標籤:
眾所周知,對AutoCAD進行二次開發用到的主要工具有:ObjectArx,VBA,VLisp。但它們的優缺點是顯而易見的:ObjectArx功能強大,編程效率高,但它的缺點是編程者必須掌握VC++,而這門語言非常的難學;VBA和VLisp雖然簡單易上手,但它們對於開發大型的程式好象無能為力。那究竟有沒有一種語言能結合它們的優點而盡量避免它們的缺點呢? 回答是肯定的,那就是微軟新推出的21世紀程式設計語言C#。關於C#的詳細介紹,大家可以參考有關的文章。
C#是通過AutoCAD ActiveX 這座橋樑來和AutoCAD之間進行通訊的。AutoCAD ActiveX 使使用者能夠從 AutoCAD 的內部或外部以編程方式來操作 AutoCAD。它是通過將 AutoCAD 對象顯示到“外部世界”來做到這一點的。一旦這些對象被顯示,許多不同的程式設計語言和環境就可以訪問它們。關於AutoCAD ActiveX 的情況,大家可以參考AutoCAD內建的協助。
呵呵,說了這麼多無聊的,還是讓我們通過一個具體的例子來說明怎樣利用C#進行AutoCAD的二次開發吧。在介紹例子之前先講一下有關的配置:
(1)Visual Studio .net (2003和2002都可以,我用的是2002)
(2)AutoCAD2000以上版本(我用的是2004)
這個例子非常簡單,就是通過C#建立的表單來啟動AutoCAD並畫一條直線。下面是編程的具體步驟:
(1)通過Visual Studio .net 建立一C#的windows應用程式。
(2)在“方案總管”中右擊“引用”標籤,在彈出的菜單中選擇“添加引用”,在“添加引用”對話方塊中選擇“com"選項卡下的下拉式清單方塊中的“AutoCAD 2004 Type Library"項(注意:不同版本的CAD的數字不同),單擊右邊的“選擇”按鈕,最後單擊下面的“確定”按鈕。
(3)在C#表單中加入兩個文字框和一個按鈕,分別用於輸入直線起點、終點的座標和在CAD中畫直線。下面主要解釋一下添加的代碼。
(a)在程式的開頭加入:using AutoCAD;//匯入AutoCAD引用空間
(b)在表單的變數聲明部分加入: private AcadApplication a;//聲明AutoCAD對象
(c)在表單的建構函式部分加入:a=new AcadApplicationClass();//建立AutoCAD對象
a.Visible=true;//使AutoCAD可見
(d)在按鈕的訊息處理函數中加入:
double[] startPoint=new double[3]; //聲明直線起點座標
double[] endPoint=new double[3];//聲明直線終點座標
string[] str=textBox1.Text.Split(‘,‘);//取出直線起點座標輸入文字框的值,文字框的輸入模式為"x,y,z"
for(int i=0;i<3;i++)
startPoint[i]=Convert.ToDouble(str[i]);//將str數組轉為double型
str=textBox2.Text.Split(‘,‘);//取出直線終點座標輸入文字框的值
for(int i=0;i<3;i++)
endPoint[i]=Convert.ToDouble(str[i]);
a.ActiveDocument.ModelSpace.AddLine(startPoint,endPoint);//在AutoCAD中畫直線
a.Application.Update();//更新顯示
好了,簡單吧,你可以試著編譯一下。關於上面一些語句的用法,我會在下一講中作詳細介紹。
大家好,今天我繼續給各位介紹利用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中產生的項目的BinRelease檔案夾中)編譯成中繼語言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 FilesMicrosoft.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中當前文檔的標題。
這一講的主要內容是介紹AutoCAD物件模型,如果你對VBA開發AutoCAD瞭解的話,這部分內容應該是超簡單的。
對象是 AutoCAD ActiveX 介面的主要構造塊,每一個顯示的對象均精確代表一個 AutoCAD 組件。AutoCAD ActiveX 介面的主要對象有:
• 直線、圓弧、文字和標註等繪圖物件。
• 線型與標註樣式等樣式設定對象
• 圖層、編組和塊等組織圖對象
• 視圖與視口等圖形顯示對象。
• 圖形、AutoCAD 應用程式本身也是對象
所有對象的根對象是AutoCAD 應用程式本身,它用AcadApplication類來表示。獲得當前啟動並執行AcadApplication對象可以使用上一講中介紹的方法來得到。AcadApplication對象下有四個子物件構成,分別是:
? AcadPreferences 對象,通過此對象可以訪問和設定“選項”對話方塊中的相關選項
? AcadDocuments對象,它表示AutoCAD 圖形
? AcadMenuBar 對象,它表示AutoCAD主功能表列 (注意不是AcadMenuBars,因為應用程式只有一個主功能表列)
? AcadMenuGroups對象, 它表示AutoCAD 菜單和工具列
上面介紹了AutoCAD ActiveX 介面物件模型的大致組成,下面重點介紹AcadDocuments對象,因為大部分的編程都與它有關。首先大家看到它是複數的形式,因此它是當前開啟的AutoCAD所有圖形的集合,這種對象稱為集合對象(呵呵,好像在講廢話)。集合對象有一些比較重要的方法和特性。其中最主要的是:Count特性用於擷取集合中的對象個數(從零開始);Item 方法用於擷取集合中的任何對象。關於它們的用法我會在下面的例子中介紹。而 AcadDocuments的單數形式AcadDocument表示當前開啟的一個AutoCAD圖形。AcadDocument對象由以下幾個主要對象組成:
? AcadModelSpace 集合和 AcadPaperSpace集合,提供對繪圖物件(直線、圓、等)的訪問
? AcadLayers、AcadLinetypes 和 AcadTextStyles,則提供對非繪圖物件(圖層、線型、文本樣式等)的訪問
? AcadPlot 對象提供對“列印”對話方塊中設定的訪問,並為應用過程提供了列印圖形的各種方法
? AcadUtility 對象提供使用者輸入和轉換函式
繪圖物件的建立使用Add方法,比如要建立一個圓,就是用AddCircle方法,而非繪圖物件的建立使用Add方法。
下面通過一個簡單的例子來說明上面介紹的內容。這個例子是在AutoCAD中建立一個新的層,然後在該層中畫一個紅色的圓和一條綠色的直線。這是程式的原始碼:(請先把上一講中產生的interop.AutoCAD.dll 和 AutoCADExample.dll檔案包含在工程中)
using System;
using AcadExample;
using AutoCAD;
namespace CircleLine
{
///
/// Class1 的摘要說明。
///
class Class1
{
///
/// 應用程式的主進入點。
///
[STAThread]
static void Main(string[] args)
{
//
// TODO: 在此處添加代碼以啟動應用程式
//
using(AutoCADConnector connector=new AutoCADConnector()) //串連AutoCAD
{
AcadDocument aDocument=connector.Application.ActiveDocument;
//取得當前AutoCAD活動圖表形對象
double[] center=new Double[3]{20,20,0};//設定圓心
double radius=20;//設定圓的半徑
double[] startPoint=new Double[3]{0,0,0};//設定直線的起點
double[] endPoint=new Double[3]{40,40,0};//設定直線的終點
AcadLayer newLayer=aDocument.Layers.Add("CircleLine");
//建立一個名為CircleLine的新層
aDocument.ActiveLayer=newLayer;//把CircleLine層設定為當前層
AcadCircle circle=aDocument.ModelSpace.AddCircle(center,radius);//加入圓
AcadLine line=aDocument.ModelSpace.AddLine(startPoint,endPoint);//加入直線
circle.color=ACAD_COLOR.acRed;//把圓變為紅色
line.color=ACAD_COLOR.acGreen;//把直線變為綠色
connector.Application.Update();//更新顯示
for(int i=0;i Console.WriteLine("這是第{0}個對象:{1}",i+1,aDocument.ModelSpace.Item(i)); //遍曆當前圖形
}
Console.ReadLine();
}
}
}
好了,今天就到這裡。
利用C#進行AUTOCAD的二次開發