当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。 , j7 c q- Z) I. W
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。; E4 H; P& v; `7 j2 A7 l M4 ]
一、基于.NET的开发2 i! _2 }% c9 y
1..NET API简介 {! `2 J! _! a" U% V( c, t& q
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
7 h; j3 h1 ^0 O e 2..NET API与传统ObjectARX的主要区别$ ~" Y u, P; D/ s: \' S
.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。
8 I6 O- X# k: J; V 其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
9 W4 T: M& x2 x$ K% F$ G* G 3.使用.NET API3 N* r# k' n! T8 C
下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
! I4 B7 i! r; n4 y$ v0 r 然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:$ J$ x6 F6 A8 z3 Y+ e8 e1 J
using Autodesk.AutoCAD.ApplicationServices;
4 O1 ~. j: G: T/ E$ P7 @6 T8 | using Autodesk.AutoCAD.DatabaseServices;/ y( f: R M' a8 p* t/ \
using Autodesk.AutoCAD.Runtime;% H, P3 _5 N* @. g' B
using Autodesk.AutoCAD.Geometry;
8 V+ H: [1 t* W' j$ l5 a 这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:
' b, j+ z# a! J6 _* g- `1 K' x [CommandMethod ("AddLine")]
% D) P: Y* ~: b5 o I public static void AddLineCmd()
" J. I0 @. f) y3 e" _/ f {
$ k+ s- |! f6 m8 d% C# d Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
3 P6 O1 c% j5 ?3 s* D BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
6 N$ K; `. A2 B' x, Q" j BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录
. Y; n4 ^! D0 | Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
! z3 S- o8 H$ V, O4 k0 S9 P try {- E/ w" j2 x/ z7 M7 `5 G: H: v
btr.AppendEntity(line);//将直线添加到模型空间中 _7 H V" i/ u
line.Close();//关闭该直线
$ X% B' z. {2 W/ }. w9 }& T2 r6 G% H6 t }
- W( @6 q& G1 Y finally {
7 o* r; J% M+ w7 g; F btr.Close();//关闭块表记录$ N5 x% y) ~$ S/ X0 a! I
bt.Close();//关闭块表
( B+ Q+ w/ d4 f5 Q7 q- D }
3 [! [3 a) Q% u. o( ^ }0 L: s/ \5 l4 w
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。# j- ~; Y* y. r! ^
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
5 P0 J C# R# ^" k 4..NET API的初始化与清除
, V. \* K# h5 }$ n$ w, W4 p3 T3 i 在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
. m8 j$ V0 T8 `4 w3 o0 n IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:3 E- ?+ c5 U! h2 r" c5 e0 [6 `3 \7 ?
namespace ARXExample {
1 K: A( v1 s1 g- upublic class MyARX : IExtensionApplication {# p9 i; j9 H Q$ z0 _9 V
……8 D" ~" |; @8 k
public void Initialize() {3 S9 T6 w8 j5 O5 `* G, \
//初始化操作2 J% I9 s) h4 N; \- K4 z
}$ Q; O$ d/ `& O% g8 [; E- |! M
public void Terminate() {
# [, @1 b+ q" S( t //清除操作
- j/ ]; ~0 w) u}
) V" h3 R7 A# N2 x- C……
' z2 p7 T' P* c H}1 J; a" E$ {+ h- o, Y
}
8 B# Y& y0 p7 f# X同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:/ O2 k5 P; [2 k X2 {2 p
[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
( @; W7 s. p) A9 n5 \- R& e[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]+ F9 V4 M& V& f! |7 R7 t4 X
这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
9 G3 M0 ]8 p/ h$ v. v6 ` 5..NET API与COM交互操作
5 U! |/ X' q, |' s$ V/ O( C 在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
( E3 `: L8 D4 k3 u N8 W增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
1 r0 h, t2 B' `5 m1 q" ?6 I# U4 dDatabase db = HostApplicationServices.WorkingDatabase;
! l5 a* L! x8 z* X9 F. KBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);
' E# l9 n3 y& Y/ Q: V2 f* j" PBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);/ H* E7 q! f3 Q7 b# C
try {- ~1 R( y: i: w' D. |# O1 f. Q; E6 T
AcadObject obj;
0 T' v4 q8 s# s6 R/ u, x//遍历块表记录
j$ z v* k9 ?$ b3 j" `foreach (ObjectId objId in btr) {7 q Y2 N2 _9 ]# k- F: @2 Y" F5 w* F3 B
//由ObjectId得到ActiveX中的AcadObject对象1 Y3 i7 m) @) [, m) q3 M1 B
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);9 [- G' }( j3 A& [( V
//为obj添加响应Modified事件& [4 w u9 P1 D, g+ _
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);
7 _: a- i' J+ y+ f* U$ i }
( B1 |# `& l+ V8 u) G3 n}
- B! s8 R' i# c, ofinally {
* _: g& h' Z/ R C6 w- ^$ N btr.Close();0 z g" _. {. z
bt.Close();# {5 w# z. D& h( P/ u. Z
}
" v" h2 k# J0 A其中事件响应函数obj_Modified的表示如下所示:
9 Y5 C) _8 q8 L+ J0 n- r* Y! x' s' Hpublic static void obj_Modified(AcadObject obj) {
9 w: E; g) \* ?9 L! XCommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");: [4 A6 T+ U/ L+ y" u
}9 Q1 B j5 N; X! _" X( f
二、结论- m$ X! C G- y+ V) g
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |