利用C#進行AutoCAD的二次開發(二)
2024-07-21 02:19:57
供稿:網友
大家好,今天我繼續給各位介紹利用c#進行autocad的二次開發。在這一講中,主要介紹上一講例子中存在的問題。
在上一次的例子中我是通過引用autocad 2004 type library來進行c#與autocad之間的通信,但這種方法存在兩個致命的缺點。第一個缺點是每次調試程序的時候c#都要重新啟動autocad,如果調試的次數非常多(比如跟蹤錯誤然后調試),那么編程的效率就很低,因為啟動一次cad還是需要較長的時間。相對于第一個缺點,第二個缺點則更要命。由于.net本身的問題,interop.autocad.dll文件(就是通過它才實現了c#與autocad之間的通信)存在著一些bug,因此雖然有時你的代碼是完全正確的,但c#編譯器還是拋出莫名其妙的錯誤。那不是完蛋了嗎?我曾經有一階段就因為這兩個要命的東東差一點放棄了c#而想改學objectarx了,呵呵,不過還是運氣好,我偶爾一次在網上看了一篇外國人寫的文章,他專門介紹了這兩個問題的解決辦法。下面就來解決這兩個問題。
首先來看第二個難題,按以下步驟來進行:
1. 隨便用visual studio .net建立一個c#應用程序,然后按照上一篇文章中的設置加入autocad 2004 type library,然后不加入任何代碼,編譯你的程序。
2. 在visual studio .net命令行工具下用ildasm.exe(這個工具可以在visual studio .net安裝光盤中找到)把interop.autocad.dll文件(這個文件在步驟1中生成的項目的bin/release文件夾中)編譯成中間語言interop. autocad.il。注意:在步驟1中建立的項目的編譯設置為release模式。
ildasm.exe /source interop.autocad.dll /output=interop. autocad.il
又要注意了:把ildasm.exe,interop.autocad.dll放在同一目錄下。
3.在記事本中打開interop. autocad.il文件,然后查找結尾是“sinkhelper”而開頭為 ".class private auto ansi sealed _dacad“的語句,把語句中的private 改為public,然后保存interop. autocad.il文件。
4.使用ilasm.exe把interop. autocad.il文件編譯為interop.autocad.dll文件,同樣是在visual studio .net命令行工具下進行。
ilasm.exe /resource=interop.autocad.res /dll interop.autocad.il /output=interop. autocad.dll
interop.autocad.res文件是在步驟1中生成的。
5.顯然你不愿意每次編寫應用程序時都通過上一篇文章中介紹的方法來加入interop. autocad.dll,那太麻煩了。你可以用下面的方法來讓程序自動加入該文件:找到c:/program files/microsoft.net/ primary interop assemblies 文件夾,然后把上面生成的
interop.autocad.dll文件拷貝進去。
好了,第二個問題解決了,接下來看第一個。
在vba中,編程者可以使用getobject函數來獲得當前活動的autocad對象,但在c#中卻沒有,為了這個函數我幾乎把msdn給翻遍了,然后去各種c#論壇問各位高手,結果都沒得到解決,呵呵,可能國內使用c#的人比較少吧。還是在老外的論壇上看到了一篇就是講這個問題的文章才把這個難題給解決了。使用下面的語句就可以獲得當前活動的autocad對象了:
(acadapplication)marshal.getactiveobject("autocad.application.16")
(對于cad2000和cad2002,則把16改為15)
當然以上語句必須在autocad打開的情況下才能使用,否則會發生錯誤,對于autocad沒打開的情況,可以使用上一篇文章的方法來處理。完整的連接autocad與c#的源程序如下所示:
using system;
using autocad;
using system.runtime.interopservices;
namespace acadexample
{
public class autocadconnector : idisposable
{
private acadapplication _application;
private bool _initialized;
private bool _disposed;
public autocadconnector()
{
try
{
// upon creation, attempt to retrieve running instance
_application = (acadapplication)marshal.getactiveobject("autocad.application.16");
}
catch
{
try
{
// create an instance and set flag to indicate this
_application = new acadapplicationclass();
_initialized = true;
}
catch
{
throw;
}
}
}
// if the user doesn't call dispose, the
// garbage collector will upon destruction
~autocadconnector()
{
dispose(false);
}
public acadapplication application
{
get
{
// return our internal instance of autocad
return _application;
}
}
// this is the user-callable version of dispose.
// it calls our internal version and removes the
// object from the garbage collector's queue.
public void dispose()
{
dispose(true);
gc.suppressfinalize(this);
}
// this version of dispose gets called by our
// destructor.
protected virtual void dispose(bool disposing)
{
// if we created our autocad instance, call its
// quit method to avoid leaking memory.
if(!this._disposed && _initialized)
_application.quit();
_disposed = true;
}
}
}
利用visual studio.net 把上面的程序編譯成一個類庫,你就可以在以后的程序中使用它了,下面的這個例子說明了它的用法。(首先把acadexample類庫包含在項目中)
using system;
using acadexample;
using autocad;
namespace consoleapplication6
{
class class1
{
[stathread]
static void main(string[] args)
{
using (autocadconnector connector = new autocadconnector())
{
console.writeline(connector.application.activedocument.name);
}
console.readline();
}
}
}
這個例子是在c#窗口中顯示autocad中當前文檔的標題。