本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
! F8 `5 j) H, W* ?! D3 y' R0 P. ~( I# b; V! d7 l4 l
, c+ Z# [( v. J9 o当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C 的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。( t5 `/ H! v3 u- O
6 r7 [( l+ b9 C% V7 d, c9 T; p6 G: l.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。
- u. ?' B; g5 J" P: p2 z. b
: m( v4 m; \ C# s8 h1 S一、基于.NET的开发% Y1 w7 i6 ], i7 t1 }; i4 l
. s1 I) u. d7 }+ [1..NET API简介' {' G3 |, }( e, P
6 ]. \# |1 @" l, H( p1 |
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C 等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C 相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
7 V0 ?* F+ o0 D# G" ]+ {# ?6 D3 M# G# u* y" F
2..NET API与传统ObjectARX的主要区别
+ D( `' y. @2 Y! G9 P3 b; v4 ~
5 z p4 e: s: ~5 }5 w# k.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C 程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C 环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。 Y& C5 }% m6 T Y) N* J, n: m+ K3 Q
% l6 Q0 _. V5 ?) F: O
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
* F; \1 u' ]2 T: v2 f; L/ a( w
" a; L3 u- i& @) }$ |3.使用.NET API
- U4 M4 b! ^8 i! \5 p/ L& C
' E+ ]+ \; [6 Z7 U$ t9 B下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
# B: J9 i$ x- ~1 N# J" }- H
( b, H, c1 r7 g- f
3 P# T4 x. m# V- f8 X' h) r然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:! O9 U( F7 r% V0 ^. x2 r
4 x. i3 ]0 m: K5 K% J J
using Autodesk.AutoCAD.ApplicationServices;, S3 o/ V4 d( |1 O. S
using Autodesk.AutoCAD.DatabaseServices;
( P* i" x2 V5 @# S: d% Tusing Autodesk.AutoCAD.Runtime;
8 h2 ]+ m2 |3 s4 _$ uusing Autodesk.AutoCAD.Geometry;
2 l" V8 n4 u" }$ s8 Y: u# I H! r' }" P& S2 F
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:/ N8 l/ ?4 n! y9 q+ b) T( u
9 n& I j. C! Q" k7 g+ c/ G/ J8 [4 b3 a
[CommandMethod ("AddLine")]* M5 y$ V! `3 D
public static void AddLineCmd()
7 U* J# F/ `% o, s* q# _* r{
; j+ l$ W- J1 i# h& NDatabase db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
" h# R9 C, w h# u; j z2 ~BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
: n# l# T. O8 gBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录6 a$ Y. \ j$ \. W- X
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
3 f" R1 i+ N' J6 t) t5 a0 {) D9 ^. b2 ~try {- [* ^1 M8 x# ^" k) P1 L, |7 c
btr.AppendEntity(line);//将直线添加到模型空间中
2 Y$ \0 P. S" pline.Close();//关闭该直线) _0 }* w: S$ j
}$ w4 S) ?8 R- f1 K! E
finally {: q l6 C+ s& S, n5 k
btr.Close();//关闭块表记录
( \& {3 X. y" i! A0 p1 |/ Nbt.Close();//关闭块表, i, H0 E+ ^! p1 ^: S
}% o2 u3 c4 F7 E( N
}8 z$ `% D% ?: o8 y# d! E. ^3 q8 J
' l Z4 w7 s; g {8 s# P
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。3 p. z4 ]/ v$ M" Z4 b9 d2 r
0 b; [0 U* g+ C0 e- I5 l: C写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。 x$ |7 O. q: f6 K3 N2 E5 D) v
( y* d9 h* J2 J) d4..NET API的初始化与清除
" e$ h! \! N0 X3 j. X5 x! Z1 w
4 ? s5 `4 n: i( N在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
# J: _: H' f i KIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:& c+ [ M" n! o
% D7 m1 e! b N" {namespace ARXExample {9 ~9 d0 m4 Y/ E- ~
public class MyARX : IExtensionApplication {
: S; [: X/ k% G! A3 i2 J* |……6 A p5 B& o) Y. h) v
public void Initialize() {
+ K9 a7 K$ F, }9 q( K# m: M//初始化操作
. O1 C; f& X- B" B- s I}. K5 {, o9 M2 O- z) i
public void Terminate() {1 x! L) ^& Z5 Z! ^
4 i5 v- W9 F' m6 k6 I
//清除操作
+ o V% i- {9 u/ I+ d) Z}7 V# b8 S; \+ B0 h, h( i6 w
……
5 m' P1 ~. [, s) u# x) B, k6 e1 c}5 C- p2 k% o( C$ t0 r. B9 }
}
+ h5 A7 X* X. L4 n. F3 x# E同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
* m4 p5 N& Z) D* z5 \[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
5 ]: p" m/ b2 V% R[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]1 L: j$ H& G: }& ?
( B' E" }( p* V这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
0 R9 G1 g0 N& i3 j
# A9 m {& b7 Y8 I3 j' }& F5..NET API与COM交互操作
# H3 O5 y! C: h$ n! n
7 p! Z9 }% a$ S/ d% X- U) {在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。. f0 Q5 {, H' Y, Z; A
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:6 T- a* Q- X1 N2 o. j. p
: g* g( e N. T+ [ W& tDatabase db = HostApplicationServices.WorkingDatabase;
& V# Q3 |5 Q) K# V( ^BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);, J* V7 T; R+ |, M
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
( x9 `& l" j) A+ w/ c! g dtry {
* t' r* H1 P. J# t! m8 rAcadObject obj;& A. h1 ]+ s, [1 ~) m2 `
//遍历块表记录
" k9 Y5 M8 Z" f( p1 Sforeach (ObjectId objId in btr) {
5 X" R8 b9 }4 _7 d: ~. Q8 y5 g//由ObjectId得到ActiveX中的AcadObject对象
- ?) @ F9 Z; iobj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);
4 `7 H5 p) {- W! Y9 I7 ?5 i0 Y//为obj添加响应Modified事件4 x3 i7 j* p, d! T
obj.Modified = new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
) Y' C( R1 y, P1 \" b}( L" { E3 r, m$ ^0 f' Q$ ]4 D0 q
}; O$ k) g A* p7 Z3 C/ P
finally {
# s) q- v. {2 L, A" Jbtr.Close();# R4 ~9 d3 V* C z' K
bt.Close();- ]" E. G% q4 Y
}6 T0 I! M7 ^0 y N
其中事件响应函数obj_Modified的表示如下所示:
. b9 h4 p5 y1 t. o; C8 L. k% z% w% `public static void obj_Modified(AcadObject obj) {
) J% ?1 B: g5 w' ^CommandLinePrompts.Message("object modified!" obj.ObjectID "\n");. J1 L( B% {& d0 a
}3 u& }& ~* A& x% x& R+ a; n
4 z2 O ?6 l% Q" M二、结论
; u9 ^- A. @& e3 J1 q# N& N0 w
6 Z7 S3 a+ p6 ~本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C 的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |