本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。5 c5 t+ I: N5 s) u
* l( @# T, R k' h" v& F
! t' }* q/ @6 m# |" z5 G" H
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C 的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。5 _% I, J# ~' ^( j! f2 J
% r; y% f! v A# z, p
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。, C! n- o1 M+ j! o4 u$ ?
& S! A! G+ O, W O/ \一、基于.NET的开发
+ X* e L5 }$ w4 ]
# J& {8 i' I% n- ?/ _" }! p1..NET API简介3 T1 _' k9 O9 K0 p
( C' E- z" k' u/ F
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C 等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C 相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。" K7 k! u3 @7 X0 E
% o# n9 _; R! W
2..NET API与传统ObjectARX的主要区别
3 Y) u$ ?4 G' Z. \6 p5 s# `5 G# A
4 p8 |) B& A2 ~( G.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C 程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C 环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。( G5 b; ~* x7 J6 _5 {% F
: a0 `; b9 C: H0 s4 f1 m. z
其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。
! l5 D% f0 J& M3 z& o
d& X) Z' \% o$ X# {3.使用.NET API* A4 b8 b2 c$ M1 z, |5 i
6 b5 i* D- L, ]- u下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。
1 q4 o- ]" W) I6 i$ ^8 i- R) d+ h+ d9 o7 O8 v% u. b( P
+ d7 m% N* {6 Q; U然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:$ w# U% Z, R( E; o$ V$ M' @( Q9 {0 E& Z
% z7 ]- _: n+ k0 ^) n+ L' o3 k$ v8 r
using Autodesk.AutoCAD.ApplicationServices;9 `) w: n$ ~& r. U
using Autodesk.AutoCAD.DatabaseServices;
+ @1 v. I8 D ]9 h1 }3 rusing Autodesk.AutoCAD.Runtime;
* A3 U6 R" w+ b2 p% iusing Autodesk.AutoCAD.Geometry;1 i: Y# @- M0 {# P% @2 j4 y
1 j+ T3 T4 ~* @) M这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令“AddLine”,该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:
! l- {# X% w" ], ^* }6 a/ q- }
, m9 V6 L& H# z& F8 w7 {$ R9 e[CommandMethod ("AddLine")]
( K9 I, k5 w3 l9 }7 ?6 ipublic static void AddLineCmd()( I3 ^" N9 F5 R) B
{
0 Y: k' v# x/ `8 S; p: S5 w( {Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库
/ U' r+ o& V: U7 nBlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表
# O0 U* U! O) B {* ~2 ?' MBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录
( \: t3 @& m# Y! q+ V! C# vLine line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线% u* n5 B+ ^. }0 f7 s7 o$ y8 i" C; X
try {
9 q5 ^2 @' c/ a, U- Hbtr.AppendEntity(line);//将直线添加到模型空间中
% L/ u3 Q8 h6 K$ j- M( S2 Uline.Close();//关闭该直线
" Z$ `( C( g/ `- g7 r1 S}5 ^3 f0 n ?( M# [8 n
finally {
4 R8 O3 X8 k2 z5 g% D8 vbtr.Close();//关闭块表记录
9 J2 Q' G& @7 D$ d9 Q( J+ Dbt.Close();//关闭块表
' z' k# f, ?! z% a}
) b7 B4 o' N% s z, [}
1 ], F0 }7 h. M( {2 R' y; ^7 P) @, s- o/ I8 m
由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。1 o! X. C! q+ Y1 e5 k
0 ?/ K5 c0 W. I5 X! O
写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过“netload”命令即可选择该dll文件进行加载,加载成功后即可以通过“AddLine”命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。
5 ~. ^; ]* s3 J+ h2 S9 f
0 v; `1 G1 o% h& G, F4..NET API的初始化与清除4 `' a! s' k( C- h
5 Y* _3 a9 c9 D7 c" {6 m% c6 a
在ObjectARX中,“acrxEntryPoint”函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
* d, w, x' G, Y9 J* _; `IExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:
( {9 y% c( b+ {- c( Y
: `/ D, D3 `! Pnamespace ARXExample {
! u6 q3 q E7 B9 r, j5 L8 L! Upublic class MyARX : IExtensionApplication {$ M! p. t/ g% O/ E- w
……6 e h# o/ B% V. W
public void Initialize() {
4 {2 I! |* y5 F& P" N+ n/ r* _//初始化操作/ h: i# `, t( o# K1 B |* g, _. e% ]
} b0 c- i7 i8 a
public void Terminate() {
; j+ |& x2 J. O7 D6 k; i& b" I3 z1 ?8 X
//清除操作
, n$ t7 o* P- M}* P9 S0 j8 U0 K9 Q. N! s$ ?% }
……' k9 c( G+ A% P
}" y* ?- ^' `1 }9 g+ Z) ^; E
}
7 L' z9 {' [# Y* d7 \6 ~同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:2 l* _( d0 A0 b: Q1 x# L# g
[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
3 t9 _3 G1 I5 o( V$ j) O: c[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]0 f+ l; N! N/ u; z) @' e! a
. b) o7 \* r5 G8 [2 c1 x这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。
5 W4 T( Q( R0 U6 ]% D7 @
* }9 T, i( @6 |* j- D3 }5..NET API与COM交互操作/ m' O9 |& S: ~( F" n2 [) T
3 Z9 w( S$ x9 t4 ]% K
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。+ N$ H8 @5 }; K* \2 m2 i
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:) [) L5 e/ p+ h* e
1 V0 u" p5 ~" w4 ]
Database db = HostApplicationServices.WorkingDatabase;0 B: f" b7 C: l$ @) M
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);( b& w1 m8 T9 ^7 w
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);
2 k# {# I) ~+ X& I3 ~) _5 L- Etry {
, v9 q7 B: h1 F5 k: L! ]. D/ cAcadObject obj;
- Z& R1 i# \* t! w9 d3 B//遍历块表记录
) p( ?$ H0 I5 b$ a: i* o! @. |+ @foreach (ObjectId objId in btr) {
5 k b- @: V; ]& I, |//由ObjectId得到ActiveX中的AcadObject对象
* @0 ^/ k2 W3 O9 }; Fobj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);( k1 M* [+ Q# t6 e+ ?- \$ j$ a7 M
//为obj添加响应Modified事件+ Y: h T# W0 a. i( a) l
obj.Modified = new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);$ a c8 X _3 a, `- \
}/ v& C' h$ D0 d0 Y1 J6 J& @! X/ z
}
' o4 Q' M9 H, B3 u3 A0 Cfinally {
( q4 ~: V9 x1 O1 h: Kbtr.Close();
4 \' V! ~* A5 }2 cbt.Close();: E, E3 S7 U$ O. x: [
}
+ q) }; [9 o) Z" C+ [! V其中事件响应函数obj_Modified的表示如下所示:% n/ h- p; w! }4 A/ U- ^3 b
public static void obj_Modified(AcadObject obj) {
( s! c8 ^4 e/ ^6 kCommandLinePrompts.Message("object modified!" obj.ObjectID "\n");6 x% Q# ~2 [" H2 J* ]4 _& W
}4 n2 A" q+ f8 `! C# v
9 z F( l% T, c, |
二、结论
- g, Z o6 M$ J- h% T' O3 m/ x/ U# S+ w9 b2 M
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C 的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。 |