华南理工大学 刘林 麦智晖 阎汉生
3 {! U- S% F( [5 x- a5 [8 S' ?9 G. T
- |% H' U; o+ D! I/ F8 {( l
本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
, v z, T. a' s5 Y! S4 J8 y Q- r; E" L% g1 s4 m/ C, ~
8 D, [1 {9 V9 b, n
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。& x$ {! B% Y( Z* J
$ v1 d! i8 j9 C8 I1 i
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。
8 X2 e' w4 d% g
1 [" Q* c5 w" B1 o m$ P m一、基于.NET的开发
# j, N- h/ f% O1 i' v5 U" g
) }3 H& s" R* O& E! _, F! ]# r1..NET API简介
: V4 U6 f' g% f. q- J
- ?/ o5 a1 w B! s在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
% Z8 D5 h$ K6 I3 P0 z+ Z: l/ p0 }3 \
2..NET API与传统ObjectARX的主要区别
0 a/ D' [# v; P1 b$ l& P; y/ u0 w# k2 Q
.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。* _+ ~& X: E# L5 ^6 |
8 I V' {0 m' A( ]; C其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。, o/ b9 A; q- p% h
3 g: b. X2 p( L/ @& M4 X3.使用.NET API
7 N& a- h1 X0 G4 }8 \# v
% `. \3 E; {1 z# F下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。4 c; E3 g! a+ b! D/ w
2 T' @0 a2 D ^8 e9 d( ~8 D
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
0 U R6 m" R! Q9 R
* [% m3 n: x7 busing Autodesk.AutoCAD.ApplicationServices;
, n4 y7 M( m! `" ^ _( L0 Ousing Autodesk.AutoCAD.DatabaseServices;. o$ A: _, v: b/ X" ]
using Autodesk.AutoCAD.Runtime;
% }5 M7 P, P4 Z; ?3 I1 _, W8 {using Autodesk.AutoCAD.Geometry;
7 b+ _- a% ~0 G {' p- L5 d. V- o) ?; V
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:4 _9 t: X) F6 a7 v5 B* ^
( A0 o. N( p1 ?2 O$ N a! _[CommandMethod ("AddLine")]. `1 ]6 X0 ~% x6 s9 h* V( l
public static void AddLineCmd()) A6 {2 I" z2 z3 G, v' k
{) {# O5 T* [, Z }5 b
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库8 Z( {, Y9 g+ X
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表1 `& e* V7 z) s6 B# W4 `1 ~: O
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录( d i9 L1 ~/ Z. S) \& ]/ P3 o8 ^
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线" c( U; T' {+ m% Y
try {
5 J& X9 u9 A' j4 F- xbtr.AppendEntity(line);//将直线添加到模型空间中
2 L3 C* z' {2 H5 O6 rline.Close();//关闭该直线- T. v$ F* T/ r' J9 |3 |' S
}7 @3 C1 R7 x( [5 l
finally {5 d1 y" m H5 P$ J* _* a/ A
btr.Close();//关闭块表记录
+ p- X* U; B# C% x2 Z/ t. obt.Close();//关闭块表! F$ I% [6 K2 R+ d+ i7 Y
}! ? W3 \) [& g2 T0 e, m
}! i& ?8 v5 b9 l8 ^* ~% x/ k
, P, ~: A, T3 u& y) Y; {+ I由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。0 J1 d/ l% q% [' Z6 m9 u
9 R+ h+ Y6 Z) H; g& B h写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
# T2 B7 }9 A8 m
6 b0 }* d; r: l G9 X5 z4..NET API的初始化与清除$ e# ~5 Z/ H4 s# E2 F( o+ F
9 c, K5 H P2 m6 W9 @
在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现0 l# u8 a( E% f: [. R( U
2 E. Q# G; |& l7 _+ R$ I" GIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
0 T) S1 ?" w& `5 p" n
4 s7 Q8 E) r4 q1 Vnamespace ARXExample {7 K( t. e8 M) v, g
public class MyARX : IExtensionApplication {
3 f- K. D( p1 p) A E……* ? ^: e; E4 c( l+ G3 p, ~
public void Initialize() {. `/ n0 M/ c" x5 M+ F
//初始化操作/ U" Q' i( Y6 k0 d* F0 l/ @
}3 Q |+ b5 @0 [- p/ r: L
public void Terminate() {
# E: [( e7 _8 c$ g; [* G' z//清除操作
3 v7 E$ r; M: t( O$ L}
% b" h: P; f! o……. ^: q! G% Q- f
}. ~$ _" P2 l/ E1 x1 u
}
" Y: V7 H7 ]/ C; |: Q4 Z' p/ r9 ]2 m! m* Z0 d
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:7 l" @4 n4 z" r8 B* U1 i9 q- P
4 J$ s) Q3 s0 k/ p5 s4 C4 z9 }9 M[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
. P: o: F- \. Y2 b( ~[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
4 u- X0 s- f2 |- _" ^3 ^1 g/ d: H
' _" j: ?7 c' E) b这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
* Q s' d- C* b I1 r* b
3 h% a7 o1 R/ B5 |5 K5 x% C5..NET API与COM交互操作
! @) Z+ O' z: B$ c9 d2 D$ N- n
5 |. o& g- d" U在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。, }( I, t" H$ {/ E
6 G& @. x& o5 c; m0 u/ r5 T" ~6 u
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
5 B1 u" }6 \. \; x
4 c2 u7 \$ t6 V) B' NDatabase db = HostApplicationServices.WorkingDatabase;
. K, j% }9 _( Y$ UBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);( d. f& F7 Z3 N
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);3 [5 O/ J( ?" c- Y; t0 U
try {) O% r) V; E: L/ _9 ?& L
AcadObject obj;
; q4 i- Q9 E$ f$ v y) d//遍历块表记录0 \$ F8 r+ |( c) v5 k+ d8 X v
foreach (ObjectId objId in btr) {, n+ N4 Y: @: A
//由ObjectId得到ActiveX中的AcadObject对象0 M, G% g V) D* ?5 L
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);) f' X% m4 I' V" ^
//为obj添加响应Modified事件
9 `6 I/ \5 d3 G" Aobj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
1 J8 I. E2 `8 i: J}+ i5 E1 R+ u j1 }
}
1 j z0 f; ~) W1 T4 j4 \5 d: y3 Yfinally {
8 b: D0 `* X2 e7 t: Y r; o! \, Sbtr.Close();
; i) K0 v( L9 X6 F7 T% Cbt.Close();
) V. A" p6 O |2 u}
& r! b9 `7 H2 ]2 ^: v- l! P
. U0 @6 E6 t5 w B1 q. p其中事件响应函数obj_Modified的表示如下所示:
: C# l, |. f2 W0 a) W8 w2 O5 \3 j, G! A! d7 y+ v8 v8 q
public static void obj_Modified(AcadObject obj) {
* ?! Q" f1 i9 \4 M* bCommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");
. |8 \5 M. }* @7 B, ?9 b" n, @}
, N0 g+ h# d3 O" y
/ e- k7 }; T. b" D1 T二、结论8 w8 X8 e4 \4 p, Q3 f6 U
. C" y) r/ B, U# T9 ]本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |