当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。 % F0 Q* Q3 y4 d0 E+ H
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。9 G& u. S0 X! B/ g ]/ K! d* _4 D0 f
一、基于.NET的开发+ w6 }" }( W4 S) w
1..NET API简介
+ B4 I7 T7 i2 ]) ]4 h 在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。; C. y& _) j; P& K5 t3 K
2..NET API与传统ObjectARX的主要区别
2 F8 _7 I. o M7 ` .NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。 ?( C7 p- W! P+ A# \! ^* \
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
9 n' \8 m4 x$ e s9 Z9 ?4 B5 V# z 3.使用.NET API
% r& u. x$ S* V: q% Y+ W 下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。' ?- k" r7 C5 U$ i# G/ W
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
! U5 Y, C% p; Z! O using Autodesk.AutoCAD.ApplicationServices;! i$ t. n+ k7 F6 H5 b
using Autodesk.AutoCAD.DatabaseServices;
+ [& Q# q: u, F8 s using Autodesk.AutoCAD.Runtime;
/ i! u; e) U, D* ]4 _7 e; k0 ~ using Autodesk.AutoCAD.Geometry;
# s4 @8 F$ S$ X# y 这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:
x/ ?7 h5 U7 H [CommandMethod ("AddLine")]
/ i7 t& E5 }+ m5 i4 v, M$ ] public static void AddLineCmd()5 S( f1 U1 b6 z- S+ c
{, @1 M6 X9 R: A$ T! F
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
: c) K) F7 V: ^ BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表- f2 H/ |0 G( l. y
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录* N# F" P" E6 S* w3 i$ [
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
/ F9 k- H! C+ J3 g* d$ g" B try {& n6 g8 B7 O9 Q; p" F; O( R) o
btr.AppendEntity(line);//将直线添加到模型空间中
/ m5 @ y2 N+ ?, \. a4 {) `8 m line.Close();//关闭该直线
3 n' Z+ P% h" ` }! Z# v* C$ D7 g* t' ?
finally {6 M6 J3 L" {0 ^4 |, y4 n
btr.Close();//关闭块表记录4 }$ @9 O1 I! A/ V! G5 Q
bt.Close();//关闭块表0 C1 r$ U/ r& n. J( ~+ u. j
}6 s; s; S4 K+ I" Z$ c) G! {9 A K
}
+ R4 I! c% N! l3 Z8 ]: L% J' p 由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。: ~ D8 f! ~3 h
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
3 w: y/ m$ t) N2 a) \/ ? 4..NET API的初始化与清除. T$ T0 I3 m" |- b5 O a" G
在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现0 p8 L7 G! c' b& M5 p
IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
" z/ f6 f& h% \! n I# Ynamespace ARXExample {
_+ g* m+ @0 Mpublic class MyARX : IExtensionApplication {
4 c! E; |4 R$ x4 O# o……; R4 A* g0 i/ Z
public void Initialize() {2 X) N/ R6 i4 C5 W" _3 Z% W( M) T
//初始化操作
- U7 D. a( M& d; e$ s# i/ x* e, {}
3 d `5 g+ R, u. z6 Rpublic void Terminate() {3 P$ r. f% O* K/ o, }% P, n
//清除操作
( q+ u+ l( R# V+ D# g6 ^7 Q1 L} {# J" r7 o' H2 w# o p( ^! A, k* H5 E
……/ B& d( E, U6 M, W
}+ k+ L5 W6 `3 q
}
( T5 X; C# K; u d0 ]" L. m9 @同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
9 n! C( U4 t! y" s' T# r; a[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
: Q! W" U1 u) }8 ^1 g C3 E8 k: J[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
, g x3 c. c% \# x4 j 这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。2 G) F+ r) _4 M0 g
5..NET API与COM交互操作, `& B0 T$ Z/ G% \# |. e
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
. e; Q1 @- E- j增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:, B v# S; M# d' ?. c! s+ I
Database db = HostApplicationServices.WorkingDatabase;9 [( {+ O$ @+ @) h t: K
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);# T [- R: k" O& N
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
3 {& V5 D9 ^9 P3 T6 V/ `$ H1 Wtry {0 P, ?: q6 A2 w9 q5 Z5 G7 l/ R" \
AcadObject obj;2 v0 N# b' z) q; x0 N6 A
//遍历块表记录
7 t; o/ m3 j; Y; j: x' oforeach (ObjectId objId in btr) {) K' c4 y. M# p, ?; j' ]
//由ObjectId得到ActiveX中的AcadObject对象. {9 ?. A" v, W
obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);0 ^' ^4 t4 {& B3 P$ r
//为obj添加响应Modified事件
9 `8 L3 B" \: V; u, j( h% ] obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);" {$ A* [0 J" H7 N/ ?
}
( U, }9 L5 m: L( P* g. d' A}
$ |) b2 A# R, ?! _finally {
) K+ B/ l6 l f" l7 _) y1 X btr.Close();
% h4 e1 V0 D# t: i% o bt.Close();+ C: T& b" u' E8 z8 @" E `# W5 w8 U
}" O7 q) I) D8 e: G" q. \
其中事件响应函数obj_Modified的表示如下所示:5 Z6 m; m' U5 B1 t& |! m# Q% Q
public static void obj_Modified(AcadObject obj) {
' F8 O, w9 {: @" m( L) mCommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");8 p$ ~# j; U* o( r+ \- M7 U
}# b5 ^- y) n" U) v+ z$ o
二、结论. ~: k9 Q, g) ?% D7 }
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |