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