华南理工大学 刘林 麦智晖 阎汉生
" d, N$ O0 L8 W Y8 K. P9 p0 y$ k1 x4 U P* _+ r6 J) N
Y: |4 [( R2 I/ h本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
' k/ X# _. K/ s( E9 ?
: j. G6 q( c) R! Q" x: n& o9 K, ^& T P3 r0 j4 V( R
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。% ^# v+ \9 N1 f
, ?0 T* s/ e: Z! A.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。7 R8 ~4 [# d% p, x; ]/ L/ \
, p: A2 _; U) b c
一、基于.NET的开发
; b: G) m' b; l% y J# b9 e) p: o( h0 Q) Y& ~! ~
1..NET API简介 c2 s# P6 W) H
1 \ L& S* J- P/ I在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
( W! l( \) w7 o7 B R0 f+ S$ U
w* J; |9 {+ i0 C7 f) ?, z( C/ K2..NET API与传统ObjectARX的主要区别2 ^: c( |1 }) n" B" S3 P H
( e4 N# {1 t! l" o.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。$ r9 ]' {0 |# i& S0 S; X
3 k; [& O" | q6 l8 r其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
5 b% f d( `( U/ ?6 M& G2 w. v( L8 b/ l& I! k7 `1 Y1 O* z. t1 t
3.使用.NET API8 j( i; z& q/ T' r
- `- H6 N9 h3 E' m. W# f下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。' p) }% b) Q& b X1 U& w% W- @
$ e: f3 c8 W3 ~9 }% P- K: n$ M然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:7 p# g% o+ Q2 w+ A, B! i1 h5 ^
6 ~& R6 ~0 c3 m: i6 }, W
using Autodesk.AutoCAD.ApplicationServices; N5 X1 x6 j/ V3 \
using Autodesk.AutoCAD.DatabaseServices;. v7 [0 X& U. v) m _
using Autodesk.AutoCAD.Runtime;; A; N8 B# E7 U/ C
using Autodesk.AutoCAD.Geometry;
! o$ v; q% r9 ~. O" \5 \! M2 o; i$ z
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:
( |9 m9 W/ @/ k
6 [6 F6 W3 ]( H- Z[CommandMethod ("AddLine")]
1 e3 D! f) U: o" H/ v- wpublic static void AddLineCmd()
% X: Q/ }1 Y- F/ U3 f% p- D) d. F{5 Z, D% ?) G( ^6 j) l! B
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库5 I5 d5 s( m9 B
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
1 E- T( r7 d2 I4 XBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录
, x: T3 t9 a7 B8 FLine line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
: h2 V& d' m- A! s) q8 Q- ]try {8 m# u1 ^, L5 q/ e; I1 m! l
btr.AppendEntity(line);//将直线添加到模型空间中- m/ s# w6 Z6 O& Z" O' @$ x
line.Close();//关闭该直线& q3 K, V$ U) K& V) E
}" Y( a; q8 \0 p6 y; P$ y/ |, k
finally {
# T1 D8 u" ~7 t3 ibtr.Close();//关闭块表记录: F0 [# s) K% n% O0 G2 L9 A7 N
bt.Close();//关闭块表$ q4 S" X2 O: x; r% C" b
}
$ U( C% a% C9 z% J0 J* I}
9 Q- b! k) A6 Y7 ~
, U% c1 n+ r8 j) z0 k9 ]7 s由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
+ ~/ H, P& d: t6 s
5 [: B1 O8 B# v+ ]& m写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
) g T: l4 o6 P$ P. _ P: k; N/ |' @) ^0 S# L$ x
4..NET API的初始化与清除: f/ Z9 h, H b* R7 p E$ `
6 C! n2 v# M1 P8 e" k在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
1 r7 e7 W6 p) U: a
0 d" t7 _3 n: }5 U' }2 p. HIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:' h2 X1 U* x5 u6 C' b( c
* E B' y/ D5 @6 |1 d u8 ~5 L- U znamespace ARXExample {
; Z. u$ b# }+ F1 a, ppublic class MyARX : IExtensionApplication {1 ^2 R0 I- D& z
……
) M- \' }( C! Z% g3 n3 upublic void Initialize() {2 Z8 b5 b: A8 q, R
//初始化操作: {, E" u# Q! P& L- `" t
}
! Z! Y3 f' o4 ] m8 K, r& cpublic void Terminate() {! ~6 p, f/ n6 |
//清除操作5 q7 V' ^5 W9 `. z( D& n) h
}
8 z4 [$ M6 f8 f……" I1 C4 {% n, {3 `/ P& Q. p* \
}+ x3 `% ~- ~' v: }9 p
}
* i) `6 m0 C! z5 M. t8 |' Y& a0 K0 L/ l/ M! x
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
{" H B: Q; k6 d
! g# a# ^4 P* h0 A7 c( ` \[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
- x) g# h- j" p- r/ v' `[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]1 o: ~0 z3 I& j$ o1 l6 I( O
& \& C/ m/ F3 l, T- ^& l: c/ G
这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。- w+ i1 N# l$ F- M7 W
! ^: V2 g1 G6 Y( g
5..NET API与COM交互操作 u5 D' J0 h! K, K4 S1 L
% ?) Y: u) ^& }/ m在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。8 ]/ I; H: j/ U5 o" F h4 Q
. j/ Y& x( R& m8 e增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
: W/ Y* ^- J( |1 N9 m, E E. f+ ~0 q% t- c1 q
Database db = HostApplicationServices.WorkingDatabase;6 |2 w* \$ e0 Y7 b- z
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);
5 d( p% j9 k( U9 h3 \BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);2 o S1 V6 c0 V; ]
try {
9 S: ? f% A: V2 ^1 K# s& WAcadObject obj;& b" I3 i+ V- ^( N
//遍历块表记录% `8 ]- l) k: j* _! _0 m8 }
foreach (ObjectId objId in btr) {) o# a B- z: L
//由ObjectId得到ActiveX中的AcadObject对象 }& t. C, u1 H
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);% c* g# A5 q8 H/ C/ |. S, `5 _1 ?
//为obj添加响应Modified事件
2 M. t8 O( n' mobj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
! N2 \) ^# P2 L. _+ x4 v7 D}. I1 q7 {* ~: |9 W
}2 @# V( T" B5 j
finally {
8 }$ V; ^" |3 ~btr.Close();
; H, } S7 z, T- T+ K; Ybt.Close();
, s ^0 |9 r1 N$ E' M}
; E3 j# F3 _, a1 d$ b3 ~
( A9 U. l: ]0 ], o# W- j其中事件响应函数obj_Modified的表示如下所示:, e( j1 i2 J ^; s& m; j
8 q7 n2 O6 y7 L
public static void obj_Modified(AcadObject obj) {5 O( Q+ h1 I$ M. h, j2 D) \
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");$ i. L6 E+ \- Z% H) i7 Q3 l( k
}" l& f! o( i3 x$ N* N' P
1 m8 r1 Y! L% _6 }3 Y; Y$ ]二、结论
3 @& A B' v% k; _/ L5 h* l+ C: A- F1 R1 j
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |