华南理工大学 刘林 麦智晖 阎汉生
$ K3 u O9 F/ S! ]) q# R9 s+ l( c: K
4 B2 n# X) A7 a4 \5 B; W本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。 & U7 [$ F7 b& b; D# e3 V
, B, W/ m7 h7 B; _
' H- D3 J$ f* T' P% w
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。
3 ?. ^% |9 I" I/ V! ?7 Y8 E4 O
1 Z1 e$ {9 v9 g7 a! {7 J* H) a.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。
3 K6 q4 c- I- d1 B7 j w2 ?% ^$ A. F3 B' |. x
一、基于.NET的开发
' W( t- Y4 z7 [) E/ ]6 x% @$ z* ?( l
1..NET API简介
: V# _/ Z/ ?& ]- P- S3 K8 _( P& H, G5 g
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
' ?# d+ j9 R/ N: {6 ?) J1 I) T9 Z/ j/ u. Y5 L& S& d! @
2..NET API与传统ObjectARX的主要区别
" b0 l' e: w+ N9 C& Z/ \; z% c, a7 j* c$ N' w
.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。
4 W) {& A+ e/ b
F3 X( @, P$ ?4 q其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。3 J! `) c) w) N" A3 Y! ~
- u: y: _. [8 {$ j- F( ?1 K3.使用.NET API2 J& ~9 H- F1 n! r4 U/ q
1 I+ j- q6 l+ k: r- E W$ t4 a) E下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
4 M- V2 d3 M6 x: c/ Y
6 u5 E% z8 h1 b/ z) A0 n+ z然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
! C. o- b- [2 \' z8 N9 W! v
' ]8 d3 E3 m, `4 e# xusing Autodesk.AutoCAD.ApplicationServices;0 c' o) Z# C; S- l2 C. D
using Autodesk.AutoCAD.DatabaseServices;
4 x* F$ _0 d4 D, ~' |* ausing Autodesk.AutoCAD.Runtime;- ]* d3 g# W, @* T) A( |
using Autodesk.AutoCAD.Geometry;
* |/ d9 l3 q# B! ? i; D4 U0 s* _# K- }" m9 B( l
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:( _: y, l) ^2 I- Q
/ i* m7 L {4 r' f[CommandMethod ("AddLine")]% M" b- w2 _6 _/ S4 u2 @8 e
public static void AddLineCmd()
" }8 f5 X' \, d. A0 e: s# S9 z$ O{
& k5 x: ~/ _* ODatabase db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
; u: t2 X) U( ]2 z6 k' \1 v% gBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
, S3 V; }; O0 L4 \2 r+ D% t9 u6 {% _9 BBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录& h- z& R3 {1 t8 p5 s, x( R0 d
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线$ g$ x1 f/ a6 W* R* c$ n
try {+ E' _( F% `6 `3 k# f
btr.AppendEntity(line);//将直线添加到模型空间中5 j. q3 o: g2 i1 C% F
line.Close();//关闭该直线; J# _3 a; y: e- a+ K8 @- O. M `
}
9 b1 ~7 f+ b! @$ ?. m, K. ~finally {5 x$ H' K: {8 t& v4 x6 \
btr.Close();//关闭块表记录
6 u+ Y- e) K# W$ `bt.Close();//关闭块表
" Z& q$ j N- m% Y4 h}
# K% U1 ^# e2 x1 n7 ^}( B; A3 E- }- Y
7 x+ Y4 ?0 N4 x2 L) T$ p" z
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
4 ~1 c8 j8 X" i; }& g* I& d& O5 f% R( x" ~
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。% c% b F. I3 N8 C+ e" h
7 t7 h, d$ w0 s2 _- n) w' K0 @
4..NET API的初始化与清除
% r6 p, e% P/ g2 r. H/ I6 _1 m) [: X3 j) g/ D
在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现- ?! A# r. |; l! i
9 L2 m5 O/ R* j1 ?6 }5 rIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:. _3 I8 o4 m+ T& `8 z; a
9 f1 J5 B& s* {4 X, tnamespace ARXExample {
! K4 c' W8 X, ppublic class MyARX : IExtensionApplication {$ U% M! t% V- a4 R2 |
……) w d& \( Z6 q3 i6 Z& s. L
public void Initialize() {
1 `& C3 {$ [% h//初始化操作
7 W0 T6 X+ Y9 u1 ~+ i}
" P. h, j! o7 e0 K: ]public void Terminate() {; q: Z& K8 s+ g: N& U
//清除操作* K, u4 k" g+ b, @/ w
}
* f! C0 H% X# O/ g# k……
- O- n) U; I7 q}5 M$ C5 n5 w, j& h5 h
}* ]2 Y9 w" q5 r& T
* I5 N% M. g9 N
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:2 Q" V) X I) m, P/ b
# S4 Q \2 \% K; n j& _, ~[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]$ R9 K* q7 h7 c5 _5 R/ D
[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]; {: d2 a; J" \; F6 |/ N
|5 o) t3 }! O6 x$ m这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
2 e, F& B* H# r Y! X o% ~' O$ {+ @1 r: d2 I2 n
5..NET API与COM交互操作& e7 v+ p" e; v% f8 D% p2 ~# T! g
4 X4 F0 i& ~; Q& c+ n; A6 G7 ~
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。" C$ l2 k# S/ L- u% K5 O: o+ m$ x P
# ]$ f4 w! ]/ M# i& f% u6 Q7 I0 |2 d
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
0 i5 Q& K+ u* q/ t7 N! r3 ~9 ~& v' |
Database db = HostApplicationServices.WorkingDatabase;
5 s3 ]6 |2 }6 L5 y( o, I- g, yBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);8 e# a5 P# ~! ^, b
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
; `$ `7 ?* x, `. G0 stry {
9 d3 V9 r! t5 G& Y- g* RAcadObject obj;
4 I( u/ f6 U' A5 E//遍历块表记录( V. J, j4 c0 F5 N
foreach (ObjectId objId in btr) {
1 l( N5 @" p9 ^* `$ v2 V: H/ j//由ObjectId得到ActiveX中的AcadObject对象
6 U9 S: d5 e: m, c4 _: xobj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);. v$ P5 q! z- [* q' Y p
//为obj添加响应Modified事件- j( b" q! B) Z/ v5 g* X
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
, L& m/ F! M3 u}6 g6 v- o; b, Y/ ^/ w
}
$ B6 A, D& I8 d) _8 X' v! N7 _finally {2 d0 l( t8 P2 ^, S( l$ @( s
btr.Close();
+ a+ c% n# C9 v; \, ]2 h# u7 w R! Tbt.Close();4 Q) ]/ G9 L M U! B7 M+ ^$ y2 h
}2 _" v& N) O! ^5 w" d. \; ?4 X! k
9 H: ~0 ^+ c- C8 \3 y其中事件响应函数obj_Modified的表示如下所示:
+ Z2 K$ s* s" T5 i8 i! }, L/ ~- L
# w: y) h0 H/ M$ `0 \% spublic static void obj_Modified(AcadObject obj) {3 w) y4 \0 K3 P& R) y P6 ]
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");7 F2 m: W+ n2 x N$ K: k
}
1 S2 |0 x; i- {6 \ m4 V; @2 U. w' v1 f( F! q: {
二、结论- @) y j- z4 n4 c& N
, {, W7 S6 i8 B/ q本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |