.NET

Reply
Distinguished Contributor
alex_b
Posts: 405
Registered: ‎08-15-2003
Message 1 of 19 (1,049 Views)

Is dll a AutoCAD plug-in?

1049 Views, 18 Replies
10-16-2012 09:58 PM

Hi

 

I'm looking for a way to programmatically check if a dll file is a AutoCAD plug-in, preferably getting the version too.

 

The only thing I can think of is using

 

System.Reflection.Assembly.ReflectionOnlyLoad()

 

to load the dll, search thru its referrences looking for Acad-specific (acdbmgd etc.) get the reference version, compare it to a list....

 

Is there a simpler way?

 

Thanks

 

alex

*Expert Elite*
norman.yuan
Posts: 1,064
Registered: ‎04-27-2009
Message 2 of 19 (1,011 Views)

Re: Is dll a AutoCAD plug-in?

10-17-2012 02:36 PM in reply to: alex_b

Using whether acdbmgd/acmgd.dll is referenced in a DLL or not to decide if a DLL is an AutoCAD plug-in DLL is not reliable, IMO. Actually, the term of "AutoCAD Plug-in" isn't quite clear enough to classify DLLs.

 

For example, we can build a few dlls, one does file/folder manupulation, another does data read/write to file/database...They do not have to have reference to acad .NET API assemblies at all. Then we can simply create a acad .NET API dll that defines coomands that execute the functions in those DLLs. In this case, can you say only the last DLL is AutoCAD Plug-in DLL, while others are not?

 

Maybe, you want to explain what exactly you want to achieve, then someone would have better advice/suggestion.

Distinguished Contributor
alex_b
Posts: 405
Registered: ‎08-15-2003
Message 3 of 19 (999 Views)

Re: Is dll a AutoCAD plug-in?

10-17-2012 11:13 PM in reply to: norman.yuan

Norman

 

I'm trying to identify which dll's on my disk drive can be loaded into AutoCAD, and into which Acad version.

As such, I do not need to identify referenced dll's. Those will be pulled in by the plug-in once ir is loaded.

So I guess I have to identify those dll's which define a Acad command.

 

Thanks

alex

Mentor
khoa.ho
Posts: 224
Registered: ‎09-15-2011
Message 4 of 19 (974 Views)

Re: Is dll a AutoCAD plug-in?

10-18-2012 05:02 PM in reply to: alex_b

Based on your explanation, I wrote the following code to check if a DLL is an AutoCAD plug-in or not. If it is, get the AutoCAD version.

 

I used System.Reflection.Assembly.ReflectionOnlyLoadFrom() to load context of a DLL file from its location.

 

[CommandMethod("GetAutocadPluginVersion")]
public static void GetAutocadPluginVersion()
{
	string dllPath = @"C:\Temp\AutocadPlugin.dll";
	string acadVersion = GetAutocadPluginVersion(dllPath);

	Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
	string message = string.IsNullOrEmpty(acadVersion)
		? "This DLL is not an AutoCAD plug-in"
		: "This DLL is an AutoCAD plug-in that supports AutoCAD " + acadVersion;
	editor.WriteMessage(message);
}

private static string GetAutocadPluginVersion(string dllPath)
{
	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 dllName = "acdbmgd";
	string acadVersion = string.Empty;

	Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(dllPath);
	AssemblyName[] assemblyNames = assembly.GetReferencedAssemblies();
	foreach (AssemblyName assemblyName in assemblyNames)
	{
		string name = assemblyName.Name;
		if (name.ToLower() == dllName.ToLower())
		{
			string version = assemblyName.Version.Major + "." + assemblyName.Version.Minor;
			if (AutoCADVersion.ContainsKey(version))
			{
				acadVersion = AutoCADVersion[version];
			}
			break;
		}
	}
	return acadVersion;
}

 

-Khoa

Distinguished Contributor
alex_b
Posts: 405
Registered: ‎08-15-2003
Message 5 of 19 (947 Views)

Re: Is dll a AutoCAD plug-in?

10-19-2012 06:08 AM in reply to: khoa.ho

khoa:

 

Excelent. Works perfectly. I had some trouble initializing the Dictionary in .NET 2.0 but it's OK now.

One more question: how can we retrieve the command names defined in the plug-in?

 

Thanks

 

alex

Mentor
khoa.ho
Posts: 224
Registered: ‎09-15-2011
Message 6 of 19 (924 Views)

Re: Is dll a AutoCAD plug-in?

10-19-2012 05:01 PM in reply to: alex_b

AutoCAD command is defined by CommandMethod attribute. We use reflection MethodInfo.GetCustomAttributes() to get all custom attributes including AutoCAD CommandMethodAttribute.

 

Assembly.ReflectionOnlyLoadFrom() is used to get all references, so it is faster to load only context in the DLL.

Assembly.LoadFile() is used to get all contents of the DLL, so it loads all methods and their custom attributes.

 

I rewrote the code a little bit complicated to make it a nice custom command in AutoCAD. When user types a new command AcadPluginDetails, it will prompt to select a DLL file to check if it is an AutoCAD plug-in or not, and list all found commands in this plug-in.

 

[CommandMethod("AcadPluginDetails")]
public static void GetAutocadPluginDetails()
{
	Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;

	var promptOpenFile = new PromptOpenFileOptions("Select an DLL file")
		{
			Filter = "Dynamic libraries (*.dll)|*.dll"
		};
	PromptFileNameResult res = editor.GetFileNameForOpen(promptOpenFile);
	string dllPath = res.StringResult;
	if (string.IsNullOrEmpty(dllPath))
		return;

	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()));

	editor.WriteMessage(message);
}

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);
		// Check if this assembly is the defined dllName
		AssemblyName loadedAssemblyName = assembly.GetName();
		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 (System.Exception ex)
	{
	}
	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
	{
		// Loads the contents of an assembly file
		Assembly assembly = Assembly.LoadFile(dllPath);
		// Get all types/classes in this assembly
		Type[] types = assembly.GetTypes();
		foreach (Type type in types)
		{
			// Get all methods in this class
			MethodInfo[] methodInfos = type.GetMethods();
			foreach (MethodInfo methodInfo in methodInfos)
			{
				// Get AutoCAD command's attribute
				object[] attributes = methodInfo.GetCustomAttributes(typeof(CommandMethodAttribute), true);
				if (attributes.Length > 0)
				{
					// Get AutoCAD command name
					string commandName = ((CommandMethodAttribute)attributes[0]).GlobalName;
					commandList.Add(commandName);
				}
			}
		}
	}
	catch (System.Exception ex)
	{
	}
	return commandList;
}

 

-Khoa

Distinguished Contributor
alex_b
Posts: 405
Registered: ‎08-15-2003
Message 7 of 19 (899 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 03:00 AM in reply to: khoa.ho

Khoa

 

The code you posted is fine, thank you.

My problem is, I do this in an out-of-process COM.

The 1st part is OK, it identifies the Acad plug-ins and thei versions.

But, when calling GetAllAutocadCommands() I get a File Not Found exception, presumably because the CommandMethodAttribute is defined in one of the Autocad dll's, the JIT tries to pull in all the referrenced dll's and can't find or load them.

I tried using CustomAttributeData.GetCustomAttributes(Assembly) but it raises the same exception.

Is there a workaround?

 

Thanks

 

alex

I

Mentor
khoa.ho
Posts: 224
Registered: ‎09-15-2011
Message 8 of 19 (883 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 01:29 PM in reply to: alex_b

Hi Alex,

Can you give more details about the error of "File Not Found" exception. What specific code causes that error?

CommandMethodAttribute is a class inside acmgd.dll, so make sure you reference this AutoCAD assembly in your out-of-process COM program.

Assembly.LoadFile() will raise error if it loads native DLL files (BadImageFormatException with no manifest of an unmanaged assembly), or managed assemblies built with higher .NET framework. My latest code will handle this error.

-Khoa

Distinguished Contributor
alex_b
Posts: 405
Registered: ‎08-15-2003
Message 9 of 19 (877 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 01:56 PM in reply to: khoa.ho

Hi Khoa

 

Yes, I do reference acmgd.dll and acdbmgd.dll

The exception is:

System.IO.FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)

on the line:

GetAllAutocadCommands(dllPath);

My understanding is that the JIT compiler tries to compile the method, looks for the CommandMethodAttribute type, tries to load acmgd.dll and fails (on it or one of its dependencies). I haven't been able to find what's missing (in any case acmgd references only system dll's and acdbmgd).

 

Thanks

 

alex

Mentor
khoa.ho
Posts: 224
Registered: ‎09-15-2011
Message 10 of 19 (871 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 03:21 PM in reply to: alex_b

I guess your program may use .NET framework 2.0, but it references acdbmgd.dll and acmgd.dll in .NET higher version, such as 3.0 (A2009), 3.5 (A2010 & A2011), or 4.0 (A2012 & A2013). AutoCAD 2007 & 2008 use .NET 2.0.

Make sure your program is using equal or higher .NET version than framework of acmgd.dll. Otherwise, the reflection of lower runtime framework cannot read assemblies of higher framework, and raises errors.

-Khoa

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.