因为.net需要用NETLOAD命令
AutoCAD core libraries are all written in unmanaged code (C++ I believe). Ultimately, whatever API you choose to develop your plugins, you will be manipulating the unmanaged AutoCAD objects from those core libraries via one of their APIs. Aside from the three types of files you mentioned, there is a number of other ways to create plugins for AutoCAD. Some examples include: Lisp Scripting, VBA Script, COM Clients (VB, Java, Delphi). Most of these are now outdated, and these days the .Net and C++(ObjectARX) APIs are most popular. However, the rest are still in use for legacy reasons. If you're starting a new module, you would use either .Net or ARX.
.NET API is a set of .NET wrapper libraries that wrap the ObjectARX API. Most common dlls you would reference are accoremgd.dll, acdbmgd.dll and acmgd.dll, but there are others. These libraries allow you to manipulate native AutoCad objects though a .NET language. If you would like to create plug-ins for AutoCad in C#, then you only need to code in C#. It is great for development speed, but the performance of your code will be somewhat inferior to ARX plugins. That being said, I really want to emphasize that it is still damn fast. I have not found the need to code in C++ for AutoCAD due to performance issues. Overall it is very powerful and feature rich. You can do pretty well anything to a drawing using C# only.
Have a look at this answer I gave recently. It should answer most if not all your questions about getting started with AutoCAD plug-in development in .Net.
ObjectARX API is very similar to what I described for the .NET API, except you code in C++. Some of the libraries include rxapi.lib, accore.lib, acgiapi.lib, acdrawbridge.lib as well as some others. Development using C++ is considerably more cumbersome than when using C#, but C++ code runs faster, although not by a large margin.
CUIX files live in a whole different galaxy. They are used for customizing the UI among other related things. You can browse various uses of cuix files here.
Your choice will really come down to what you are doing. If you are writing code that will batch process hundreds of thousands of drawings as fast as possible, you will want to explore the C++ API. If you are processing just hundreds of drawings or just creating a bunch of commands for users, I would vehemently urge you to use the C# API. It is worth the small hit in performance that will almost never be perceptible to the user.
For more information, go to this AutoDesk link, and scroll down to the training labs. I would recommend that you at least read through both ObjectARX and .NET Training labs. Once you choose what you want to use, go through all the labs for the one of your choice. You will thank yourself later as you will save countless hours of headache and frustration!
I have written the .net-module (dll-file) which can be loaded in AutoCAD by means of command NETLOAD. Has checked up - all works. But I want to have possibility not only to load, but also unload such modules - therefore I want to load them at once in separate AppDomain.
I read MSDN here. Hasn't understood, what sense in AppDomain. Load if it loads the code not only in the domain necessary to me but also in the main:
If the current AppDomain object represents application domain A, and the Load method is called from application domain B, the assembly is loaded into both application domains. For example, the following code loads MyAssembly into the new application domain ChildDomain and also into the application domain where the code executes:Code: [Select]AppDomain ad = AppDomain.CreateDomain("ChildDomain");
ad.Load("MyAssembly");
?
That the code was loaded only in that module which it is necessary - I have tried to use CrossAppDomainDelegate in my code sample (C# code):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using acad = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Reflection;
[assembly: CommandClass(typeof(DomainUseSample.Class1))]
namespace DomainUseSample
{
public sealed class Class1
{
static AppDomain dom;
string path = @"D:\MD\Visual Studio 2010\CmdSample\CmdSample\bin\Debug\CmdSample.dll";
[CommandMethod("bush", "dload", CommandFlags.Session)]
public void Load()
{
if (dom != null)
{
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage("The domain already exists.\n");
return;
}
dom = AppDomain.CreateDomain("TestDomain");
try
{
dom.DoCallBack(new CrossAppDomainDelegate(LoadDll));
}
catch (System.Exception ex)
{
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage(string.Format("Excetion message: \"{0}\"\n", ex.Message));
return;
}
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage("Successful loading.\n");
}
[CommandMethod("bush", "dunload", CommandFlags.Session)]
public void Unload()
{
if (dom == null)
{
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage("The domain isn't created yet! At first launch a command dload.\n");
return;
}
try
{
AppDomain.Unload(dom);
dom = null;
}
catch (System.Exception ex)
{
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage(string.Format("Excetion message: \"{0}\"\n", ex.Message));
return;
}
acad.DocumentManager.MdiActiveDocument.Editor.WriteMessage("Successful unloading.\n");
}
void LoadDll() {
Assembly asm = Assembly.LoadFrom(path);
}
}
}
When I load this code and I launch a command dload - I receive an exception:
Command: netload
Command: dload
Excetion message: "Type 'DomainUseSample.Class1' in assembly 'DomainUseSample,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as
serializable."
Ok, I mark class Class1 with attribute Serializable:
[Serializable]
public sealed class Class1
{
...
}
Now, when I load this code and I launch a command dload - I receive an other exception:
Command: netload
Command: dload
Excetion message: "Type is not resolved for member
'DomainUseSample.Class1,DomainUseSample, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'."
How correctly to load and unload .net-libraries in separate AppDomain by operation with AutoCAD?
Тему можно закрывать... Ключ к решению - обработка события AssemblyResolve.
Если кому интересно - ниже показываю черновик решения
Значит так, в xml-файл выношу настройки, в которых указываю абсолютные пути, где я хотел бы чтобы сборка искала dll-файлы (в том порядке, в котором указаны). Начинается поиск всегда с текущего каталога, потом в каталоге AutoCAD, ну и во всех остальных...
Файл Settings.xml:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <Settings>
3: <SearchPaths>
4: <Path>D:\MD\Visual Studio 2010\DomainUseSample\DomainUseSample\bin\Debug</Path>
5: <Path>D:\MD\Visual Studio 2010\CmdSample\CmdSample\bin\Debug</Path>
6: </SearchPaths>
7: </Settings>
Теперь код:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using acad = Autodesk.AutoCAD.ApplicationServices.Application;
6: using Autodesk.AutoCAD.ApplicationServices;
7: using Autodesk.AutoCAD.DatabaseServices;
8: using Autodesk.AutoCAD.EditorInput;
9: using Autodesk.AutoCAD.Runtime;
10: using System.Reflection;
11: using System.IO;
12: using System.Security.Policy;
13: using System.Security;
14: using System.Security.Permissions;
15: using System.Threading;
16: using System.Xml.Linq;
17: using Autodesk.AutoCAD.Interop;
18:
19: [assembly: CommandClass(typeof(DomainUseSample.Class1))]
20:
21: namespace DomainUseSample {
22: [Serializable]
23: public sealed class Class1 : MarshalByRefObject {
24: static AppDomain dom;
25: static Editor ed;
26:
27: /// <summary>
28: /// Создать дополнительный домен
29: /// </summary>
30: [CommandMethod("bush", "dload", CommandFlags.Session)]
31: public void MyNetload() {
32: ed = acad.DocumentManager.MdiActiveDocument.Editor;
33: if (dom != null) {
34: ed.WriteMessage("Домен уже существует.\n");
35: return;
36: }
37: AppDomain curDomain = Thread.GetDomain();
38:
39: curDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSomeFolder);
40: //С помощью закомментированного ниже кода можно указывать подкаталоги, где должны автоматически искаться ресурсы
41: //string config = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "App.config");
42: //curDomain.SetupInformation.PrivateBinPath = "CmdSample";
43: //curDomain.SetupInformation.ConfigurationFile = config;
44:
45: //Вывожу на консоль AutoCAD информацию о текущем (основном) домене
46: DomAsmsPrint(curDomain);
47:
48: AppDomainSetup aps = new AppDomainSetup();
49: aps.PrivateBinPath = "CmdSample";
50: //aps.ConfigurationFile = config;
51: aps.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
52:
53: dom = AppDomain.CreateDomain("D #2", null, aps);
54: dom.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
55: ed.WriteMessage(string.Format("Создан новый домен с именем \"{0}\"\n", dom.FriendlyName));
56:
57: //Вывожу на консоль AutoCAD информацию о дополнительном домене
58: DomAsmsPrint(dom);
59:
60: try {
61: //Загружаю в дополнительный домен новую сборку
62: dom.DoCallBack(() => Assembly.LoadFrom(@"D:\MD\Visual Studio 2010\CmdSample\CmdSample\bin\Debug\CmdSample.dll"));
63: }
64: catch (System.Exception ex) {
65: ed.WriteMessage(string.Format("Возникло исключение: \"{0}\"\n", ex.Message));
66: return;
67: }
68:
69: //Снова вывожу на консоль AutoCAD информацию об обоих доменах
70: ed.WriteMessage(string.Format("##################\nТеперь снова проверяю содержимое обоих доменов...\n##################\n",
71: dom.FriendlyName));
72: DomAsmsPrint(curDomain);
73: DomAsmsPrint(dom);
74:
75:
76:
77: ed.WriteMessage("Загрузка выполнена успешно.\n");
78: }
79:
80: /// <summary>
81: /// Вывести на консоль AutoCAD информацию о домене
82: /// </summary>
83: /// <param name="dom1"></param>
84: private static void DomAsmsPrint(AppDomain dom1) {
85: ed = acad.DocumentManager.MdiActiveDocument.Editor;
86: ed.WriteMessage(string.Format("Перечень сборок, загруженных в домен \"{0}\":\n", dom1.FriendlyName));
87: ed.WriteMessage("**************\n");
88: foreach (Assembly item in dom1.GetAssemblies()) {
89: ed.WriteMessage(string.Format("{0}\n", item.Location));
90: }
91: ed.WriteMessage("==============\n");
92: ed.WriteMessage(string.Format("Каталоги поиска, указанные в свойстве PrivateBinPath домена \"{0}\":\n", dom1.FriendlyName));
93: if (dom1.SetupInformation.PrivateBinPath != null && dom1.SetupInformation.PrivateBinPath.Trim() != string.Empty)
94: foreach (string item in dom1.SetupInformation.PrivateBinPath.Split(';')) {
95: ed.WriteMessage(string.Format("\t{0}\n", item));
96: }
97: ed.WriteMessage("**************\n");
98: }
99:
100: /// <summary>
101: /// Выгрузить дополнительный домен
102: /// </summary>
103: [CommandMethod("bush", "dunload", CommandFlags.Session)]
104: public void MyNetUnload() {
105: ed = acad.DocumentManager.MdiActiveDocument.Editor;
106: if (dom == null) {
107: ed.WriteMessage("Дополнительный домен ещё не создан! Сначала запустите команду dload.\n");
108: return;
109: }
110: try {
111: AppDomain.Unload(dom);
112: dom = null;
113: }
114: catch (System.Exception ex) {
115: ed.WriteMessage(string.Format("Сообщение об ошибке: \"{0}\"\n", ex.Message));
116: return;
117: }
118: ed.WriteMessage("Выгрузка метода прошла успешно.\n");
119: }
120:
121: /// <summary>
122: /// Найти и загрузить нужную сборку.
123: /// </summary>
124: /// <param name="sender">Отправитель</param>
125: /// <param name="args">Аргументы</param>
126: /// <returns>Возвращается загруженная сборка</returns>
127: Assembly LoadFromSomeFolder(object sender, ResolveEventArgs args) {
128: List<string> list = new List<string>();
129: list.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
130: list.Add(((AcadApplication)acad.AcadApplication).Path);
131: string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
132: XElement xml = XElement.Load(Path.Combine(folderPath, "Settings.xml"));
133:
134: foreach (XElement item in xml.Element("SearchPaths").Elements("Path")) {
135: list.Add(item.Value.Trim());
136: }
137:
138: foreach (string item in list) {
139: string parentPath = item;
140: string assemblyPath = Path.Combine(parentPath, args.Name.Split(',')[0].Trim() + ".dll");
141: if (File.Exists(assemblyPath)) {
142: Assembly assembly = Assembly.LoadFrom(assemblyPath);
143: return assembly;
144: }
145: }
146: throw new System.Exception("Не удалось найти файл сборки");
147: }
148: }
149: }
Результат работы кода (вывод на консоль AutoCAD):
Command: netload
Command: dload
Перечень сборок, загруженных в домен "DefaultDomain":
**************
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
C:\Program Files\AutoCAD 2009\AcdbMgd.dll
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\Program Files\AutoCAD 2009\AdWindowsWrapper.dll
C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.4027_x-ww_e6
9378d0\msvcm80.dll
C:\Program Files\AutoCAD 2009\AdWindows.dll
C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework\3.0.0.0__31bf3856ad364e35\Pre
sentationFramework.dll
C:\WINDOWS\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.d
ll
C:\WINDOWS\assembly\GAC_32\PresentationCore\3.0.0.0__31bf3856ad364e35\Presentati
onCore.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\Syst
em.Windows.Forms.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Dra
wing.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\Syst
em.Configuration.dll
C:\Program Files\AutoCAD 2009\acmgd.dll
C:\Program Files\AutoCAD 2009\AcRibbon.dll
C:\Program Files\AutoCAD 2009\en-US\AcRibbon.resources.dll
C:\Program Files\AutoCAD 2009\en-US\AdWindows.resources.dll
C:\Program Files\AutoCAD 2009\acmgdinternal.dll
C:\Program Files\AutoCAD 2009\AcWindows.dll
C:\Program Files\AutoCAD 2009\en-US\AcWindows.resources.dll
C:\Program Files\AutoCAD 2009\AcMrUi.dll
C:\Program Files\AutoCAD 2009\en-US\AcMrUi.resources.dll
C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework.Luna\3.0.0.0__31bf3856ad364e3
5\PresentationFramework.Luna.dll
C:\Program Files\AutoCAD 2009\AcMgdReverse.dll
C:\Program Files\AutoCAD 2009\AcLayer.dll
C:\Program Files\AutoCAD 2009\en-US\AcLayer.resources.dll
D:\MD\Visual Studio
2010\DomainUseSample\DomainUseSample\bin\Debug\DomainUseSample.dll
==============
Каталоги поиска, указанные в свойстве PrivateBinPath домена "DefaultDomain":
**************
Создан новый домен с именем "D #2"
Перечень сборок, загруженных в домен "D #2":
**************
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
D:\MD\Visual Studio
2010\DomainUseSample\DomainUseSample\bin\Debug\DomainUseSample.dll
==============
Каталоги поиска, указанные в свойстве PrivateBinPath домена "D #2":
CmdSample
**************
##################
Теперь снова проверяю содержимое обоих доменов...
##################
Перечень сборок, загруженных в домен "DefaultDomain":
**************
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
C:\Program Files\AutoCAD 2009\AcdbMgd.dll
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\Program Files\AutoCAD 2009\AdWindowsWrapper.dll
C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.4027_x-ww_e6
9378d0\msvcm80.dll
C:\Program Files\AutoCAD 2009\AdWindows.dll
C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework\3.0.0.0__31bf3856ad364e35\Pre
sentationFramework.dll
C:\WINDOWS\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.d
ll
C:\WINDOWS\assembly\GAC_32\PresentationCore\3.0.0.0__31bf3856ad364e35\Presentati
onCore.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\Syst
em.Windows.Forms.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Dra
wing.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\Syst
em.Configuration.dll
C:\Program Files\AutoCAD 2009\acmgd.dll
C:\Program Files\AutoCAD 2009\AcRibbon.dll
C:\Program Files\AutoCAD 2009\en-US\AcRibbon.resources.dll
C:\Program Files\AutoCAD 2009\en-US\AdWindows.resources.dll
C:\Program Files\AutoCAD 2009\acmgdinternal.dll
C:\Program Files\AutoCAD 2009\AcWindows.dll
C:\Program Files\AutoCAD 2009\en-US\AcWindows.resources.dll
C:\Program Files\AutoCAD 2009\AcMrUi.dll
C:\Program Files\AutoCAD 2009\en-US\AcMrUi.resources.dll
C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework.Luna\3.0.0.0__31bf3856ad364e3
5\PresentationFramework.Luna.dll
C:\Program Files\AutoCAD 2009\AcMgdReverse.dll
C:\Program Files\AutoCAD 2009\AcLayer.dll
C:\Program Files\AutoCAD 2009\en-US\AcLayer.resources.dll
D:\MD\Visual Studio
2010\DomainUseSample\DomainUseSample\bin\Debug\DomainUseSample.dll
C:\WINDOWS\assembly\GAC_MSIL\System.Xml.Linq\3.5.0.0__b77a5c561934e089\System.Xm
l.Linq.dll
C:\WINDOWS\assembly\GAC_MSIL\Autodesk.AutoCAD.Interop\17.2.0.0__eed84259d7cbf30b
\Autodesk.AutoCAD.Interop.dll
==============
Каталоги поиска, указанные в свойстве PrivateBinPath домена "DefaultDomain":
**************
Перечень сборок, загруженных в домен "D #2":
**************
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
D:\MD\Visual Studio
2010\DomainUseSample\DomainUseSample\bin\Debug\DomainUseSample.dll
D:\MD\Visual Studio 2010\CmdSample\CmdSample\bin\Debug\CmdSample.dll
==============
Каталоги поиска, указанные в свойстве PrivateBinPath домена "D #2":
CmdSample
**************
Загрузка выполнена успешно.
Command: dunload
Выгрузка метода прошла успешно.