.NET

Reply
Distinguished Contributor
alex_b
Posts: 393
Registered: ‎08-15-2003
Message 11 of 19 (451 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 04:43 PM in reply to: khoa.ho

Khoa

 

It uses NET 2.0 indeed, but the references are to A2008, so it should be OK.

One more detail: which I missed pasting: The FileNotFound is thrown as:

 

Could not load file or assembly 'acmgd, Version=17.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

And I noticed that the version shown in Add Reference is 17.1.51.0. Could that be it?

 

I even tried to put the executable in the A2008 folder, so it won't have any trouble loading dll's.

This is what happened:

******************************************************************************

System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> <CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load during process initialization.
 ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

  at AcPlPlotReactor.{ctor}(AcPlPlotReactor* )
   at ?A0x860c6007.??__EgPlotReactor@@YMXXZ()
   at _initterm_m((fnptr)* pfbegin, (fnptr)* pfend)
   at <CrtImplementationDetails>.LanguageSupport.InitializePerProcess(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport._Initialize(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String errorMessage, Exception innerException)
   at <CrtImplementationDetails>.ThrowModuleLoadException(String , Exception )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   at .cctor()
   --- End of inner exception stack trace ---
   at LL.Form1.GetAutocadPluginVersion(String dllPath)

*******************************************************************************************

Does this mean anyrhing to you?

 

THanks

 

alex

Mentor
khoa.ho
Posts: 159
Registered: ‎09-15-2011
Message 12 of 19 (434 Views)

Re: Is dll a AutoCAD plug-in?

10-20-2012 11:49 PM in reply to: alex_b

Alex,

The error of "Could not load file or assembly 'acmgd, Version=17.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies." is the problem of reading unmanaged DLL dependencies of acmgd.dll. When your .NET program references acmgd.dll to use CommandMethodAttribute, it fails to load its native unmanaged dependencies. This is a problem of .NET reflection to load native C++ assemblies. I still don't know how to fix that. I will come to find the solution later.

-Khoa

Distinguished Contributor
alex_b
Posts: 393
Registered: ‎08-15-2003
Message 13 of 19 (422 Views)

Re: Is dll a AutoCAD plug-in?

10-21-2012 04:48 AM in reply to: khoa.ho

Khoa,

 

>>I will come to find the solution later.

So there is still hope..

I admit that I don't understand much of this, but just a thought: What about using CustomAttributeData class and thus avoiding loading acmgd.dll at all?

 

Thanks

 

alex

Mentor
khoa.ho
Posts: 159
Registered: ‎09-15-2011
Message 14 of 19 (397 Views)

Re: Is dll a AutoCAD plug-in?

10-21-2012 10:37 PM in reply to: alex_b

Alex,

 

I made a new console app (without any references to AutoCAD assemblies such as acmgd.dll) and got exactly the same problem with your program. I revised my posted code to capture error events. But it is not finished to post here.

 

“The type initializer for '<Module>' threw an exception...” indicates that the .NET reflector fails when trying to reference unmanaged assemblies inside acmgd.dll

 

CustomAttributeData.GetCustomAttributes() has the same error of "Could not load file or assembly 'acmgd, Version=17.2.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies."

 

CustomAttributeData.GetCustomAttributes(methodInfo) is similar to methodInfo.GetCustomAttributes(true). CustomAttributeData class is more generic to accept many object types to retrieve their attributes.

 

The problem as I mentioned previously is .NET reflection tries to load dependent C++ assemblies during reading the AutoCAD plug-in file. It can read acmgd.dll at the AutoCAD installation folder but fails to read all its unmanaged dependencies. I still try to figure how to prevent reading those unnecessary C++ dependencies of acmgd.dll.

 

There is no problem if the posted code works inside AutoCAD. But outside AutoCAD as a console app, it will cause a problem.

 

-Khoa

Distinguished Contributor
alex_b
Posts: 393
Registered: ‎08-15-2003
Message 15 of 19 (385 Views)

Re: Is dll a AutoCAD plug-in?

10-22-2012 11:20 AM in reply to: khoa.ho

Khoa

 

1.My Reflector 6 program suceeds in doing what I'm looking for: It finds the methods having the CommandMethod attribute, which shows that it is possible to do it.

 

2. From MSDN CustomAttributeData class docu:

CustomAttributeData can be used in the execution context as well as in the reflection-only context. For example, you might want to avoid loading the assembly that contains the code for a custom attribute.

 

2Maybe?

 

To make a hard task harder (for me, not you), what about the same problem for .arx files (here we know they are Acad plug-ins, we just have to find the commands).

 

alex

Mentor
khoa.ho
Posts: 159
Registered: ‎09-15-2011
Message 16 of 19 (358 Views)

Re: Is dll a AutoCAD plug-in?

10-22-2012 10:34 PM in reply to: alex_b

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

Distinguished Contributor
alex_b
Posts: 393
Registered: ‎08-15-2003
Message 17 of 19 (308 Views)

Re: Is dll a AutoCAD plug-in?

11-02-2012 04:37 AM in reply to: khoa.ho

Khoa

 

>>...I found Mono.Cecil is a great library to support .NET reflection but it requires learning curve and time.

 

Surprisingly (or maybe not) there was almost no learning curve, due in part probably to the complete lack of documentation.

I downloaded the library and it took 15 minutes to get the results.

Here is the code, and it works:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Mono.Cecil;
using System.Text;
//code not extensively tested yet
//TODO add error checking
//TODO fix it for Unicode. for now CustomAttribute.Blob is just raw ASCII data with some obscure formatting (additional ASCII 0 and ASCII 8 added)

namespace ReflectionAcadPlugins
{
	class Program
	{
		public static void Main()
		{
			//Creates an AssemblyDefinition from the "MyLibrary.dll" assembly
			AssemblyDefinition myLibrary = AssemblyFactory.GetAssembly(@"MyLibrary.dll");
			//Gets all the program modules
			ModuleDefinitionCollection modules = myLibrary.Modules;
			foreach (ModuleDefinition mod in modules)
			{
				//Gets all types/classes which are declared in the module
				TypeDefinitionCollection types = mod.Types;
				foreach (TypeDefinition type in mod.Types)
				{
					if (type == null) continue;
					//gets all methods in this class
					MethodDefinitionCollection methods = type.Methods;
					//gets all custom attributes for this method
					foreach (MethodDefinition met in methods)
					{
						CustomAttributeCollection attribs = met.CustomAttributes;
						//checks it the attribute is what we want
						foreach (CustomAttribute attr in attribs)
						{
							if (attr.Constructor.ToString().Contains("CommandMethodAttribute"))
							{
								Byte[] bytes = attr.Blob;
								string cmd = System.Text.ASCIIEncoding.ASCII.GetString(bytes);
								cmd = ReplaceNonPrintableCharacters(cmd);
								Console.WriteLine(cmd);
							}
						}
					}
				}
			}
		}
		static string ReplaceNonPrintableCharacters(string s)
		{
			StringBuilder 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();
		}

 So your tip about Mono.Cecil was great.

 

Thank you

 

alex

Distinguished Contributor
alex_b
Posts: 393
Registered: ‎08-15-2003
Message 18 of 19 (304 Views)

Re: Is dll a AutoCAD plug-in?

11-02-2012 05:34 AM in reply to: alex_b

Just remembered:

I still need to do the same (extracting the command names) for arx files.

I haven't a clue how to go about it.

Any ideas?

 

Mentor
khoa.ho
Posts: 159
Registered: ‎09-15-2011
Message 19 of 19 (289 Views)

Re: Is dll a AutoCAD plug-in?

11-02-2012 12:25 PM in reply to: alex_b

Hi Alex,

 

I am happy that you could make it work with Mono.Cecil library, as I found .NET framework has some limitations for reflection. Your topic is also very interesting to me to start playing with .NET Reflection.

 

-Khoa

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community