Author Topic: .NET MISCELLANEOUS/GENERAL Routines  (Read 23827 times)

0 Members and 1 Guest are viewing this topic.

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #30 on: January 08, 2012, 07:05:25 am »
NumericBox and IntegerBox. (EDIT: added an AngleBox)

These two three little classes can be added to a project to add new controls.
They inhertit from TextBox and have some specfic properties and overload methods to insure valid values.
An ErrorProvider is used in case of non valid entry.
Specific properties are available in the Visual Studio Properties window for the control instance.

IntegerBox
Specific properties:
- ErrorMsg: the message displayed by the ErrorProvider for incorrect value (default: "Incorrect number").
- Maximum: the maximum allowed value (default: 2147483647)
- Minimum: the minimum allowed value (default: -2147483648)
- Value: the value as integer (default 0). Setting this value overwrite the Text property.

Code: [Select]
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace ControlLibrary
{
    /// <summary>
    /// Defines a control that can be used to display or edit an integer.
    /// </summary>
    public class IntegerBox : TextBox
    {
        private ErrorProvider _errorProvider;
        private int _value;

        /// <summary>
        /// Set default values.
        /// </summary>
        public IntegerBox()
        {
            _errorProvider = new ErrorProvider();
            ErrorMsg = "Incorrect number";
            Minimum = -2147483648;
            Maximum = 2147483647;
            _value = 0;
        }

        /// <summary>
        /// Get or set the error provider message.
        /// </summary>
        public string ErrorMsg { get; set; }

        /// <summary>
        /// Get or set the minimum allowed value.
        /// </summary>
        public int Minimum { get; set; }

        /// <summary>
        /// Get or set the maximum allowed value.
        /// </summary>
        public int Maximum { get; set; }

        /// <summary>
        /// Get or set the value as integer.
        /// </summary>
        public int Value
        {
            get { return _value; }
            set
            {
                _value = value;
                this.Text = _value.ToString();
                this.OnValidating(new CancelEventArgs());
            }
        }

        /// <summary>
        /// Evaluates if the value is a valid integer according to MinValue and MaxValue.
        /// If not, cancels the validation and displayd an error provider.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnValidating(System.ComponentModel.CancelEventArgs e)
        {
            base.OnValidating(e);
            int i;
            if (!int.TryParse(this.Text, out i) || i < Minimum || i > Maximum)
            {
                e.Cancel = true;
                this.Select(0, this.Text.Length);
                _errorProvider.SetError(this, ErrorMsg);
            }
        }

        /// <summary>
        /// Updates Value.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnValidated(EventArgs e)
        {
            base.OnValidated(e);
            _value = Convert.ToInt32(this.Text);
        }

        /// <summary>
        /// Hide the error provider.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            _errorProvider.SetError(this, "");
        }
    }
}

NumericBox
Specific properties:
- DecimalPlaces: the number of digits displayed in the box after validation (default 0)
- ErrorMsg: the message displayed by the ErrorProvider for incorrect value (default: "Incorrect number").
- Value: the value as double (default 0.0). Setting this value overwrite the Text property. This value may be more accurate than the displayed one.

Code: [Select]
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace ControlLibrary
{
    /// <summary>
    /// Defines a control that can be used to display or edit a real number (double).
    /// </summary>
    public class NumericBox : TextBox
    {
        private double _value;
        private ErrorProvider _errorProvider;
        private int _decimalPlaces;
        protected string _stringFormat;

        /// <summary>
        /// Set default values.
        /// </summary>
        public NumericBox()
        {
            _value = 0;
            _errorProvider = new ErrorProvider();
            ErrorMsg = "Incorrect number";
            SetFormat();
        }

        /// <summary>
        /// Get or set the number of digits diplayed in the box.
        /// </summary>
        public int DecimalPlaces
        {
            get { return _decimalPlaces; }
            set { _decimalPlaces = value; SetFormat(); }
        }

        /// <summary>
        /// Get or set the ErrorProvider message.
        /// </summary>
        public string ErrorMsg { get; set; }

        /// <summary>
        /// Get or set the number value as double (may be more accurate than the displayed one).
        /// Updates the Text according to DecimalPlaces.
        /// </summary>
        public virtual double Value
        {
            get { return _value; }
            set {  _value = value;  this.Text = _value.ToString(_stringFormat); }
        }

        /// <summary>
        /// Evaluates if the value is a valid real number.
        /// If not, cancels the validation and displayd the ErrorProvider icon.
        /// </summary>
        /// <param name="e">The event data</param>
        protected override void OnValidating(CancelEventArgs e)
        {
            double d;
            if (!double.TryParse(this.Text, out d))
            {
                e.Cancel = true;
                this.Select(0, this.Text.Length);
                _errorProvider.SetError(this, ErrorMsg);
            }
            base.OnValidating(e);
        }

        /// <summary>
        /// Updates Text and Value.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnValidated(EventArgs e)
        {
            _value = Convert.ToDouble(this.Text);
            this.Text = _value.ToString(_stringFormat);
            base.OnValidated(e);
        }

        /// <summary>
        /// Hide the ErrorProvider icon.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnTextChanged(EventArgs e)
        {
            _errorProvider.SetError(this, "");
            base.OnTextChanged(e);
        }

        /// <summary>
        /// Creates a format string according to DecimalPlaces value.
        /// Updates the Format property.
        /// </summary>
        private void SetFormat()
        {
            if (DecimalPlaces < 1)
                _stringFormat = "0";
            else
            {
                _stringFormat = "0.";
                for (int i = 0; i < DecimalPlaces; i++) _stringFormat += "0";
            }
        }
    }
}

AngleBox (inherits from NumericBox)
Specific Property:
- UnitFormat: the unit format for the Text displayed. The Value property is always expressed in radians.

Code: [Select]
using System;

namespace ControlLibrary
{
    /// <summary>
    /// Defines a control that can be used to display or edit an angular value (double).
    /// </summary>
    public class AngleBox : NumericBox
    {
        private double _value;

        /// <summary>
        /// Angular units enumeration.
        /// </summary>
        public enum Unit
        {
            Degree,
            Grade,
            Radian
        }

        /// <summary>
        /// Define the default angular unit.
        /// </summary>
        public AngleBox()
        {
            this.UnitFormat = Unit.Degree;
        }

        /// <summary>
        /// Get or set the angular format (unit).
        /// </summary>
        public Unit UnitFormat { get; set; }

        /// <summary>
        /// Get or set the angle value in radians.
        /// Updates the Text property according to UnitFormat and DecimalPlaces.
        /// </summary>
        public override double Value
        {
            get { return _value; }
            set { _value = value; this.Text = AngleToString(_value); }
        }

        /// <summary>
        /// Updates Text and Value properties.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnValidated(EventArgs e)
        {
            _value = StringToAngle(this.Text);
            this.Text = AngleToString(_value);
            base.OnValidated(e);
        }

        /// <summary>
        /// Converts a string into an angle value in radians.
        /// </summary>
        /// <param name="txt">The angle expressed according to UnitFormat.</param>
        /// <returns>The angle value in radians.</returns>
        private double StringToAngle(string txt)
        {
            switch (UnitFormat)
            {
                case Unit.Degree:
                    return Convert.ToDouble(txt) * Math.PI / 180.0;
                case Unit.Grade:
                    return Convert.ToDouble(txt) * Math.PI / 200.0;
                default: //Radian
                    return Convert.ToDouble(txt);
            }
        }

        /// <summary>
        /// Converts an angle value in radians into a string.
        /// </summary>
        /// <param name="val">The angle value in radians..</param>
        /// <returns>The angle expressed according to UnitFormat</returns>
        private string AngleToString(double val)
        {
            switch (UnitFormat)
            {
                case Unit.Degree:
                    return (val * 180.0 / Math.PI).ToString(_stringFormat);
                case Unit.Grade:
                    return (val * 200.0 / Math.PI).ToString(_stringFormat);
                default: // Radian
                    return val.ToString(_stringFormat);
            }
        }
    }
}
« Last Edit: January 15, 2012, 04:35:44 am by gile »
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #31 on: February 10, 2012, 04:09:26 am »
Hi,

I know there're many examples for writing an/or reading Excel files.

I purpose this one, it is certainly not better than some others (it *is not* regarding performance) but I thaught it was a fine example (to use 'as is' or get inspiration from).
Thanks to TonyT, Alexander Rivilis, Kaefer, Kerry Brown and all others for all I learned from them.

The ExcelReader and ExcelWriter classes try to mimic the StremReader and StreamWriter features.
They use late binding so that there's no need to reference Excel libraries which are version dependant.
A LateBinding static class is used to make the late binding expression more easy to read.

Using example:
Code - C#: [Select]
  1.        static void Main(string[] args)
  2.        {
  3.            using (ExcelWriter xlw = new ExcelWriter(@"C:\Temp\ExcelTest.xls"))
  4.            {
  5.                xlw.WriteLine(new object[3] { "foo", "bar", "baz" });
  6.                xlw.WriteLine(new object[3] { 1, 2, 3 });
  7.                xlw.Save();
  8.            }
  9.  
  10.            using (ExcelReader xlr = new ExcelReader(@"C:\Temp\ExcelTest.xls"))
  11.            {
  12.                while (!xlr.StreamEnded)
  13.                {
  14.                    foreach (object obj in xlr.ReadLine())
  15.                    {
  16.                        Console.Write("{0} ", obj);
  17.                    }
  18.                    Console.WriteLine();
  19.                }
  20.            }
  21.  
  22.            Console.ReadLine();
  23.        }


<EDIT: added some ExcelReader.ReadRange() and ExcelWriter.WriteRange() methods see here.>
<EDIT: added some method to Write a Database or get a range content in a Database (thanks to kaefer)>
« Last Edit: February 19, 2012, 03:26:51 pm by gile »
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #32 on: February 10, 2012, 09:26:21 am »
The same as upper but using the 'dynamic' type instead of 'traditional' late binding (requires Framework 4.0).

<EDIT: added some ExcelReader.ReadRange() and ExcelWriter.WriteRange() methods see here.>
<EDIT: added some method to Write a Database or get a range content in a Database (thanks to kaefer)>
« Last Edit: February 19, 2012, 03:27:00 pm by gile »
Speaking English as a French Frog

kosak

  • Mosquito
  • Posts: 8
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #33 on: February 15, 2012, 09:57:58 am »
Hi Gile,

could you please show in a code snippet how to use practically
the ExcelReader and ExcelWriter classes in 2 respective commands in AutoCAD ?
...let say export and import block attributes to and from Excel ...
just a tiny snippet if possible
Thanks in advance !

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #34 on: February 15, 2012, 01:21:37 pm »
Here're two commands which work like the Express Tools ATTOUT and ATTIN.

EATT, for extracting attribute values to the specified Excel file, uses an ExcelWriter instance which is explicitly disposed if the user chooses not to open the Excel file.
IATT, for importing (and changing) attribute values, uses an ExcelReader instance in a using statement so that if is automatically disposed after reading the datas.

<EDIT: updated code tu use the new features of ExcelStreamLateBinding library>

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.IO;
  5. using System.Threading;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using Autodesk.AutoCAD.Runtime;
  9. using Autodesk.AutoCAD.Windows;
  10. using ExcelStreamLateBinding;
  11. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  12.  
  13. namespace ExcelAttribute
  14. {
  15.    public class Commands
  16.    {
  17.        private string _expMsg, _dispMsg, _impMsg;
  18.        private bool _fr = Thread.CurrentThread.CurrentCulture.Name.StartsWith("fr");
  19.        private Database _db = HostApplicationServices.WorkingDatabase;
  20.        private Editor _ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
  21.  
  22.        public Commands()
  23.        {
  24.            _expMsg = _fr ? "Extraction d'attributs" : "Attributes Extract";
  25.            _dispMsg = _fr ? "Ouvrir le fichier Excel ?" : "Open Excel file ?";
  26.            _impMsg = _fr ? "Importation d'attributs" : "Attributes Import";
  27.        }
  28.  
  29.        [CommandMethod("EATT", CommandFlags.UsePickSet)]
  30.        public void ExportAttributes()
  31.        {
  32.            TypedValue[] filter = new TypedValue[2] { new TypedValue(0, "INSERT"), new TypedValue(66, 1) };
  33.            PromptSelectionResult psr = _ed.GetSelection(new SelectionFilter(filter));
  34.            if (psr.Status != PromptStatus.OK) return;
  35.  
  36.            string path = string.Format("{0}{1}.xls",
  37.                AcAp.GetSystemVariable("DWGPREFIX"),
  38.                Path.GetFileNameWithoutExtension((string)AcAp.GetSystemVariable("DWGNAME")));
  39.            SaveFileDialog dlg = new SaveFileDialog(_expMsg, path, "xls;xlsx", "", 0);
  40.            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
  41.            string filename = dlg.Filename;
  42.  
  43.            System.Data.DataTable table = new System.Data.DataTable();
  44.            table.Columns.Add("HANDLE", typeof(String));
  45.            table.Columns.Add("NAME", typeof(String));
  46.            using (Transaction tr = _db.TransactionManager.StartTransaction())
  47.            {
  48.                foreach (SelectedObject so in psr.Value)
  49.                {
  50.                    BlockReference br = tr.GetObject(so.ObjectId, OpenMode.ForRead) as BlockReference;
  51.                    BlockTableRecord btr = br.IsDynamicBlock ?
  52.                        (BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead) :
  53.                        (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
  54.                    table.Rows.Add(new string[2] { br.Handle.ToString(), btr.Name });
  55.                    foreach (KeyValuePair<string, string> pair in GetAttributes(br, tr))
  56.                    {
  57.                        if (!table.Columns.Contains(pair.Key))
  58.                            table.Columns.Add(pair.Key, typeof(String));
  59.                        table.Rows[table.Rows.Count - 1][pair.Key] = pair.Value;
  60.                    }
  61.                }
  62.            }
  63.  
  64.            using (ExcelWriter xlw = new ExcelWriter(filename))
  65.            {
  66.                if (File.Exists(filename))
  67.                    xlw.Clear();
  68.                xlw.WriteRange(table);
  69.                xlw.Worksheet.Get("Columns").Invoke("AutoFit");
  70.                object range = xlw.Worksheet.Get("Range",
  71.                    xlw.Worksheet.Get("Cells", 1, 1),
  72.                    xlw.Worksheet.Get("Cells", 1, table.Columns.Count));
  73.                range.Get("Font").Set("Bold", true);
  74.                xlw.Save();
  75.                if (System.Windows.Forms.MessageBox.Show(
  76.                    _dispMsg, _expMsg, System.Windows.Forms.MessageBoxButtons.YesNo) ==
  77.                    System.Windows.Forms.DialogResult.Yes)
  78.                {
  79.                    xlw.ExcelApp.Set("DisplayAlerts", true);
  80.                    xlw.ExcelApp.Set("Visible", true);
  81.                    xlw.ExcelApp.Set("UserControl", true);
  82.                }
  83.            }
  84.        }
  85.  
  86.        [CommandMethod("IATT")]
  87.        public void ImportAttributes()
  88.        {
  89.            string path = string.Format("{0}{1}.xls",
  90.                AcAp.GetSystemVariable("DWGPREFIX"),
  91.                Path.GetFileNameWithoutExtension((string)AcAp.GetSystemVariable("DWGNAME")));
  92.            OpenFileDialog dlg = new OpenFileDialog(_impMsg, path, "xls;xlsx", "", 0);
  93.            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
  94.            string filename = dlg.Filename;
  95.  
  96.            System.Data.DataTable table;
  97.            using (ExcelReader xlr = new ExcelReader(filename))
  98.            {
  99.                table = xlr.RangeToDataTable(1, 1);
  100.            }
  101.  
  102.            if (table == null)
  103.                return;
  104.            using (Transaction tr = _db.TransactionManager.StartTransaction())
  105.            {
  106.                foreach (DataRow row in table.Rows)
  107.                {
  108.                    try
  109.                    {
  110.                        ObjectId brId = _db.GetObjectId(false, new Handle(Convert.ToInt64(row[0].ToString(), 16)), 0);
  111.                        BlockReference br = tr.GetObject(brId, OpenMode.ForRead, true) as BlockReference;
  112.                        if (br != null)
  113.                        {
  114.                            foreach (ObjectId id in br.AttributeCollection)
  115.                            {
  116.                                AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
  117.                                if (table.Columns.Contains(att.Tag))
  118.                                {
  119.                                    att.TextString = row[att.Tag].ToString();
  120.                                }
  121.                            }
  122.                        }
  123.                    }
  124.                    catch { }
  125.                }
  126.                tr.Commit();
  127.            }
  128.        }
  129.  
  130.        private Dictionary<string, string> GetAttributes(BlockReference br, Transaction tr)
  131.        {
  132.            Dictionary<string, string> result = new Dictionary<string, string>();
  133.            foreach (ObjectId id in br.AttributeCollection)
  134.            {
  135.                AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
  136.                result.Add(att.Tag.ToUpper(), att.TextString);
  137.            }
  138.            return result;
  139.        }
  140.    }
  141. }
« Last Edit: February 19, 2012, 04:04:31 pm by gile »
Speaking English as a French Frog

kosak

  • Mosquito
  • Posts: 8
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #35 on: February 16, 2012, 06:18:43 am »
http://www.theswamp.org/Smileys/aaron/grin.gif

Hi Gile,

many thanks for the example !!!
I compiled the whole project for ACAD 2011 german and everything works fine.
I will try to do the same using classes for Access 2007 and 2010.
The routines work very very fast !

best Regards
Konstantin

kaefer

  • Swamp Rat
  • Posts: 572
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #36 on: February 16, 2012, 07:02:17 am »
The routines work very very fast !

Without having tested gile's youngest baby, I'd wager a guess that you could still speed up the interop data exchange part by utilizing a 2D-Array of objects for that too. This approach would reduce the number of calls to determine the Excel Range from the number of records to one, and also the number of calls to the Value2 property. An old example for this technique can be found here.
« Last Edit: February 16, 2012, 08:23:06 am by kaefer »

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #37 on: February 16, 2012, 03:42:41 pm »
Nice idea kaefer (as usual).
If I have some time, I'd add some WriteRange() method to the ExcelWriter class.
Speaking English as a French Frog

airportman

  • Newt
  • Posts: 34
  • i customize when required
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #38 on: December 18, 2012, 01:43:15 pm »
Has anyone recompiled this to work with Autocad 2012.
I am currently having trouble with it working on my Autocad 2010.
It throws up a dialog stating:

FATAL ERROR: Unsupported version of Windows Presentation Foundation


could someone direct me to a fix for this issue?
Perception is a state of mind  -/ Twitter = @hochanz -/ Intel i7 - 3.07GHz -/ 12GB Ram -/ Nvidia Quadro FX 1800

BlackBox

  • King Gator
  • Posts: 3742
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #39 on: July 10, 2013, 06:57:51 pm »
Resulting from this thread, here are some Extension Methods for String (string):

Code - C#: [Select]
  1. using Microsoft.VisualBasic;
  2. using System.Globalization;
  3. using System.Text.RegularExpressions;
  4. using System.Threading;
  5.  
  6. namespace System
  7. {
  8.    public static class StringExtensions
  9.    {
  10.        public enum StringCase { Lower = 1, Sentence, Title, Toggle, Upper };
  11.  
  12.        public static string ToCase(this string str, int strCase)
  13.        {
  14.            string res;
  15.  
  16.            switch (strCase)
  17.            {
  18.                case (int)StringCase.Lower:
  19.                    res = str.ToLower();
  20.                    break;
  21.  
  22.                case (int)StringCase.Sentence:
  23.                    res = str.ToSentenceCase();
  24.                    break;
  25.  
  26.                case (int)StringCase.Title:
  27.                    res = str.ToTitleCase();
  28.                    break;
  29.  
  30.                case (int)StringCase.Toggle:
  31.                    res = str.ToToggleCase();
  32.                    break;
  33.  
  34.                case (int)StringCase.Upper:
  35.                    res = str.ToUpper();
  36.                    break;
  37.  
  38.                default:
  39.                    res = str;
  40.                    break;
  41.            }
  42.  
  43.            return res;
  44.        }
  45.        public static string ToSentenceCase(this String str)
  46.        {
  47.            string SentenceBreakers = Regex.Escape(".!?" + Constants.vbCrLf);
  48.            string Pattern =
  49.                "((?<=^[^" + SentenceBreakers + "\\w]{0,})[a-z]|(?<![" +
  50.                SentenceBreakers + "])(?<=[" + SentenceBreakers + "][^" +
  51.                SentenceBreakers + "\\w]{0,})[a-z])";
  52.  
  53.            return Regex.Replace(str.ToLower(), Pattern,
  54.                m => m.Value[0].ToString().ToUpper() + m.Value.Substring(1));
  55.        }
  56.        public static string ToTitleCase(this String str)
  57.        {
  58.            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
  59.  
  60.            return cultureInfo.TextInfo.ToTitleCase(str.ToLower());
  61.        }
  62.        public static string ToToggleCase(this String str)
  63.        {
  64.            string newStr = "";
  65.            char[] arr = str.ToCharArray();
  66.  
  67.            foreach (char c in arr)
  68.            {
  69.                string s = c.ToString();
  70.  
  71.                if (s == s.ToLower())
  72.                    s = s.ToUpper();
  73.  
  74.                else
  75.                    s = s.ToLower();
  76.  
  77.                newStr = newStr + s;
  78.            }
  79.  
  80.            return newStr;
  81.        }
  82.    }
  83. }
  84.  
"Potential has a shelf life." - Margaret Atwood

LE3

  • Guest
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #40 on: July 11, 2013, 03:15:19 pm »
I need a way to open some drawings files and find out it is a template for a dynamic block, that way can be sorted out and send to another folder, before I do any editions on the drawings.

I am testing for these two RegApps names if they are present (per my tests on files I use here, only those two apply, if you know of any other one or have another approach, would be good to hear of that):
"AcDbDynamicBlockTrueName"
"AcDbBlockRepETag"

Code - C#: [Select]
  1.  
  2.        private static bool IsDynamicBlockFile(string fileName, List<string> filenames, Transaction transaction, Database database)
  3.        {
  4.            using (var regAppTable = (RegAppTable) transaction.GetObject(database.RegAppTableId, OpenMode.ForRead))
  5.            {
  6. #if GET_APP_NAMES
  7.                var names =
  8.            regAppTable.Cast<ObjectId>()
  9.                       .Where(id => id.IsValid)
  10.                       .Select(id => ((RegAppTableRecord)transaction.GetObject(id, OpenMode.ForRead)).Name);
  11. #endif
  12.                if (regAppTable.Cast<ObjectId>().Any(id =>
  13.                    {
  14.                        var regAppTableRecord = (RegAppTableRecord) transaction.GetObject(id, OpenMode.ForRead);
  15.                        return regAppTableRecord.Name == "AcDbDynamicBlockTrueName" || regAppTableRecord.Name == "AcDbBlockRepETag";
  16.                    }))
  17.                {
  18.                    filenames.Add(Path.GetFileName(fileName));
  19.                    return true;
  20.                }
  21.            }
  22.            return false;
  23.        }


LE3

  • Guest
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #41 on: July 18, 2013, 10:16:56 am »
This is a tip and comment I got when started working for this company, from one of the senior programmers (Scott), that want to share, HTH.

However, I think you are being more complicated than you need to when determining when to draw the option table.
You can take all this code:

Code - C#: [Select]
  1. var anyWithJobOption = new List<bool>();
  2. foreach (var job in jobs.ItemsOnJob)
  3. {
  4.    anyWithJobOption.Add(job.HasJobOption);
  5. }
  6. var withJobOption = anyWithJobOption.Any(are => are);

And use Boolean logic instead of LINQ & Lists:
Code - C#: [Select]
  1. foreach (var job in jobs.ItemsOnJob)
  2. {
  3.    withJobOption |= job.HasJobOption;
  4. }
  5. if (withJobOption)
  6. {
  7.    // code proccess goes here...
  8. }
« Last Edit: July 18, 2013, 10:22:13 am by LE »

fixo

  • Guest
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #42 on: May 19, 2014, 03:15:46 pm »
Sample code to slicing solid multiple
Code - C#: [Select]
  1.       [CommandMethod("soc", CommandFlags.UsePickSet | CommandFlags.Redraw)]
  2.        public static void testMultySliceSolid()
  3.        {
  4.  
  5.            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  6.  
  7.            Database db = doc.Database;
  8.  
  9.            Editor ed = doc.Editor;
  10.            string blkname = string.Empty;
  11.  
  12.            using (Transaction trans = db.TransactionManager.StartTransaction())
  13.            {
  14.  
  15.                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  16.                Solid3d sol = trans.GetObject(ed.GetEntity("\nSelect  3dSolid").ObjectId, OpenMode.ForRead) as Solid3d;
  17.  
  18.                if (sol == null)
  19.                {
  20.                    Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Nothing or wrong object selected");
  21.                    return;
  22.                }
  23.  
  24.                PromptPointOptions ppo = new PromptPointOptions("\nStarting point of slicing direction: ");
  25.                PromptPointResult ppr = ed.GetPoint(ppo);
  26.                if (ppr.Status != PromptStatus.OK) return;
  27.                PromptPointOptions pco = new PromptPointOptions("\nEnding point: ");
  28.                pco.BasePoint = ppr.Value;
  29.                pco.UseBasePoint = true;
  30.                pco.UseDashedLine = true;
  31.                PromptPointResult pcr = ed.GetPoint(pco);
  32.                if (pcr.Status != PromptStatus.OK) return;
  33.                Point3d p1 = ppr.Value;
  34.                Point3d p2 = pcr.Value;
  35.                if (p1.DistanceTo(p2)==0)
  36.                {
  37.                    ed.WriteMessage("\nInvalid coordinate specification");
  38.                    return;
  39.                }
  40.                PromptDoubleOptions pdo =
  41.                    new PromptDoubleOptions("\nEnter a slicing interval: ");
  42.                pdo.AllowNone = true;
  43.                pdo.UseDefaultValue = true;
  44.                pdo.DefaultValue = 10;
  45.  
  46.                PromptDoubleResult res;
  47.                res = ed.GetDouble(pdo);
  48.                if (res.Status != PromptStatus.OK)
  49.                    return;
  50.  
  51.                double size = res.Value;
  52.  
  53.                ed.WriteMessage("\nInterval Entered\t{0:f2}",
  54.                    size);
  55.                /*Do your stuff here*/
  56.                PromptIntegerOptions pio = new PromptIntegerOptions("");
  57.                pio.Message = "\nEnter the number of slices: ";
  58.  
  59.                // Restrict input to positive and non-negative values
  60.                pio.AllowZero = false;
  61.                pio.AllowNegative = false;
  62.                // Add default value
  63.                pio.DefaultValue = 6;
  64.                pio.AllowNone = true;
  65.  
  66.                // Get the value entered by the user
  67.                PromptIntegerResult ires = ed.GetInteger(pio);
  68.                if (ires.Status != PromptStatus.OK) return;
  69.  
  70.                int num = ires.Value;
  71.  
  72.                ed.WriteMessage("\nNumber of slices entered\t{0}", num);
  73.                /*Do your stuff here*/
  74.                double d = p1.DistanceTo(p2);
  75.  
  76.                if ((Math.Abs(d - size * num)) > 0.00001)
  77.                {
  78.                    Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(string.Format(
  79.                        "Number of slices exceed a maximum, \nrecalculate number [{0}] and interval [{1}]\nif current distace is [{2}], accuratelly, please.", num, size,d));
  80.                    return;
  81.                }
  82.                // work with solid
  83.                Vector3d vec = p1.GetVectorTo(p2).GetNormal();
  84.                sol.UpgradeOpen();
  85.                Solid3d slice= new Solid3d();
  86.  
  87.                for (int i = 1; i < num; i++)
  88.                {
  89.                    Point3d spt = p1.Add(vec.MultiplyBy(size*i));
  90.                    Plane plan = new Plane(spt, vec.Negate());
  91.                    if (i == 1)
  92.                    {
  93.                         slice = sol.Slice(plan, true);
  94.                         slice.ColorIndex = 1;
  95.                         btr.AppendEntity(slice);
  96.                         trans.AddNewlyCreatedDBObject(slice, true);
  97.                    }
  98.                    else
  99.                    {
  100.                        ObjectId id = Autodesk.AutoCAD.Internal.Utils.EntLast();
  101.                         sol = (Solid3d)trans.GetObject(id, OpenMode.ForRead);
  102.                         if (!sol.IsWriteEnabled) sol.UpgradeOpen();
  103.                         slice = sol.Slice(plan, true);
  104.                         slice.ColorIndex = 1;
  105.                         btr.AppendEntity(slice);
  106.                         trans.AddNewlyCreatedDBObject(slice, true);
  107.  
  108.                    }
  109.  
  110.                }
  111.  
  112.                trans.Commit();
  113.            }
  114.        }
  115.  

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #43 on: November 28, 2014, 03:38:10 pm »
An overload Editor.GetWindow() extension method.
  • public static PromptWindowResult GetWindow(this Editor ed, string message, string secondMessage)
  • public static PromptWindowResult GetWindow(this Editor ed, string messageAndKeywords, string globalKeywords, string secondMessage)
  • public static PromptWindowResult GetWindow(this Editor ed, PromptWindowOptions options)
The PromptWindowOptions type provides the same features as PromptPointOptions more a SecondMessage read/write property.
The PromptWindowResult type offers the same properties as PromptResult (Stauts and StringResult) plus Value of type Extents3d (current UCS coordinates).

Code - C#: [Select]
  1. using System;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3.  
  4. namespace Autodesk.AutoCAD.EditorInput
  5. {
  6.    public static class EditorExtensions
  7.    {
  8.        public static PromptWindowResult GetWindow(this Editor ed, string message, string secondMessage)
  9.        {
  10.            PromptWindowOptions options = new PromptWindowOptions(message, secondMessage);
  11.            return ed.GetWindow(options);
  12.        }
  13.  
  14.        public static PromptWindowResult GetWindow(this Editor ed, string messageAndKeywords, string globalKeywords, string secondMessage)
  15.        {
  16.            PromptWindowOptions options = new PromptWindowOptions(messageAndKeywords, globalKeywords, secondMessage);
  17.            return ed.GetWindow(options);
  18.        }
  19.  
  20.        public static PromptWindowResult GetWindow(this Editor ed, PromptWindowOptions options)
  21.        {
  22.            if (ed == null)
  23.                throw new ArgumentNullException("ed");
  24.  
  25.            if (options == null)
  26.                throw new ArgumentNullException("options");
  27.  
  28.            Extents3d value = new Extents3d();
  29.            PromptPointResult result = ed.GetPoint(options);
  30.  
  31.            if (result.Status == PromptStatus.Keyword)
  32.                return new PromptWindowResult(result.Status, result.StringResult);
  33.  
  34.            if (result.Status != PromptStatus.OK)
  35.                return new PromptWindowResult(result.Status);
  36.  
  37.            value.AddPoint(result.Value);
  38.            result = ed.GetCorner(options.SecondMessage, result.Value);
  39.  
  40.            if (result.Status != PromptStatus.OK)
  41.                return new PromptWindowResult(result.Status);
  42.  
  43.            value.AddPoint(result.Value);
  44.            return new PromptWindowResult(result.Status, value);
  45.        }
  46.    }
  47.  
  48.    public class PromptWindowOptions : PromptPointOptions
  49.    {
  50.        public string SecondMessage { get; set; }
  51.  
  52.        public PromptWindowOptions(string message, string secondMessage)
  53.            : base(message)
  54.        {
  55.            this.SecondMessage = secondMessage;
  56.        }
  57.  
  58.        public PromptWindowOptions(string messageAndKeywords, string globalKeywords, string secondMessage)
  59.            : base(messageAndKeywords, globalKeywords)
  60.        {
  61.            this.SecondMessage = secondMessage;
  62.        }
  63.    }
  64.  
  65.    public class PromptWindowResult
  66.    {
  67.        public string StringResult { get; private set; }
  68.  
  69.        public PromptStatus Status { get; private set; }
  70.  
  71.        public Extents3d Value { get; private set; }
  72.  
  73.        internal PromptWindowResult(PromptStatus status, Extents3d value)
  74.        {
  75.            this.Status = status;
  76.            this.Value = value;
  77.        }
  78.  
  79.        internal PromptWindowResult(PromptStatus status, string keyword)
  80.            : this(status)
  81.        {
  82.            this.StringResult = keyword;
  83.        }
  84.  
  85.        internal PromptWindowResult(PromptStatus status)
  86.            : this(status, new Extents3d()) { }
  87.    }
  88. }
  89.  

A test command example:
Code - C#: [Select]
  1.        [CommandMethod("Test")]
  2.        public void Test()
  3.        {
  4.            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  5.  
  6.            PromptWindowOptions options =
  7.                new PromptWindowOptions(
  8.                    "\nSpecify first corner [Extents/Previous]: ",
  9.                    "Extents Previous",
  10.                    "\nSpecify opposite corner");
  11.            options.AllowNone = true;
  12.  
  13.            dynamic acadApp = Application.AcadApplication;
  14.  
  15.            while (true)
  16.            {
  17.                PromptWindowResult result = ed.GetWindow(options);
  18.                switch (result.Status)
  19.                {
  20.                    case PromptStatus.Keyword:
  21.                        if (result.StringResult == "Extents")
  22.                            acadApp.Zoomextents();
  23.                        else
  24.                            acadApp.ZoomPrevious();
  25.                        break;
  26.                    case PromptStatus.OK:
  27.                        var exts = result.Value;
  28.                        exts.TransformBy(ed.CurrentUserCoordinateSystem);
  29.                        acadApp.ZoomWindow(exts.MinPoint.ToArray(), exts.MaxPoint.ToArray());
  30.                        break;
  31.                    default:
  32.                        return;
  33.                }
  34.            }
  35.        }
« Last Edit: November 28, 2014, 05:51:51 pm by gile »
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 2089
  • Marseille, France
Re: .NET MISCELLANEOUS/GENERAL Routines
« Reply #44 on: January 23, 2015, 02:28:57 pm »
Hi,

These some helpers allow to access AutoCAD registry data from outside AutoCAD.
This may be usefull with installing / deinstalling applications.

<EDIT: added a ServicePack property to the ProductKey class>
<EDIT: changed the GetCurrentProductKey() and GetAllProductKeys() implementation to a safer one>
<EDIT: corrected some copy/paste errors>
<EDIT: updated code to handle ServicePacks Autodesk registry>

AcadReg class provides static methods to get AutoCAD registry product keys
  • AcAdReg.GetCurrentProductKey() returns the instance of ProductKey (see below) corresponding to the current AutoCAD version (latest used).
  • AcadReg.GetAllProductKeys() gets sequence of ProductKey containing all AutoCAD products installed.
  • AcAdReg.GetProductKeysSince(string release) gets a sequence of ProductKey containing all AutoCAD products since the specified release.
  • AcAdReg.GetProductKeysSince(string release, IEnumerable<ProductKey> source) gets a sequence of ProductKey containing the AutoCAD products since the specified release contained in the source sequence.
Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using Microsoft.Win32;
  6.  
  7. namespace Gile.AutocadRegistryServices
  8. {
  9.    public static class AcadReg
  10.    {
  11.        public static ProductKey GetCurrentProductKey()
  12.        {
  13.            string key = @"Software\Autodesk\AutoCAD";
  14.            using (RegistryKey root = Registry.CurrentUser.OpenSubKey(key))
  15.            {
  16.                if (root == null)
  17.                    throw new InvalidOperationException(string.Format("'{0}' = null", key));
  18.                string curver = (string)root.GetValue("CurVer");
  19.                if (string.IsNullOrEmpty(curver))
  20.                    throw new InvalidOperationException(string.Format("'{0}' CurVer = null", key));
  21.                key += "\\" + curver;
  22.                using (RegistryKey rkey = Registry.CurrentUser.OpenSubKey(key))
  23.                {
  24.                    curver = (string)rkey.GetValue("CurVer");
  25.                    if (string.IsNullOrEmpty(curver))
  26.                        throw new InvalidOperationException(string.Format("'{0}' CurVer = null", key));
  27.                    return new ProductKey(key + "\\" + curver);
  28.                }
  29.            }
  30.        }
  31.  
  32.        public static IEnumerable<ProductKey> GetAllProductKeys()
  33.        {
  34.            string prefix = @"Software\Autodesk\AutoCAD";
  35.            using (RegistryKey root = Registry.CurrentUser.OpenSubKey(prefix))
  36.            {
  37.                return root.GetSubKeyNames()
  38.                    .Select(s => string.Format(@"{0}\{1}", prefix, s))
  39.                    .SelectMany(s => Registry.CurrentUser.OpenSubKey(s).GetSubKeyNames()
  40.                        .Where(k => Regex.IsMatch(k, "^ACAD-....:..."))
  41.                        .Select(k => new ProductKey(string.Format(@"{0}\{1}", s, k))));
  42.            }
  43.        }
  44.  
  45.        public static IEnumerable<ProductKey> GetProductKeysSince(string release)
  46.        {
  47.            return GetProductKeysSince(release, GetAllProductKeys());
  48.        }
  49.  
  50.        public static IEnumerable<ProductKey> GetProductKeysSince(string release, IEnumerable<ProductKey> source)
  51.        {
  52.            if (!(Regex.IsMatch(release, @"^R\d\d$|^R\d\d.\d$")))
  53.                throw new FormatException("Incorrect Release format: " + release);
  54.  
  55.            if (source == null)
  56.                throw new ArgumentNullException("source");
  57.  
  58.            return source.Where(pk => pk.Release.CompareTo(release) >= 0);
  59.        }
  60.    }
  61. }

ProductKey class provides methods and properties to deal with AutoCAD registry product key
Public properties
  • KeyName gets the full path of the product key
  • Release gets the release version (RXX.X)
  • ProductId gets the product Id
  • LocaleId gets the locale Id
  • ServicePack gets the last installed service pack
Public instance methods
  • GetProfileKeys() gets the sequence of ProfileKey (see below) instances corresponding to all profiles keys
  • RegisterApplication() registers a .NET application
  • RegisterSystemVariable() registers a new system variable
  • UnregisterApplication() unregisters a .NET application
  • UnregisterSystemVariable() unregisters a new system variable
Code - C#: [Select]
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Linq;
  4. using Microsoft.Win32;
  5.  
  6. namespace Gile.AutocadRegistryServices
  7. {
  8.    public class ProductKey
  9.    {
  10.        public string KeyName { get; private set; }
  11.  
  12.        public string Release { get; private set; }
  13.  
  14.        public string ProductId { get; private set; }
  15.  
  16.        public string LocaleId { get; private set; }
  17.  
  18.        public string ServicePack { get; private set; }
  19.  
  20.        internal ProductKey(string keyName)
  21.        {
  22.            KeyName = keyName;
  23.            string[] items = keyName.Split('\\');
  24.            Release = items[3];
  25.            string[] ids = items[4].Substring(5).Split(':');
  26.            ProductId = ids[0];
  27.            LocaleId = ids[1];
  28.            string subKeyName = Release.CompareTo("R19.0") < 0 ?
  29.                subKeyName = keyName + "\\Service Packs" :
  30.                Path.Combine(Path.GetDirectoryName(keyName), "ACAD-" + ProductId + "\\Service Packs");
  31.            using (RegistryKey rkey = Registry.LocalMachine.OpenSubKey(subKeyName))
  32.            {
  33.                if (rkey == null)
  34.                {
  35.                    ServicePack = "";
  36.                }
  37.                else
  38.                {
  39.                    subKeyName += "\\" + rkey.GetSubKeyNames()[0];
  40.                    using (RegistryKey subKey = Registry.LocalMachine.OpenSubKey(subKeyName))
  41.                    {
  42.                        string productName = (string)subKey.GetValue("ProductName");
  43.                        string patchTitle = (string)subKey.GetValue("PatchTitle");
  44.                        ServicePack = patchTitle.Length > productName.Length ?
  45.                            patchTitle.Substring(productName.Length + 1) :
  46.                            productName.Substring(patchTitle.Length + 1);
  47.                    }
  48.                }
  49.            }
  50.        }
  51.  
  52.        public IEnumerable<ProfileKey> GetProfileKeys()
  53.        {
  54.            string profiles = string.Format(@"{0}\Profiles", KeyName);
  55.            using (RegistryKey rkey = Registry.CurrentUser.OpenSubKey(profiles))
  56.            {
  57.                return rkey.GetSubKeyNames()
  58.                    .Select(skn => new ProfileKey(string.Format(@"{0}\{1}", profiles, skn)));
  59.            }
  60.        }
  61.  
  62.        public void RegisterApplication(
  63.            string appName,
  64.            string fileName,
  65.            string description,
  66.            bool allUsers = false,
  67.            string[] globalCmdNames = null,
  68.            string[] localCmdNames = null,
  69.            string[] groups = null)
  70.        {
  71.            RegistryKey hive = allUsers ?
  72.                RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) :
  73.                Registry.CurrentUser;
  74.            string apps = string.Format(@"{0}\Applications", KeyName);
  75.            using (RegistryKey appsKey = hive.OpenSubKey(apps, true))
  76.            {
  77.                if (appsKey.GetSubKeyNames().Contains(appName))
  78.                    return;
  79.                int flags =
  80.                    globalCmdNames != null &&
  81.                    localCmdNames != null &&
  82.                    globalCmdNames.Length > 0 &&
  83.                    globalCmdNames.Length == localCmdNames.Length ?
  84.                    12 : 2;
  85.                using (RegistryKey appKey = appsKey.CreateSubKey(appName))
  86.                {
  87.                    appKey.SetValue("DESCRIPTION", description, RegistryValueKind.String);
  88.                    appKey.SetValue("LOADCTRLS", flags, RegistryValueKind.DWord);
  89.                    appKey.SetValue("LOADER", fileName, RegistryValueKind.String);
  90.                    appKey.SetValue("MANAGED", 1, RegistryValueKind.DWord);
  91.  
  92.                    if (flags == 12)
  93.                    {
  94.                        using (RegistryKey cmdKey = appKey.CreateSubKey("Commands"))
  95.                        {
  96.                            for (int i = 0; i < globalCmdNames.Length; i++)
  97.                            {
  98.                                cmdKey.SetValue(globalCmdNames[i], localCmdNames[i], RegistryValueKind.String);
  99.                            }
  100.                        }
  101.                        if (groups != null && groups.Length > 0)
  102.                        {
  103.                            using (RegistryKey grpKey = appKey.CreateSubKey("Groups"))
  104.                            {
  105.                                foreach (string grpName in groups)
  106.                                {
  107.                                    grpKey.SetValue(grpName, grpName, RegistryValueKind.String);
  108.                                }
  109.                            }
  110.                        }
  111.                    }
  112.                }
  113.            }
  114.        }
  115.  
  116.        public void UnregisterApplication(string appName, bool allUsers = false)
  117.        {
  118.            RegistryKey hive = allUsers ?
  119.                RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) :
  120.                Registry.CurrentUser;
  121.            string apps = string.Format(@"{0}\Applications", KeyName);
  122.            using (RegistryKey appsKey = hive.OpenSubKey(apps, true))
  123.            {
  124.                if (appsKey.GetSubKeyNames().Contains(appName))
  125.                appsKey.DeleteSubKeyTree(appName);
  126.            }
  127.        }
  128.  
  129.        public void RegisterSystemVariable(
  130.            string name,
  131.            object defaultValue,
  132.            SysVar.StorageType storageType,
  133.            SysVar.PrimaryType primaryType,
  134.            SysVar.SecondaryType secondaryType = SysVar.SecondaryType.None,
  135.            int lowerBound = int.MinValue,
  136.            int upperBound = int.MaxValue,
  137.            SysVar.TypeFlags typeFlags = SysVar.TypeFlags.None,
  138.            string owner = "")
  139.        {
  140.            if (Release.CompareTo("R18.1") < 0)
  141.                return;
  142.            RegistryKey hive = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
  143.            string apps = string.Format(@"{0}\Variables", KeyName);
  144.            using (RegistryKey varsKey = hive.OpenSubKey(apps, true))
  145.            {
  146.                if (varsKey.GetSubKeyNames().Contains(name))
  147.                    return;
  148.                using (RegistryKey key = varsKey.CreateSubKey(name))
  149.                {
  150.                    key.SetValue("", defaultValue, RegistryValueKind.String);
  151.                    key.SetValue("PrimaryType", (int)primaryType, RegistryValueKind.DWord);
  152.                    if (secondaryType != SysVar.SecondaryType.None)
  153.                        key.SetValue("SecondaryType", (int)secondaryType, RegistryValueKind.DWord);
  154.                    if (typeFlags != SysVar.TypeFlags.None)
  155.                        key.SetValue("TypeFlags", (int)typeFlags, RegistryValueKind.DWord);
  156.                    key.SetValue("StorageType", (int)storageType, RegistryValueKind.DWord);
  157.                    if (owner != "")
  158.                        key.SetValue("Owner", owner, RegistryValueKind.String);
  159.                    if (primaryType == SysVar.PrimaryType.String)
  160.                    {
  161.                        if (lowerBound != int.MinValue)
  162.                            key.SetValue("LowerBound", (int)lowerBound, RegistryValueKind.DWord);
  163.                        if (upperBound != int.MaxValue)
  164.                            key.SetValue("UpperBound", (int)upperBound, RegistryValueKind.DWord);
  165.                    }
  166.                }
  167.            }
  168.        }
  169.  
  170.        public void UnregisterSystemVariable(string name)
  171.        {
  172.            if (Release.CompareTo("R18.1") < 0)
  173.                return;
  174.            RegistryKey hive = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
  175.            string apps = string.Format(@"{0}\Variables", KeyName);
  176.            using (RegistryKey varsKey = hive.OpenSubKey(apps, true))
  177.            {
  178.                varsKey.DeleteSubKey(name, false);
  179.            }
  180.        }
  181.    }
  182. }

ProfileKey class provides methods and properties to deal with AutoCAD registry profile key
Public properties
  • KeyName gets the full path of the product key
  • Name gets the profile name
Public instance methods
  • AddSupportPath adds the path to the profile support paths list
  • AddTrustedPath adds the path to the profile trusted paths list (AutoCAD 2014+)
  • RemoveSupportPath removes the path to the profile support paths list
  • RemoveTrustedPath removes the path to the trusted support paths list (AutoCAD 2014+)
Code - C#: [Select]
  1. using System;
  2. using System.Linq;
  3. using System.Text;
  4. using Microsoft.Win32;
  5.  
  6. namespace Gile.AutocadRegistryServices
  7. {
  8.    public class ProfileKey
  9.    {
  10.        public string KeyName { get; private set; }
  11.  
  12.        public string Name { get; private set; }
  13.  
  14.        internal ProfileKey(string key)
  15.        {
  16.            string[] items = key.Split('\\');
  17.            KeyName = key;
  18.            Name = items[6];
  19.        }
  20.  
  21.        public void AppendSupportPath(string path)
  22.        {
  23.            AppendPath("General", "ACAD", path);
  24.        }
  25.  
  26.        public void PrependSupportPath(string path)
  27.        {
  28.            PrependPath("General", "ACAD", path);
  29.        }
  30.  
  31.        public void AddTrustedPath(string path)
  32.        {
  33.            if (KeyName.Split('\\')[3].CompareTo("R19.1") >= 0)
  34.                AppendPath("Variables", "TRUSTEDPATHS", path);
  35.        }
  36.  
  37.        public void RemoveSupportPath(string path)
  38.        {
  39.            RemovePath("General", "ACAD", path);
  40.        }
  41.  
  42.        public void RemoveTrustedPath(string path)
  43.        {
  44.            if (KeyName.Split('\\')[3].CompareTo("R19.1") >= 0)
  45.                RemovePath("Variables", "TRUSTEDPATHS", path);
  46.        }
  47.  
  48.        private void AppendPath(string subKey, string value, string path)
  49.        {
  50.            string key = string.Format(@"{0}\{1}", KeyName, subKey);
  51.            using (RegistryKey rkey = Registry.CurrentUser.OpenSubKey(key, true))
  52.            {
  53.                string paths = (string)rkey.GetValue(value);
  54.                if (!paths.EndsWith(";"))
  55.                    paths += ";";
  56.                if (!paths.Split(';').Select(s => s.ToUpper()).Contains(path.ToUpper()))
  57.                {
  58.                    paths += path + ";";
  59.                    rkey.SetValue(value, paths);
  60.                }
  61.            }
  62.        }
  63.  
  64.        private void PrependPath(string subKey, string value, string path)
  65.        {
  66.            string key = string.Format(@"{0}\{1}", KeyName, subKey);
  67.            using (RegistryKey rkey = Registry.CurrentUser.OpenSubKey(key, true))
  68.            {
  69.                string paths = (string)rkey.GetValue(value);
  70.                if (!paths.EndsWith(";"))
  71.                    paths += ";";
  72.                if (!paths.Split(';').Select(s => s.ToUpper()).Contains(path.ToUpper()))
  73.                {
  74.                    paths = path + ";" + paths;
  75.                    rkey.SetValue(value, paths);
  76.                }
  77.            }
  78.        }
  79.  
  80.        private void RemovePath(string subKey, string value, string path)
  81.        {
  82.            string key = string.Format(@"{0}\{1}", KeyName, subKey);
  83.            using (RegistryKey rkey = Registry.CurrentUser.OpenSubKey(key, true))
  84.            {
  85.                string str = (string)rkey.GetValue(value);
  86.                if (str == null) return;
  87.                string[] paths = str.Split(';');
  88.                StringBuilder sb = new StringBuilder();
  89.                foreach (string s in paths)
  90.                {
  91.                    if (s != string.Empty &&
  92.                        !s.Equals(path, StringComparison.CurrentCultureIgnoreCase))
  93.                        sb.Append(s).Append(";");
  94.                }
  95.                rkey.SetValue(value, sb.ToString());
  96.            }
  97.        }
  98.    }
  99. }

SysVar class provides enums similar to the AutoCAD.Runtime.Variable ones to make the code more readable
Code - C#: [Select]
  1. using System;
  2.  
  3. namespace Gile.AutocadRegistryServices
  4. {
  5.    public class SysVar
  6.    {
  7.        public enum StorageType
  8.        {
  9.            PerSession = 0,
  10.            PerUser = 1,
  11.            PerProfile = 2,
  12.            PerDatabase = 3
  13.        }
  14.  
  15.        public enum PrimaryType
  16.        {
  17.            Double = 5001,
  18.            Short = 5003,
  19.            String = 5005,
  20.            Integer = 5010
  21.        }
  22.  
  23.        public enum SecondaryType
  24.        {
  25.            None = 0,
  26.            Boolean = 1,
  27.            SymbolName = 2,
  28.            Area = 3,
  29.            Distance = 4,
  30.            Angle = 5,
  31.            UnitlessReal = 6
  32.        }
  33.  
  34.        [Flags]
  35.        public enum TypeFlags
  36.        {
  37.            None = 0,
  38.            SpacesAllowed = 1,
  39.            DotMeansEmpty = 2,
  40.            NoUndo = 4,
  41.            Chatty = 8
  42.        }
  43.    }
  44. }

Using example to install a .NET DLL for all profiles of all products installed for the current user:
Code - C#: [Select]
  1.        /// <summary>
  2.        /// Install a .NET application
  3.        /// </summary>
  4.        /// <param name="fileName">The DLL full path.</param>
  5.        public void Install(string fileName)
  6.        {
  7.            string folder = System.IO.Path.GetDirectoryName(fileName);
  8.            string appName = System.IO.Path.GetFileNameWithoutExtension(fileName);
  9.  
  10.            // for all AutoCAD products
  11.            foreach (ProductKey prodKey in AcadReg.GetAllProductKeys())
  12.            {
  13.                // add the support path to each profile
  14.                foreach (ProfileKey key in prodKey.GetProfileKeys())
  15.                {
  16.                    key.AddSupportPath(folder);
  17.                }
  18.                // register the application
  19.                prodKey.RegisterApplication(appName, fileName, appName);
  20.            }
  21.  
  22.            // for AutoCAD products since 2014
  23.            var trusted =
  24.                AcadReg.GetProductKeysSince("R19.1")
  25.                .SelectMany(k => k.GetProfileKeys());
  26.            // add the trusted path to each profile
  27.            foreach (ProfileKey key in trusted)
  28.            {
  29.                key.AddTrustedPath(folder);
  30.            }
  31.        }

Using example to uninstall a .NET DLL:
Code - C#: [Select]
  1.        /// <summary>
  2.        /// Uninstall a .NET application
  3.        /// </summary>
  4.        /// <param name="fileName">The DLL full path.</param>
  5.        public void Uninstall(string fileName)
  6.        {
  7.            string folder = System.IO.Path.GetDirectoryName(fileName);
  8.            string appName = System.IO.Path.GetFileNameWithoutExtension(fileName);
  9.  
  10.            // for all AutoCAD products
  11.            foreach (ProductKey prodKey in AcadReg.GetAllProductKeys())
  12.            {
  13.                // remove the support path from each profil
  14.                foreach (ProfileKey key in prodKey.GetProfileKeys())
  15.                {
  16.                    key.RemoveSupportPath(folder);
  17.                }
  18.                // unregister the application
  19.                prodKey.UnregisterApplication(appName);
  20.            }
  21.  
  22.            // for AutoCAD products since 2014
  23.            var trusted =
  24.                AcadReg.GetProductKeysSince("R19.1")
  25.                .SelectMany(k => k.GetProfileKeys());
  26.            // remove the trusted path from each profile
  27.            foreach (ProfileKey key in trusted)
  28.            {
  29.                key.RemoveTrustedPath(folder);
  30.            }
  31.        }
« Last Edit: October 01, 2015, 02:27:36 pm by gile »
Speaking English as a French Frog