本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。: f4 U4 g7 t2 r' p, G0 P+ e- R5 E
: ^$ \3 c: G6 l3 s" T
( d+ m5 F0 d: d3 I% q" o
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C 的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。
+ h4 a& H5 D1 P* m% s. u5 [
! P, A6 h- N5 X* Y* [9 T.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。, p% ~9 I0 [# i( _0 ]: D
: [" Y) {. J! U0 ~一、基于.NET的开发
L' V4 `8 _* O% V2 C
0 E. }2 [1 Q/ V) X1 l7 u. L% J1..NET API简介' r5 t6 H* r4 z0 S0 E
- h2 y4 f# D5 z$ I6 x: N( U5 G+ c
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C 等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C 相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。" J& \- P7 p( e4 k' n% \* U
+ G* p$ h9 D! E
2..NET API与传统ObjectARX的主要区别
2 p7 p7 e7 v9 E, _, j& x+ |
8 i6 e5 C( c9 ]% M; F8 r Z$ A.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C 程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C 环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。6 n' ]( V% V' G
2 Q3 s9 h, y- }
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
& h; @' `0 N5 |+ A* ^! v# U
8 ^2 C$ ~& C& [$ }( ^) k3.使用.NET API3 i' n2 n, d3 s% j ]- R0 u
: a6 y% {8 D% _# ~) I
下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。7 U" O5 L/ B3 w8 x, Q
9 k% f# K: T" _3 P% V! D
. a8 ^% e3 R# C# O
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
0 p I4 L& q n0 v, u( q! x! q
) N+ d& j- u3 z( D7 `using Autodesk.AutoCAD.ApplicationServices;$ M7 ]% N) S9 q W& t' J" G3 |
using Autodesk.AutoCAD.DatabaseServices;- I# Z3 A2 G/ N- m+ ^3 c
using Autodesk.AutoCAD.Runtime;
9 h, P% k% K* K6 Nusing Autodesk.AutoCAD.Geometry;
: M4 M' h: d9 V- i7 _9 V# I5 f- B) [. H1 R
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:7 V9 V% M% f4 H& t. s4 c! E
) b, ?( l. a4 S4 I5 }
[CommandMethod ("AddLine")]1 x9 k. C$ v B, E# x% L( X0 |4 |
public static void AddLineCmd()
1 X" t7 p5 j; z0 g6 p) ?{; E" o2 J6 {7 r9 w6 h- ?
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
7 x3 E* d. Q h( E5 pBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
' @: Y" z; q3 M1 a5 DBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录' ^0 B- R7 k! O% I2 Y, V: O
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线7 X+ U* F! j! ]3 I2 s/ c L
try {: k! O: \; R6 z
btr.AppendEntity(line);//将直线添加到模型空间中
2 j& I* t/ e1 h X! B4 H, Dline.Close();//关闭该直线
* v9 _% a2 O" [}
5 d! p- D+ }5 K! `# X9 }finally {& a' o% C% p8 S! G/ O. ]
btr.Close();//关闭块表记录1 ^5 _% O- ?8 i, d5 J% s
bt.Close();//关闭块表 f T @+ L8 g8 X) u% V
}* \8 L, k' T, W$ C. l
}
v% l5 {8 E6 P% k% [7 e+ J- |$ {/ x2 n
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。5 U, _/ a4 \, z7 `* w! i$ W
+ A7 d3 o. \( j' S5 i4 J4 k写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
/ u- p9 H! P$ T
) z2 o" k$ V9 @6 k! c/ I: ]8 k" U5 a4..NET API的初始化与清除
% R+ M; C5 [+ z$ y
% W$ A1 y5 d8 [+ F: V2 C在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现% ]% n9 z3 ]+ z& x8 `
IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
: x* z2 F8 u o* T1 m
j& l! [, Q: S2 u! Z7 F# E( v, q) jnamespace ARXExample {4 u2 X9 ]& V. o. T* `) {
public class MyARX : IExtensionApplication {
0 ]: B1 r$ g# ?) i" K* C……
6 W/ J! z/ \: r. m5 s! B6 qpublic void Initialize() {
% p, R% [; `/ g* _//初始化操作5 A" m6 I; x7 }5 G
}
/ C' F# f7 i6 T* F* bpublic void Terminate() {
/ g+ A7 @5 a- y9 L
5 M: A5 F" [! t//清除操作
3 w6 c. D2 V8 h2 e}) l% n3 S+ J6 f5 x" n
…… t! [. W% W. b2 }
}2 [7 V/ m; |- [; f2 P2 O
}, `. v) q$ `% k: L7 y1 c6 s1 @% L
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
H9 E4 n6 v3 K z( c, m[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]' R! N4 M. o- D" X# T
[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
& _" V, x5 M1 l: Y1 p, v: u8 u, C. Q
这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
. w. B" u' ?1 q u& Z2 G# C: h0 L# J2 n0 s8 o& Q5 ]
5..NET API与COM交互操作5 Y8 W1 x% e5 n) s+ V; u
! O B/ ?# E% U# b z在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
0 \" s; e ]) n1 b9 _增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:8 R* B2 Z2 u. g+ Q
6 b" Z8 v' ^& MDatabase db = HostApplicationServices.WorkingDatabase;$ I, |# G2 u- ?6 P5 L( [
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);2 j. O6 Q9 @8 Y$ m, q- T: m3 k
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);/ U$ e4 |- B2 Y
try {
# V; t( ?3 J/ w6 `" oAcadObject obj;
3 t) H1 D- x+ j' e0 n3 o1 P' x" Y//遍历块表记录: T* c3 ^, f$ \! N" S
foreach (ObjectId objId in btr) {* B( C- b- `$ l$ Q: d* k$ X( l
//由ObjectId得到ActiveX中的AcadObject对象
; Z% T) q4 F3 B8 M. U' B% Pobj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);
7 b( V' G; R# ^//为obj添加响应Modified事件
- V# |" D. _9 V& [4 B/ Kobj.Modified = new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);- Y, r" H r' Q F3 H
}
6 f5 b1 u U4 q/ n0 \7 b6 B. x0 T}
9 T _. q" m) O" f& |/ tfinally {
" S% V7 G6 Y( x# q6 y. d# U, ?btr.Close();
3 |2 N, S3 }; ^1 u0 v4 x, S$ a2 sbt.Close();
% ^) D8 A: [8 U9 i& S* l( \}( j/ Z- t; `7 r7 Z' x/ w
其中事件响应函数obj_Modified的表示如下所示:
& ?( Z; Z7 o4 H; W, Bpublic static void obj_Modified(AcadObject obj) {
. `5 Y4 B/ E! @7 A# S$ [CommandLinePrompts.Message("object modified!" obj.ObjectID "\n");# Q' H* Q: F* ~+ B9 N1 |
}
! `8 ?/ u" ]$ |6 ^/ w
$ y1 o5 r; m8 V二、结论: G5 X5 @) K+ r: w1 b, ?) w
. z- J! \, @# W本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C 的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |