华南理工大学 刘林 麦智晖 阎汉生
0 {8 K7 B! ^7 F3 H
! }. O: t7 q$ x B* d$ R7 h# o% u5 u1 j1 g. e7 b
本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
+ g D0 u; W! s* _/ l2 n9 z4 j( k' E$ a, `& @- _
# M5 G9 c r8 ]% U2 s当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。
: h$ O( C; w2 y- ~+ w" }# a# M
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。5 @- v% I+ _7 d: v3 I0 n
' I1 t. k3 ?3 s% X+ k/ J一、基于.NET的开发
) _; g U) k9 n, L3 |0 u! t4 U) W) e* O9 Y7 N
1..NET API简介
. u" Y) J" u0 q: }1 s
+ g6 w Y |+ h在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。- k* w0 i% X+ g2 u/ |
5 ^, j C( ?% b: e" P9 J4 N
2..NET API与传统ObjectARX的主要区别
& b( ?! z( \* N0 v) A/ d3 V. T6 F
* C- h; v6 V. k/ H.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。
/ q. b5 T M7 G+ B! r- h2 c5 g9 }
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
+ Q. h4 v% c# u, T
5 I8 k. m, V& x# \6 t: w/ c& W! F3.使用.NET API# ?& u. d1 i; _ U
2 D8 Q+ E% o0 C下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。, N1 x1 U0 L3 F" d
# b0 T5 [6 r5 L R( o9 E, K4 S然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
0 E# L4 ?3 t; L, ]+ t5 Q" }' x# T- S2 H2 c0 P# o
using Autodesk.AutoCAD.ApplicationServices;# M" S2 q. W) |' ~( s& M
using Autodesk.AutoCAD.DatabaseServices;/ N$ w4 u: b8 O- g4 R7 M
using Autodesk.AutoCAD.Runtime;6 V( v" }( y' P/ L1 }0 ]
using Autodesk.AutoCAD.Geometry;
$ _0 C" M4 _ m6 [! e R, L0 a, h
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:+ A5 V7 b) [3 Y5 s: n
5 Z1 x$ B7 w. a; H7 Q) R, B
[CommandMethod ("AddLine")]
$ ]) O' H% c9 Rpublic static void AddLineCmd()1 e; k1 S& [7 s- I1 O* b
{
+ W. Y: L8 y" B2 @Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库2 R3 n* C" {/ ?- X! p$ Q* B) [7 w
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表/ A( D4 }6 {; I* H- U& ]
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录
, L8 y) Q# u, a- O( dLine line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线3 {" O2 i' W& c5 B0 n* J
try {0 N5 _& Q4 M0 W+ Q q
btr.AppendEntity(line);//将直线添加到模型空间中
8 t6 U5 q- C3 Dline.Close();//关闭该直线4 n" h& G3 _( T* b$ `5 ^: J ~
}+ V/ x4 H. D4 p' L+ q; p( x; h$ H9 k
finally {
+ ~% \% r% [( W( Y" a8 g% ^; ubtr.Close();//关闭块表记录
0 ]) I) x$ C" rbt.Close();//关闭块表5 k/ o# q6 Y0 B. @1 h5 l* P" ?
}
% K; x. o1 O& O( r2 V& w; r) \}
# y c9 w0 ^/ g. r* ~2 T
: Z% \) [# ~. C9 R9 H由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。$ } n1 R0 X( V `- F! ~
8 l0 q) k7 O+ k. z9 H, V3 e9 Z) D写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。" W* o0 M/ N- g" \6 y
1 C# b2 |) c3 |* K4 s/ e4 k: d4..NET API的初始化与清除
" d$ F1 O& g7 y" ^! j; B i
2 f0 |! f0 d* A$ z" [# B在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
( ?' G5 d, p5 Z# D$ i9 L
% u, b5 {; h( kIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:, |1 K) |0 V6 l$ c9 L2 J. r$ e, h6 F
; E; h. B& V) A: c/ Rnamespace ARXExample {1 L' z" x! T, }, x' Q$ t
public class MyARX : IExtensionApplication {
# P+ L" h5 ~" C8 J" h……
) ?. \6 L; S# a6 a1 I3 p: r5 upublic void Initialize() {
1 m! L' K) @1 v1 m8 d! k//初始化操作
/ V. N- t2 s; _& f) b. R- J}
; d8 E3 j' _4 T- Dpublic void Terminate() {
4 H6 o6 q" b8 S# c! C; U* ~! B//清除操作
4 P/ @1 V; n4 o9 s0 n& W}, P; }' A2 d, y h7 ]
……
% P3 |9 N1 Y4 l, t}* P1 p. u, C+ w5 H2 B
}+ x5 G# l) E% n* z
5 l, J% y2 n3 b9 L同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
- @( p2 |: v; P" t: u0 D, r0 z F( R! m% q6 A( `% ^5 t/ ^3 e% Z
[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
2 I& T8 l* @ ^/ T5 h[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
6 Y }. q' n7 B7 x4 [7 ~8 b5 s; E
" c: R6 d/ _) k+ \: b( p6 ?: h5 V这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
+ E& l" C% x7 D D7 j$ C3 j
& a/ ^& L9 F) S3 Y7 l4 l5..NET API与COM交互操作
0 c. g6 r" R2 U6 H, i5 Z9 i; q* a8 S, \9 W) O1 k- m& v, S
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。0 B/ q9 Y$ P8 m+ i. X3 B* j, I
7 u5 s6 i2 K0 j% Z
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:# T6 g! r. [/ l0 ?1 r/ u/ R0 c! I
! `. I# ]5 @' z3 W* [ P
Database db = HostApplicationServices.WorkingDatabase;
6 |$ r! s( x0 C% y! O: nBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);6 p) q5 Q; @* j5 p3 q6 h4 o
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
! j0 e- Z! n# ]4 Atry {( @% F b# P6 s Y+ M4 h5 P
AcadObject obj;
% J6 F: w0 t% [1 g! k//遍历块表记录7 m. [- H1 `0 N& Y7 P( f" I* e; ~9 A
foreach (ObjectId objId in btr) {
F' M' A1 g2 ]2 I9 K//由ObjectId得到ActiveX中的AcadObject对象7 ]- S, N. [+ M6 y# l6 d% p4 Z
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);
! M$ U2 t4 ]3 m) Q, ]6 `//为obj添加响应Modified事件$ J$ f6 B. w& F1 q A# Z8 S
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);7 ~* M! Y! u5 a
}
9 s* E" \$ W" z0 w- {1 _}
5 V: r4 V4 X0 V6 p+ n1 h' _finally {
3 e i6 y" Z) k) B% K% Hbtr.Close();
, E; H: m8 ~9 l* n1 P( qbt.Close();8 { `: S! g7 L9 E6 G( k/ g
}5 x9 x! l7 y. J2 }2 D+ E
& P* _4 l! m& X- x6 t$ g; Z% j! ?
其中事件响应函数obj_Modified的表示如下所示:
! c; Q# |, L5 m8 D9 u" y- w0 h/ R. h- F3 A
public static void obj_Modified(AcadObject obj) {& e: o# m' |* R: G* o
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");
! R/ {; Y9 n* X/ L* G. K- w3 p% T}
* H5 _# O2 a5 y) R7 m* a5 ^ ^
0 {) s! R( s+ P* N! b2 \二、结论8 P9 B/ J" Y: S! y, K$ w) c
1 z; d1 B$ A& w3 n
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |