华南理工大学 刘林 麦智晖 阎汉生
' F X5 Q+ Q. ^4 U: y! s* @ R. o' X( U }
; l1 H! ~) d' f6 w5 M, W8 _本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。 ! G7 A$ u6 A- ?* D7 f V
- c: I* E2 W' x; M+ T E# H
: q' S9 M1 R1 ]; u% B! V0 c
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。/ Y4 Y$ ~& {9 s$ U5 ^
( Y5 k" |/ O' Z* U; O8 K.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。
" A) e. w! C) U7 J& ]3 O0 v% ^/ I U4 p
一、基于.NET的开发" C4 U( C( x/ H. A- b, N
( B# F& x$ G" S9 [& |; u8 t+ ^
1..NET API简介
- m- R+ C$ Z1 s! T: j3 `
8 a# a& X) R8 r f& @在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。 W, i- t0 u: H+ v* h2 _
$ N& Z9 x, ~+ ^1 j* x
2..NET API与传统ObjectARX的主要区别
1 ]+ d; u. E$ d) e' T3 V& E$ x$ D
.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。
. Y% o) u$ q$ ~+ v' S' H
' Z. o5 |7 l! w( ]; |; @1 Y3 \其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
5 j& B* t# L( w( o: d/ e0 f# x: T2 b7 f/ r- G$ E0 c8 W& `0 x
3.使用.NET API
5 K [; x8 D7 l: \# A+ C) u* Y0 G g
下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。& s/ y( ], X7 Q- |! m
& ?$ `* ]6 i5 [* E9 }2 w" P, X$ A
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:- p: s. d/ P# G! u9 A/ |
+ L; `6 }9 G5 e
using Autodesk.AutoCAD.ApplicationServices;
+ p/ n- W7 X2 v$ Z# ~using Autodesk.AutoCAD.DatabaseServices;
0 d7 ^+ r) }, B- ?3 E. S" ^using Autodesk.AutoCAD.Runtime; Y# w) ]# T2 e
using Autodesk.AutoCAD.Geometry;# k, A1 q: [ x' O$ d
8 X6 p! N( g! t/ ^ ]$ u
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:0 K, R7 O0 G" Q5 b* t/ x
% m8 G( t( Z9 p8 Y& U: X[CommandMethod ("AddLine")]
' v0 M" P0 d5 R5 |, Hpublic static void AddLineCmd()" p; v; H8 P3 ]7 P8 }
{
8 Q$ l1 H0 A. DDatabase db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库& b, O; C" M" X6 [7 J$ ]
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
9 ~8 i! c6 b6 E* NBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录1 Z; u6 o8 `4 i# f5 z
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线6 N+ g8 R9 y0 I* y
try {
" ^5 g/ s, u* W$ fbtr.AppendEntity(line);//将直线添加到模型空间中
2 g4 T" Y) H0 i) v4 `3 \line.Close();//关闭该直线
" E& O. D9 d1 J1 {$ B# e) O}
: H) x4 O7 B+ L+ l! [( u( Cfinally {
: i" B$ U/ `, E/ C( Rbtr.Close();//关闭块表记录9 M, A; Q' j& d, W1 T
bt.Close();//关闭块表) ?5 t6 \1 \& M2 O3 ^, {7 A( K
}
9 f+ Q0 \- b, q4 N. Q$ F} y0 f( m3 \! [" C- L6 ^( |9 `, T; r4 a
/ b0 Y) J) ]2 U9 H; }3 E; Q
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。! B9 i. I$ P# z* [: u5 g* n* J. r
q$ K, \+ d9 Y( ]# e
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
) @: U( e5 q% v& O, O' _! g1 v0 Z! ~. s% o R* `
4..NET API的初始化与清除
* q f1 P1 y9 s& B/ h0 q; [, N* N: Y0 o
在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现6 Z% ]% o2 k) `8 m+ q l4 e5 B0 l
) m2 u4 L5 D! y+ [+ _3 j- _IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
4 z3 p! z! C. u2 E# X5 L
6 Z5 {8 W0 v, B0 u" f' n( H4 Qnamespace ARXExample {( m6 k' o' ^/ D0 f9 a; q& x
public class MyARX : IExtensionApplication {( f: A& I, \/ ]. _$ y. @
……
+ ~+ [. V% W. N7 W6 a! Ypublic void Initialize() {1 }+ X# w4 A# ]% e, D
//初始化操作3 u1 P4 {: N" d9 ]! o8 Q5 _
}
. N$ R9 ^, b9 l" wpublic void Terminate() {# |5 _" E3 A+ z6 e/ q3 n
//清除操作% W! a5 ^8 x' _. K+ y1 j
}
7 d+ V& H% ~& M" B* D7 b……" _ S4 c5 s% F: o6 r a/ a
}* f( w& p& o! u! l
}8 z* W- o! G: L8 s5 n9 W- n0 A
: z& Q0 t. N2 m4 f. A, Q同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:8 H7 |0 s6 K5 S1 B
5 L3 h1 I; a3 |0 s+ _0 L; i9 R[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]7 [. n1 x* x# \$ F5 c5 m
[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]& S$ d+ c* G# X5 C X/ p
6 @* J# P. w9 v+ s" ~" ~% X这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
, }+ H: }9 E- w* {4 w; n a4 e V, K H$ K
5..NET API与COM交互操作; K, I4 N' y" i' A3 m5 C `; j, _' Q
7 W* b" `: [0 a- E* R% g# U& {; C
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。 C: [' r% Z; Y; l- z' Y5 R: C2 g
# V& J7 y: n% i% R. z, p
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:/ ^+ K4 n. s2 Y1 T* \
# T/ v% u: o6 F3 i# I* i, V
Database db = HostApplicationServices.WorkingDatabase;8 A/ y! n, {6 F; r& [5 z% I
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);
/ |0 W# P% A! ]) @BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);" |6 C+ L- I" J
try {
6 K9 M) c' {0 @8 T) P. DAcadObject obj;
' E( S& F( W7 `0 T/ D; m//遍历块表记录9 H. M0 W, ~) d& O4 E. Z: T
foreach (ObjectId objId in btr) {
$ O0 S! Z( M7 R//由ObjectId得到ActiveX中的AcadObject对象& b) S$ Q- A1 c( O+ E0 T1 m
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);
' P5 h. }6 n9 m; H//为obj添加响应Modified事件, o7 t- E: B" |
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified); J7 Z4 P8 Q+ @( Z; a" j5 Z
}
5 r; k) Y- K. t( w% U}2 a& h" V* Y, h! @3 \$ D% L
finally {
1 R3 o) q1 _" b5 V& dbtr.Close();8 J R& y6 T- U- o& f
bt.Close();
) o- B/ B7 \/ i: o# b0 M}6 q8 K# D2 A+ Z/ o6 W8 k) u
1 C# C5 R' E! s% w) g. \/ }' b
其中事件响应函数obj_Modified的表示如下所示:# D. g3 x4 A7 ~, Z2 d
6 r" N9 w" q% r0 Upublic static void obj_Modified(AcadObject obj) {2 V1 k! D/ o" {/ z) ?' X
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");5 I8 O3 }5 s) a: Z
}
9 t5 \6 z5 I+ m$ F9 Z2 s9 t& [: F' Y' y& x( H" \
二、结论
4 l, @7 y! X) {0 _) L' W2 B- H' H+ l! W
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |