华南理工大学 刘林 麦智晖 阎汉生) n& J2 C0 ^, e
& u. r4 R! ?0 e0 p7 J
( _& K( j6 p/ z6 H" h7 C- [本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。 0 t1 @3 I# I8 E7 B" B# i% m$ r& K
/ X) q1 W. R; `# j
8 ^0 w2 Y2 M2 e9 ~3 H1 u7 ^% v当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。/ l1 f, U. d) \. P- {
8 J6 S9 h$ k b$ E; b) _.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。* z% ^3 { ~, [3 V6 @6 d
$ k5 I( l' l) {- b' n2 H9 N. |. W
一、基于.NET的开发& Z i/ _# W1 A$ f
( P" x3 A" ?6 I, E7 E6 ^. q
1..NET API简介7 c# l, N, l; P( K( Q1 q
6 |& W5 T- d0 w+ Y! Z& ~' u
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
# J8 O, v; E& j% |! x0 c
5 z# d1 J$ k" z+ N/ f6 [# m2..NET API与传统ObjectARX的主要区别
* m# a( }! ~& Z5 R' x: V3 C0 i" ^' p K4 h" Z8 n
.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。2 c# k3 D0 B9 a7 p9 h
1 L2 i) _" p1 x+ {. X5 |- x m0 L
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。$ D/ d; O% s9 y- \" M
( r- [% @9 l& D" O) }% d4 [
3.使用.NET API
# p _4 `( i6 L' K) k) s N9 w
) b% u$ ]- m3 M- j l下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。 I, p& l. m- c% d! H
# O- {! C+ i5 L7 R然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:8 `& c! @/ P8 q, o) O
7 |5 V+ n! `; ]2 q6 d: o" p
using Autodesk.AutoCAD.ApplicationServices;
: J- P* }6 E) }% y) [using Autodesk.AutoCAD.DatabaseServices;
' j2 I; n" {. M w, Gusing Autodesk.AutoCAD.Runtime;
0 g- {( e& t9 ]# Qusing Autodesk.AutoCAD.Geometry;7 t3 { F3 s: Q. }& }8 ]7 m
! y- P2 @! M, V: i+ z1 n
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:+ d- L# K! r' {- U8 I
6 m4 D& p% Y3 i' A
[CommandMethod ("AddLine")]
3 Z/ }" f6 v8 [public static void AddLineCmd()
0 V. G% `3 Y# ~3 a7 L, C6 I/ C{/ G4 A3 @$ [1 [( w/ D
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
8 G. j9 Y$ h* r. U2 Z1 ZBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
6 I. G9 L: K- y8 Z1 Q7 N1 b' QBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录( s1 g. U9 i8 C: s# |+ K% W. G7 g
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线+ V& `4 L- {6 O2 f7 M+ n
try {
2 h7 I" h. Z: Wbtr.AppendEntity(line);//将直线添加到模型空间中
4 E9 M' C, i, uline.Close();//关闭该直线
3 m( \9 O( K2 {* |' F$ B$ ~}+ I, H7 B ~' ?; _
finally {6 t! Y! X. `8 d# e! t* q& i
btr.Close();//关闭块表记录
& S( ~$ q! u4 j6 T; m; S; pbt.Close();//关闭块表0 P( A' E+ B: X7 p# Q- D' Y5 E
}
" ~) h- `* ? i& Z1 r5 q! F}% v. s2 r$ f: r7 W. S' z* s
3 k$ J" p) J" i! Y
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
7 a6 n- H- |8 v- G6 V. L6 W5 M, T6 H* C) P0 w0 p$ O' o0 a; W
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。5 c) t- I. X! d5 ?5 O
2 H3 ?+ E: ^9 y+ y4..NET API的初始化与清除8 x1 t" N6 a' L2 w' ?2 N" H# @
; ]0 k0 c. r3 ]* Y4 Q* [在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
4 x" f6 n1 x: N- R4 { W x2 u
) _2 f+ f3 ]6 ?/ j* @# XIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:7 f2 }, ]% T3 i
8 F+ V4 d$ |. H8 J- g
namespace ARXExample {
( T- d7 |6 u% |! }1 u4 ppublic class MyARX : IExtensionApplication {
$ f" }4 ~; H' R/ X* m/ Z0 E……( x+ k; v( I% _& y' q
public void Initialize() {
# U4 W& ~2 x( ~5 U- p//初始化操作: s6 r3 T5 {# l
}
/ q. h9 a' K% i- h# r5 D8 N* cpublic void Terminate() {( {/ l! |# @9 t$ u( R7 }/ M& S
//清除操作7 ^9 K3 u/ c% C% ^
}
1 V. x* B. P3 \& L# ` ~& e$ m……3 I$ U( W% ^& B* o$ |
}
6 v. q7 E; u+ u, k- a [# |}4 _/ O' i! j' p; T; m6 O5 Y8 Z
3 {+ c K( q( W, {4 u2 W
同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:9 @1 A; O" T/ ]$ }' v$ i/ g
5 S& M5 ?/ [+ j( s7 N" d8 y* `[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
2 J+ Y5 }" h ^) e4 o[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
* b! f/ B% T, W. n4 j5 l# Y( f7 V9 a R" i" @7 ?
这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。7 V. D, v* m) B6 r: J$ {
3 Z) U5 X& d% e4 ^/ }$ r
5..NET API与COM交互操作# [. `1 N9 u% Z4 v j# n4 P$ R. T
( C# S6 U* Y9 `! i; N在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
4 N3 s7 Q q& W" R9 S+ Y* B) Y( d9 d. w# s9 j4 g0 P2 J( A
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:, |: y+ Z1 J- m: T2 k$ ]
k; b2 ]' J( {8 bDatabase db = HostApplicationServices.WorkingDatabase;
% s2 B ]7 _/ {BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);+ ?. B) | L9 K$ g
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);2 w' E; ~' ~- H6 ~
try {9 S: Z7 k- {" l% V- K
AcadObject obj;3 q/ O5 I7 d1 ? k& ]0 _
//遍历块表记录
, n* y/ Z" h$ q( tforeach (ObjectId objId in btr) {
) s+ D7 E5 G& F. i9 T; N {; `# J//由ObjectId得到ActiveX中的AcadObject对象$ G+ p0 A! ?$ o8 L6 Q) u) m+ K* k
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);$ f N+ u* l6 ]6 |6 T9 `+ e
//为obj添加响应Modified事件( Z6 [( {. r" @, w, Z2 F/ W
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
: R8 `5 [/ h0 u& X5 t) G! ]% m}/ V2 n) d; |. W/ f% h& ~$ q+ l# W
}
; N6 w/ L6 |! k2 }finally {; u# E- m0 d. ^! T
btr.Close();
2 B5 B6 ]0 a9 v* Qbt.Close();
& R4 z) c: Y" g( J# h} k( ]: I, t1 f
. ^. u4 c* W8 W% N6 I8 r其中事件响应函数obj_Modified的表示如下所示:: U" W" B8 O! J5 v* }8 S( f
) r) b% I, @6 P! x; rpublic static void obj_Modified(AcadObject obj) {5 G% G M2 ^! F) Q& n+ r
CommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");1 \2 H% e2 d% J
}
: C4 b. }( ?9 v# O+ x6 k( R
2 i1 @2 l' P4 W; n二、结论 v1 P- U3 v0 `
) w+ Z% q4 `% w3 S* ^
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |