Our company has an internal tool to check for all referenced assemblies of a given .NET Assembly. This is very handy for figuring out what to send to the customer, etc.
This works great for normal .net assemblies (both .dll and .exe).
When I use this tool on an AutoCAD project's .dll file, I get a FileNotFoundException on acdbmgd.dll. This happens even when copying that dll over to the directory of the source .dll file.
Is there anything special about the autocad .dll files?
Hi,
You can follow my previous post with alex_b on Nov 2 (Is dll a AutoCAD plug-in?). Use Mono.Cecil library to get reflection of unmanaged AutoCAD assemblies (acdbmgd.dll, acmgd.dll, accoremgd.dll...).
Use Mono.Collections.Generic.Collection<ModuleDefinition> modules = assembly.Modules; to load unmanaged referenced assemblies.
Here is the code to read an AutoCAD plug-in:
// Copyright by Khoa Ho
using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; using Mono.Cecil; namespace AcadReflection { class ManagedAssembly { static void Main1(string[] args) { try { string dllPath = @"C:\Program Files\Autodesk\AutoCAD Plant 3D 2013 - English\AcCalcUi.dll"; string output = GetAutocadPluginDetails(dllPath); Console.WriteLine(output); } catch (BadImageFormatException ex) { Console.WriteLine(ex.Message + "\n" + ex.StackTrace); } } #region Reflection with .NET framework public static string GetAutocadPluginDetails(string dllPath) { try { if (string.IsNullOrEmpty(dllPath)) return string.Empty; string dllName = Path.GetFileName(dllPath); string acadVersion = GetAutocadPluginVersion(dllPath); List<string> acadCommands = GetAllAutocadCommands(dllPath); string message = string.IsNullOrEmpty(acadVersion) ? "File " + dllName + " is not an AutoCAD plug-in" : "File " + dllName + " is an AutoCAD plug-in that supports AutoCAD " + acadVersion + (acadCommands.Count == 0 ? string.Empty : "\nFound commands in this plug-in: " + String.Join(", ", acadCommands.ToArray())); return message; } catch (BadImageFormatException ex) { throw; } } private static string GetAutocadVersion(AssemblyName assemblyName) { var AutoCADVersion = new Dictionary<string, string> { { "15.0", "2000" }, { "15.1", "2000i" }, { "15.6", "2002" }, { "16.0", "2004" }, { "16.1", "2005" }, { "16.2", "2006" }, { "17.0", "2007" }, { "17.1", "2008" }, { "17.2", "2009" }, { "18.0", "2010" }, { "18.1", "2011" }, { "18.2", "2012" }, { "19.0", "2013" } }; string acadVersion = string.Empty; string version = assemblyName.Version.Major + "." + assemblyName.Version.Minor; if (AutoCADVersion.ContainsKey(version)) { acadVersion = AutoCADVersion[version]; } return acadVersion; } // Get the AutoCAD version of a given DLL file, // returns empty string if it is not an AutoCAD plug-in public static string GetAutocadPluginVersion(string dllPath) { string acadVersion = string.Empty; // Indicate the most common DLL name referencing in an AutoCAD plug-in const string dllName = "acdbmgd"; // Loads an assembly into the reflection-only context, given its path try { Assembly assembly = Assembly.ReflectionOnlyLoadFrom(dllPath); AssemblyName loadedAssemblyName = assembly.GetName(); // Check if this assembly is the defined dllName if (loadedAssemblyName.Name.ToLower() == dllName.ToLower()) { acadVersion = GetAutocadVersion(loadedAssemblyName); } else // this assembly is not acdbmgd.dll { AssemblyName[] assemblyNames = assembly.GetReferencedAssemblies(); foreach (AssemblyName assemblyName in assemblyNames) { string name = assemblyName.Name; if (name.ToLower() == dllName.ToLower()) { acadVersion = GetAutocadVersion(assemblyName); break; } } } } catch (Exception ex) { throw; } return acadVersion; } // Retrieve all AutoCAD commands from a given DLL plug-in file public static List<string> GetAllAutocadCommandsNET(string dllPath) { var commandList = new List<string>(); try { AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomainOnReflectionOnlyAssemblyResolve; // Loads the contents of an assembly file Assembly assembly = Assembly.ReflectionOnlyLoadFrom(dllPath); // Get all types/classes in this assembly Type[] types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException typeException) { types = typeException.Types; } foreach (Type type in types) { if (type == null) continue; // Get all methods in this class MethodInfo[] methodInfos = type.GetMethods(); foreach (MethodInfo methodInfo in methodInfos) { try { // Get AutoCAD command's attribute //object[] attributes = methodInfo.GetCustomAttributes(false); IList<CustomAttributeData> attributeDataList = CustomAttributeData.GetCustomAttributes(methodInfo); foreach (CustomAttributeData customAttributeData in attributeDataList) { if (customAttributeData.GetType().Name == "CommandMethodAttribute") { // Get AutoCAD command name string commandName = ""; // ((CommandMethodAttribute)attributes[0]).GlobalName; commandList.Add(commandName); } } } catch (FileNotFoundException fileException) { //throw; } } } } catch (BadImageFormatException ex) { throw; } return commandList; } private static Assembly CurrentDomainOnReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args) { return Assembly.ReflectionOnlyLoad(args.Name); } #endregion #region Reflection with Mono.Cecil public static List<string> GetAllAutocadCommands(string dllPath, string acadCommandAttribute = "CommandMethodAttribute") { var commandList = new List<string>(); try { AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(dllPath); // Get all program modules Mono.Collections.Generic.Collection<ModuleDefinition> modules = assembly.Modules; foreach (ModuleDefinition module in modules) { // Get all types/classes which are declared in the module Mono.Collections.Generic.Collection<TypeDefinition> types = module.Types; foreach (TypeDefinition type in types) { if (type == null) continue; // Get all methods in this class Mono.Collections.Generic.Collection<MethodDefinition> methods = type.Methods; // Get all custom attributes for this method foreach (MethodDefinition method in methods) { Mono.Collections.Generic.Collection<CustomAttribute> attributes = method.CustomAttributes; // Check if the attribute is what we want foreach (CustomAttribute attribute in attributes) { if (attribute.Constructor.ToString().Contains(acadCommandAttribute)) { Byte[] bytes = attribute.GetBlob(); string command = ASCIIEncoding.ASCII.GetString(bytes); command = ReplaceNonPrintableCharacters(command); commandList.Add(command); } } } } } } catch (Exception ex) { } return commandList; } static string ReplaceNonPrintableCharacters(string s) { var result = new StringBuilder(); for (int i = 0; i < s.Length; i++) { char c = s[i]; byte b = (byte)c; if (b >= 32) result.Append(c); } return result.ToString(); } #endregion } }
-Khoa