眾所周知,對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();
}
}
}
好了,今天就到這里。