Alex,
CustomAttributeData.GetCustomAttributes() always throws exception when reading attributes. I still don't know how to prevent loading acmgd.dll and its dependencies. The .NET reflection throws errors when loading unmanaged assemblies.
.NET Reflector software and other disassembly tools can read custom attributes (of assembly, class, method) nicely without loading dependencies. I don't know how it can do that. This is something we need to learn. I found Mono.Cecil is a great library to support .NET reflection but it requires learning curve and time.
To keep you moving forward, I post the code of a sample console app that can read an AutoCAD plug-in to find its AutoCAD version, but it fails to get all AutoCAD commands. In Visual Studio, create a new simple console app (prefer .NET 4.0 to read all AutoCAD plug-in versions) without any extra references, and then copy the code to the file Program.cs.
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace AcadReflection
{
class Program
{
static void Main(string[] args)
{
try
{
string dllPath = @"C:\Program Files\AutoCAD PID 2009\AcCalcUi.dll";
string output = GetAutocadPluginDetails(dllPath);
Console.WriteLine(output);
}
catch (BadImageFormatException ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
#region Reflection
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> GetAllAutocadCommands(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 System.Reflection.Assembly.ReflectionOnlyLoad(args.Name);
}
#endregion
}
}
-Khoa