当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。 ' ^$ G+ E0 w! x$ h& n. L9 R
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。
- r3 r1 M& O. N6 s一、基于.NET的开发/ A' \" s3 H! v/ y9 H
1..NET API简介
S S) R9 k+ O3 | 在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。
! r- l$ h& @# J: G' R 2..NET API与传统ObjectARX的主要区别
2 Q9 E, Z! W a6 H) R .NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。
' t6 C) x6 |4 |6 t 其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。" @2 X1 F3 i- t3 z$ q
3.使用.NET API
/ h) Z) l$ p5 q9 ?- o% m! S 下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
: d' ^4 H' C2 g# O 然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:
7 o; D8 z% c( k" Z8 i/ F ^ using Autodesk.AutoCAD.ApplicationServices;) B* R) t: I0 s% w( s; ]
using Autodesk.AutoCAD.DatabaseServices;
( \( n7 D4 M( J' m using Autodesk.AutoCAD.Runtime;; c1 [* z3 s; b' F7 a/ c
using Autodesk.AutoCAD.Geometry;$ l }( T: u7 U6 N" [+ w/ v
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:2 p3 }6 H+ Z+ l" L- {% P" |
[CommandMethod ("AddLine")]; ]) a8 |/ ~$ p: R1 d
public static void AddLineCmd()
! A4 p: G, U. M# C% f {
! V( s9 p$ b8 {8 G Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
+ b( A. I: W& ~0 E+ `' v BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
3 \1 h" t% s' b- e/ D9 a BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录
3 U; @9 a; w0 v' g- g, l& ^ Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
0 z4 V& a! {) G( R try {* r8 b, @+ x0 e: N( h4 K
btr.AppendEntity(line);//将直线添加到模型空间中
% j" C! p3 c% \0 \- t F line.Close();//关闭该直线
* f: B7 _" |! B/ _: B, a! N }
8 p, d8 y$ M/ l finally {4 N% A' t+ ?/ l3 t5 \( r
btr.Close();//关闭块表记录( Z$ p3 _1 H: ]0 W
bt.Close();//关闭块表# a% d! \2 i7 {/ U$ N. e/ V
}
& r2 z3 d0 @6 j" L8 D$ X# ]' ~5 L1 f }
; S6 O3 f/ d! S- B 由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
1 M# ]. v( { k 写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
" n5 {2 Y9 K5 ~ q 4..NET API的初始化与清除5 I4 c- S v# i/ {" k, X9 o$ c
在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现. i5 G: q# Z+ W( Y/ N7 p) s; g
IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
. K3 W3 y- d; d7 `* pnamespace ARXExample {# P" ^4 u( Q( ~4 O! p5 b
public class MyARX : IExtensionApplication {
( ]! c8 \: O$ Z4 k# \" _# c……% P2 t- |/ L7 K- h, Y, W9 T7 X* b
public void Initialize() {6 u) ~& D& V8 w U+ V
//初始化操作 x9 T8 h+ r3 Q7 I7 s6 ?
}0 i& L) e! u* O
public void Terminate() {
$ \2 Z* r& U5 H. E6 e& f //清除操作
4 m9 n( v5 c( ?( F! u% Y! B7 E}- J* p" H. o7 L) `' s6 ^
……
y; @; K/ M) L& s}
3 y0 a; I/ f' f- e+ S}
0 j" x2 c# k, k! S @2 o1 l+ e9 r3 w) a同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
" J, q1 I+ c2 B( n/ Y[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
K5 g- b5 |' I5 \$ {* Z[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]
" b) P3 W' M0 l5 V 这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。5 O! `" t4 b! {' G) P
5..NET API与COM交互操作5 a; \, w; x; D$ Z
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
$ @1 A. G5 _& K# o0 }增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:$ D; s u9 H3 ^& `, v+ n
Database db = HostApplicationServices.WorkingDatabase;
1 ?6 n) V! f: gBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);$ z1 T# z. K; s
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);2 c( u( p1 {2 `
try {
# A8 T) r8 G) B+ g0 E0 ^AcadObject obj;
8 D' U. m4 g% ^: z' n0 ?$ _//遍历块表记录
! ~7 \& Q% n) q' Hforeach (ObjectId objId in btr) {
5 ^# H" U7 d* p //由ObjectId得到ActiveX中的AcadObject对象
' K8 b9 I g2 G U% q! S$ ` obj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);
Q5 e2 L: D2 L3 v) Z9 M //为obj添加响应Modified事件
! p( I) `/ {- w) f+ r, l obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);( m$ X4 P* Q7 O6 Q0 e2 M. h& [
}
: H* I7 B% d4 Q# E4 r}: z9 [. j3 K- }
finally {( A+ I5 d+ v. D2 i( A! O7 I
btr.Close();
4 S( v5 {2 k' F+ w& j$ j! z. P bt.Close();
# D$ d9 y6 J5 n" I" b2 ^}
" \6 t& `( G# K其中事件响应函数obj_Modified的表示如下所示:( j! ^- C4 D9 t7 C4 q; \
public static void obj_Modified(AcadObject obj) {
1 f; s6 I! H( S) G( Q* i1 DCommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");6 J& {1 r3 X( N; X8 j3 M+ x! j' O7 `
} C$ W! ?( A( Q/ e& b: X' j4 \% _1 D
二、结论& \6 s# g' I. I( c" f
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |