Code Red > .NET

COM and Dynamic

(1/1)

It's Alive!:
I found this the other day, probably already been mentioned..
But I found you can interact with Cad’s COM interface without added those dreaded hard references.
So lets say there’s a function that’s in COM, that’s not in the wrappers, you can call it using the dynamic keyword
Example


--- Code - C#: --- public class DynApplication    {        public dynamic DynObj {get; protected set;}        public DynApplication()        {            DynObj = _AcAp.Application.AcadApplication;        }        public List<string> ListArx        {            get            {                List<string> apps = new List<string>();                foreach(string app in DynObj.ListArx)                    apps.Add(app);                return apps;            }        }    } 

--- Code - C#: ---        [CommandMethod("dyn")]        static public void dyn()        {            DynApplication dynApp = new DynApplication();             foreach(string item in dynApp.ListArx)            {                _AcAp.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n{0}", item);            }        } 

It's Alive!:
This only issues, I ran across are:
-if the function has an out parameter that outs a com class as a parameter. Dynamic complains it can’t convert an object to a com_object.
-Function signature errors are found at runtime instead of compile time.

Performance should be identical as interactions with COM are runtime anyway, early binding only compiles with the interface

Jeff H:
Here is an example of using dynamic with Preferences in AutoCAD

First snippet is example of commands interacting with it

--- Code - C#: ---    List<string> pathsAddedToEnd = new List<string>()        {            @"C:\Testing\AutoCAD\Fonts",            @"C:\Testing\AutoCAD\Shapes",            @"C:\Testing\AutoCAD\Blocks"        };        List<string> pathsAddedToBeginning = new List<string>()        {            @"C:\Testing\AutoCAD\LineTypes",            @"C:\Testing\AutoCAD\Pat"        };        /// <summary>        /// Adds list to search paths to end & to beginning        /// </summary>        [CommandMethod("AddSearchPaths")]        public void AddSearchPaths()        {            SupportPath sp = Preferences.SupportPaths;            foreach (var path in pathsAddedToEnd)            {                if (!sp.Contains(path))                {                    sp.Add(path);                    Ed.WriteLine("\nAdded Path {0}", path);                }            }            foreach (var path in pathsAddedToBeginning)            {                if (!sp.Contains(path))                {                    sp.Insert(0, path);                    Ed.WriteLine("\nInserted Path {0}", path);                }            }             sp.SaveChanges();        }          /// <summary>        /// Clears current printer configuration paths & adds new path & Defalt path usng enviroment variables.        /// </summary>        [CommandMethod("AddPrinterConfigPaths")]        public void AddPrinterConfigPaths()        {            PrinterConfigPath config = Preferences.PrinterConfigPath;            config.Clear();            var newConfig = @"C:\Testing\AutoCAD\Plotting\Plotters";            config.Add(newConfig);            var defaultConfig = @"%appdata%\Autodesk\AutoCAD 2020\R23.1\enu\Plotters";            config.Add(defaultConfig);            Ed.WriteLine("\nAdded Path {0}", newConfig);            Ed.WriteLine("\nAdded Path {0}", defaultConfig);            config.SaveChanges();        }        /// <summary>        /// Clears current printer description paths & adds new path.        /// </summary>        [CommandMethod("AddPrinterDescPaths")]        public void AddPrinterDescPaths()        {            PrinterDescPath desc = Preferences.PrinterDescPath;            desc.Clear();            var newDesc = @"C:\Testing\AutoCAD\Plotting\Plotters\PMP Files";            desc.Add(newDesc);            Ed.WriteLine("\nAdded Path {0}", newDesc);            desc.SaveChanges();        }         /// <summary>        /// Clears current printer style paths & adds new path.        /// </summary>        [CommandMethod("AddPrinterStyleSheetPaths")]        public void AddPrinterStyleSheetPaths()        {            PrinterStyleSheetPath styles = Preferences.PrinterStyleSheetPath;            styles.Clear();            var style = @"C:\Testing\AutoCAD\Plotting\PlotStyles";            styles.Add(style);            Ed.WriteLine("\nAdded Path {0}", style);            styles.SaveChanges();        } 
Class that returns different SupportPaths feeding dynamic object into constructors

--- Code - C#: --- public static class Preferences    {        /// <summary>        /// Gets the acad preferences.        /// </summary>        /// <value>        /// The acad preferences.        /// </value>        private static dynamic AcadPreferences        { get { return Application.Preferences; } }         /// <summary>        /// Gets the support paths.        /// </summary>        /// <value>        /// The support paths.        /// </value>        public static SupportPath SupportPaths { get { return new SupportPath(AcadPreferences); } }         /// <summary>        /// Gets the tool palette paths.        /// </summary>        /// <value>        /// The tool palette paths.        /// </value>        public static ToolPalettePath ToolPalettePaths { get { return new ToolPalettePath(AcadPreferences); } }         /// <summary>        /// Gets the printer configuration path.        /// </summary>        /// <value>        /// The printer configuration path.        /// </value>        public static PrinterConfigPath PrinterConfigPath { get { return new PrinterConfigPath(AcadPreferences); } }         /// <summary>        /// Gets the printer desc path.        /// </summary>        /// <value>        /// The printer desc path.        /// </value>        public static PrinterDescPath PrinterDescPath { get { return new PrinterDescPath(AcadPreferences); } }         /// <summary>        /// Gets the printer style sheet path.        /// </summary>        /// <value>        /// The printer style sheet path.        /// </value>        public static PrinterStyleSheetPath PrinterStyleSheetPath { get { return new PrinterStyleSheetPath(AcadPreferences); } }         /// <summary>        /// Gets the template DWG path.        /// </summary>        /// <value>        /// The template DWG path.        /// </value>        public static TemplateDWGPath TemplateDWGPath { get { return new TemplateDWGPath(AcadPreferences); } }         /// <summary>        /// Gets the enterprise menu file.        /// </summary>        /// <value>        /// The enterprise menu file.        /// </value>        public static EnterpriseMenuFile EnterpriseMenuFile { get { return new EnterpriseMenuFile(AcadPreferences); } }         /// <summary>        /// Gets the menu file.        /// </summary>        /// <value>        /// The menu file.        /// </value>        public static MenuFile MenuFile { get { return new MenuFile(AcadPreferences); } }         /// <summary>        /// Gets the display scroll bars.        /// </summary>        /// <value>        /// The display scroll bars.        /// </value>        public static DisplayScrollBars DisplayScrollBars { get { return new DisplayScrollBars(AcadPreferences); } }         /// <summary>        /// Gets the SCM time value.        /// </summary>        /// <value>        /// The SCM time value.        /// </value>        public static SCMTimeValue SCMTimeValue { get { return new SCMTimeValue(AcadPreferences); } }         /// <summary>        /// Gets the page setup overrides template file.        /// </summary>        /// <value>        /// The page setup overrides template file.        /// </value>        public static PageSetupOverridesTemplateFile PageSetupOverridesTemplateFile { get { return new PageSetupOverridesTemplateFile(AcadPreferences); } }         /// <summary>        /// Gets the q new template file.        /// </summary>        /// <value>        /// The q new template file.        /// </value>        public static QNewTemplateFile QNewTemplateFile { get { return new QNewTemplateFile(AcadPreferences); } }    } 
SupportPath class handles enabling using environment variables, joining & splitting list of paths with';', functions to add, remove, clear, insert at indexes, etc.......

--- Code - C#: ---  public class SupportPath : IAcadPathRepository    {        /// <summary>        /// The seperator        /// </summary>        private static char[] seperator = new char[] { ';' };          /// <summary>        /// The paths        /// </summary>        private List<string> paths = new List<string>();          /// <summary>        /// Gets or sets the preferences.        /// </summary>        /// <value>        /// The preferences.        /// </value>        protected dynamic Preferences { get; set; }          /// <summary>        /// Gets or sets the preferences file.        /// </summary>        /// <value>        /// The preferences file.        /// </value>        protected virtual dynamic PreferencesFile        {            get { return Preferences.Files.SupportPath; }            set { Preferences.Files.SupportPath = value; }        }          /// <summary>        /// Initializes a new instance of the <see cref="SupportPath"/> class.        /// </summary>        /// <param name="acadPreferences">The acad preferences.</param>        public SupportPath(object acadPreferences)        {            Preferences = acadPreferences;            paths = CreatepathList(PreferencesFile);        }          /// <summary>        /// Gets the paths.        /// </summary>        /// <returns></returns>        public IEnumerable<string> GetPaths()        {            return paths.AsReadOnly();        }          /// <summary>        /// Adds the specified path.        /// </summary>        /// <param name="path">The path.</param>        public void Add(string path)        {            path = Expand(path);            paths.Add(path);        }          /// <summary>        /// Inserts the specified index.        /// </summary>        /// <param name="index">The index.</param>        /// <param name="path">The path.</param>        public void Insert(int index, string path)        {            path = Expand(path);            paths.Insert(index, path);        }          /// <summary>        /// Removes the specified path.        /// </summary>        /// <param name="path">The path.</param>        /// <returns></returns>        public bool Remove(string path)        {            path = Expand(path);            int index = paths.FindIndex(p => p.Equals(path, StringComparison.OrdinalIgnoreCase));            paths.RemoveAt(index);            return index > -1;        }          /// <summary>        /// Removes at.        /// </summary>        /// <param name="index">The index.</param>        public void RemoveAt(int index)        {            paths.RemoveAt(index);        }          /// <summary>        /// Removes all.        /// </summary>        /// <param name="match">The match.</param>        /// <returns></returns>        public int RemoveAll(Predicate<string> match)        {            return paths.RemoveAll(match);        }          /// <summary>        /// Removes the range.        /// </summary>        /// <param name="index">The index.</param>        /// <param name="count">The count.</param>        public void RemoveRange(int index, int count)        {            paths.RemoveRange(index, count);        }          /// <summary>        /// Clears this instance.        /// </summary>        public void Clear()        {            paths.Clear();        }          /// <summary>        /// Determines whether [contains] [the specified path].        /// </summary>        /// <param name="path">The path.</param>        /// <returns></returns>        public bool Contains(string path)        {            return paths.Contains(Expand(path), StringComparer.OrdinalIgnoreCase);        }          /// <summary>        /// Saves the changes.        /// </summary>        public void SaveChanges()        {            this.PreferencesFile = CreatePathsString(paths);            paths = CreatepathList(PreferencesFile);        }          /// <summary>        /// Createpathes the list.        /// </summary>        /// <param name="pathString">The path string.</param>        /// <returns></returns>        private static List<string> CreatepathList(string pathString)        {            return pathString.Split(seperator).ToList();        }          /// <summary>        /// Creates the paths string.        /// </summary>        /// <param name="pathList">The path list.</param>        /// <returns></returns>        private static string CreatePathsString(IEnumerable<string> pathList)        {            return String.Join(";", pathList);        }          /// <summary>        /// Expands the specified path.        /// </summary>        /// <param name="path">The path.</param>        /// <returns></returns>        private static string Expand(string path)        {            return path.StartsWith("%") ? Environment.ExpandEnvironmentVariables(path) : path;        }    }
These classes below just overwrite the SupportPath dynamic PreferencesFile function to feed in specific support paths.

--- Code - C#: --- public class PrinterConfigPath : SupportPath    {        /// <summary>        /// Initializes a new instance of the <see cref="PrinterConfigPath"/> class.        /// </summary>        /// <param name="acadPreferences">The acad preferences.</param>        public PrinterConfigPath(object acadPreferences)            : base(acadPreferences)        {        }         /// <summary>        /// Gets or sets the preferences file.        /// </summary>        /// <value>        /// The preferences file.        /// </value>        protected override dynamic PreferencesFile        {            get { return Preferences.Files.PrinterConfigPath; }            set { Preferences.Files.PrinterConfigPath = value; }        }    }  public class PrinterDescPath : SupportPath    {        /// <summary>        /// Initializes a new instance of the <see cref="PrinterDescPath"/> class.        /// </summary>        /// <param name="acadPreferences">The acad preferences.</param>        public PrinterDescPath(object acadPreferences)            : base(acadPreferences)        {        }         /// <summary>        /// Gets or sets the preferences file.        /// </summary>        /// <value>        /// The preferences file.        /// </value>        protected override dynamic PreferencesFile        {            get { return Preferences.Files.PrinterDescPath; }            set { Preferences.Files.PrinterDescPath = value; }        }    }  public class PrinterStyleSheetPath : SupportPath    {        /// <summary>        /// Initializes a new instance of the <see cref="PrinterStyleSheetPath"/> class.        /// </summary>        /// <param name="acadPreferences">The acad preferences.</param>        public PrinterStyleSheetPath(object acadPreferences)            : base(acadPreferences)        {        }         /// <summary>        /// Gets or sets the preferences file.        /// </summary>        /// <value>        /// The preferences file.        /// </value>        protected override dynamic PreferencesFile        {            get { return Preferences.Files.PrinterStyleSheetPath; }            set { Preferences.Files.PrinterStyleSheetPath = value; }        }    } 

It's Alive!:
Very cool!

gile:
Nice code Jeff (as usual).

The dynamic type can also be used with plain .NET and the Dynamic Language Runtime.


--- Code - C#: ---        public static void AddCircle(Point3d center, double radius)        {            dynamic btr = HostApplicationServices.WorkingDatabase.CurrentSpaceId;            btr.AppendEntity(new Circle(center, Vector3d.ZAxis, radius));        }         public static void ToLayer0()        {            dynamic bt = HostApplicationServices.WorkingDatabase.BlockTableId;            foreach (var btr in bt)                if (!btr.IsLayout)                    foreach (var ent in btr)                        ent.Layer = "0";        }         public static List<string> LayoutList()        {            var layouts = new List<string>();            dynamic dict = HostApplicationServices.WorkingDatabase.LayoutDictionaryId;            foreach (var item in dict)                layouts.Add(item.Key);            return layouts;        }

Navigation

[0] Message Index

Go to full version