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