华南理工大学 刘林 麦智晖 阎汉生% o; C- |2 ^" ~& I) s
! }4 y& T9 H1 u
1 w6 R! d0 ^" m- L% \% ^
本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
! m+ _. P W& `( o7 E
; p% J! H6 {' U. b: }, `! F. J1 \) q9 a4 `6 w
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。
' d& O# C! u0 o- }# J2 g& v
4 O i- Q; Y+ P4 l' k1 B6 C+ `/ Z.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。) J6 f) g9 }4 k: J2 H
+ a$ M" I/ O# K& [
一、基于.NET的开发4 E, i8 B5 S& N3 `$ E
* h) u5 Y* ^1 g0 G3 y9 O3 \5 ]1..NET API简介
% i) q0 L- `8 R) e: g( `% f7 b4 n; r, d' D; y" E; s! n
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。( s$ `2 x* B2 a
' m b7 x, _. D* H* r# |' s$ i4 U" O
2..NET API与传统ObjectARX的主要区别
- u: [& n. _5 @) V4 L* G2 B, I
Y. g+ g0 U. x) a# v2 i.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。, B- a: G5 a( l0 h8 c
V; j5 f3 h( v( K' v# {* Z3 ?
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。# o' O6 v+ B$ G- h/ p6 M5 g
; t( [7 ?" n% C0 {/ W! @
3.使用.NET API
- B9 a; F& }' l: M' b1 _, P6 y7 B7 M- ?4 `7 T- t4 B
下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
8 ~( }* P, X7 A" ^! k! r: |8 `) v& v, t
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
0 l" [* H. J# G
' ]$ F3 M& M" }+ P9 y1 l0 Gusing Autodesk.AutoCAD.ApplicationServices;
! }7 m1 L& O7 I$ M* l4 y6 Xusing Autodesk.AutoCAD.DatabaseServices;. S: D- K* Z; l3 I9 f( Y! r
using Autodesk.AutoCAD.Runtime;2 |6 u( l- C0 O9 D" H
using Autodesk.AutoCAD.Geometry;2 q: g( a) ]7 N1 k. D0 ^: R- J
( _, i6 S9 n3 }( q, {这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:# n( J* I3 a* o& V8 L# H% c+ D
2 n1 g8 X; D3 {9 L
[CommandMethod ("AddLine")]
: e3 l9 A3 |* F# W0 Kpublic static void AddLineCmd()3 p5 Z7 Y/ k$ Y. i1 o( d4 m
{
$ M& R$ j- F: J7 d2 U0 }Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
1 |( G$ [) z( X' i9 E5 GBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表7 c! X; V4 W7 h
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录$ E( J- ]1 @) W* z
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
" a3 l6 Y: ~" ltry {- z# L" F9 u* ^& Y8 V. |
btr.AppendEntity(line);//将直线添加到模型空间中
- F) \$ N& @( J, t& ~ M! Dline.Close();//关闭该直线) F9 K6 X0 K9 ~8 R* ~- b
}
2 Q r# l: O/ i: f9 H2 v1 pfinally {
, z) x1 D- C3 E- h$ X9 nbtr.Close();//关闭块表记录
& W& C2 Q, f1 a6 F( Q4 G+ g8 pbt.Close();//关闭块表
* r1 T! U. e0 W/ y( ~" C}$ O+ _! N- [5 R4 s( u( {
}4 w" Q% E! ?3 [0 h1 {% }
% h ?5 e3 U; c% e6 U由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
- M% S7 N2 N- ?9 a/ N& l+ I t) i: q( }% t' {
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。* p5 ~, L# w6 @$ O# z9 A9 f0 V$ G! R
3 c/ c" C' \* m: Q4..NET API的初始化与清除
" y* _; {: f! w5 s4 C3 x9 p. }0 m2 s* V+ f2 o9 @: _# |
在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
6 D& Q1 U# O# p- a: _; g: m, L$ V9 |( m- ~2 C
IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:$ ~3 J7 Q, P* p0 E! L
u, n+ c5 Y8 i4 n' Q+ L
namespace ARXExample {
. m0 O* ~: l3 N) N2 Bpublic class MyARX : IExtensionApplication {2 Q* _8 {0 {( h$ b
……/ [& O( A- [: Z, ~: K' X; w. g
public void Initialize() {
8 U6 E7 k. i% D! F//初始化操作8 N$ I! |! W: ?" y! [
}
/ \/ f: g8 e/ M( e" q2 dpublic void Terminate() {' Z# m9 k/ F$ m( h* \
//清除操作- e# O8 I2 Y$ n% C! x6 I/ V
}
' J9 S, |2 s( T2 v. I6 A8 q……
; ^, q4 K" n% d% a' b. w2 \' Z+ i9 h# L}
& f0 e$ B+ f, a}5 k! v( q5 r1 ]) ^! ~: N7 m
. e0 l' t0 W4 U- ]; D5 P; D4 n6 a
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
$ g, s$ a! q/ F q( L" m: b* d$ }: y( W8 T3 }
[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
/ p4 M* l* b$ a$ L! G& G4 d. C7 k[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]+ n7 x) }! [* f. [6 Y
% D2 V) r9 U$ C, q" i2 R
这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
" T! U e/ }4 h/ y& U6 w, }: {) ^# R- w; V
5..NET API与COM交互操作
+ [3 L5 R) {# g% P' S
$ Z/ f% P6 e7 N7 g; n5 i在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
$ T9 e- ?( }2 W0 B- U. H6 [" L( W) g& f4 l* |0 n e! A8 m/ F
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
, I/ ]7 l8 H: H k7 o$ b( k4 F3 ^& Q, _" \
Database db = HostApplicationServices.WorkingDatabase;
8 ]1 J2 U5 @- a2 cBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);) M: r A( m$ p' r4 N+ _
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
7 p0 v- G9 _ {2 f' E- @: P% etry {
w; s a. L8 R( u. O" z1 cAcadObject obj;
8 q% n: t7 I; u7 R//遍历块表记录
9 f+ j$ r7 g6 i, zforeach (ObjectId objId in btr) {/ W) D; |' }$ E, T+ W4 i
//由ObjectId得到ActiveX中的AcadObject对象9 `* @; T1 B6 t7 X" P/ G
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);4 Q y( ~# z, N- O( ?3 x
//为obj添加响应Modified事件
/ ~8 r4 | n, p9 |: Kobj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
: {" H" Y4 r9 l}/ m( e1 G2 r6 m: z9 F
}8 }. ] s3 `; I9 p) b
finally { a# \1 @/ I8 n$ h- I
btr.Close();+ n+ Y" Y N: X
bt.Close();- ?8 d0 O! h4 r6 _$ o$ U+ b g
}0 i+ h8 C& ]; b- T6 F- I
p% t, f+ P* B/ o) ]其中事件响应函数obj_Modified的表示如下所示:
" @& r2 X- \+ I+ u8 q' ~/ o. h* V7 p7 A& D! d1 e( z7 o
public static void obj_Modified(AcadObject obj) {- q% T8 A& C x8 k
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");1 [# M* W; l; z. R9 d, R/ Y* j( }
}
% P& R) d( l" b$ T1 f2 i: c/ M+ B0 ]) B! S2 d
二、结论6 o1 w( }. t. C4 b
1 J# ]6 }" N$ I% z本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |