CAD设计论坛

 找回密码
 立即注册
论坛新手常用操作帮助系统等待验证的用户请看获取社区币方法的说明新注册会员必读(必修)
查看: 4891|回复: 3

[开发] .NET平台的AutoCAD二次开发

[复制链接]
发表于 2006-4-16 16:10 | 显示全部楼层 |阅读模式
华南理工大学 刘林 麦智晖 阎汉生
$ [; Z' u: a9 Q) `! P1 n7 u4 X
: O" c' p' u0 ^# }6 K4 D) g- ]3 [: P& }% N3 f, m8 _
本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA、ObjectARX作了对比。同时讨论了如何弥补.NET API某些不足的功能。
- d- C" O& I& f+ l4 H9 e
% z' H, K# Z4 v7 Y  E2 K) b. p' N. l4 ?% o) p* z' C
当前AutoCAD的二次开发工具主要有:VisualLisp、VBA和ObjectARX等。其中,VisualLisp与VBA较为简单,特别是VBA,使用方便且开发速度较快,但其功能相比ObjectARX有所不足,尤其是对面向对象的功能支持不好。而ObjectARX基于VC平台,在C++的支持下,其功能非常强大,可以很好地运用各种面向对象技术,但其缺点是发开速度比较慢,同时对开发人员的能力要求较高。
; }- P) V9 H5 R) o7 ]! m  @( |+ j5 s' I, z& G$ N+ P
.NET是微软新推出的开发平台,具有众多优点。基于.NET平台对AutoCAD进行二次开发,可充分利用.NET的各种优势,在保证功能强大的前提下大大提高开发速度。* a/ o# w( c2 X6 J3 {

& C3 w4 z; ^5 ]7 g" A& R; A% H; p一、基于.NET的开发
% G" e6 ]2 ~% m1 }6 ?" Q' ]' u, U1 z. g& x0 Q
1..NET API简介+ K; d( t+ ]7 h1 G
, q5 N" M" B8 x
在新推出的AutoCAD 2006中,Autodesk为其开发增加了.NET API。.NET API提供了一系列托管的外包类(Managed Wrapper Class),使开发人员可在.NET框架下,使用任何支持.NET的语言,如VB.NET、C# 和Managed C++等对AutoCAD进行二次开发。其优点是完全面向对象,在拥有与C++相匹配的强大功能的同时,具有方便易用的特点,是较理想的AutoCAD二次开发工具。1 l3 d( i( V3 T& ]+ `7 I0 Q1 s  D
. y2 I3 ^0 Y0 ]& P
2..NET API与传统ObjectARX的主要区别+ k, C& }* D6 s: {2 F4 ~2 t3 {

# L# t" i. E5 H4 H9 N, D.NET API与传统ObjectARX的区别主要源于在.NET环境下开发应用程序与在VC环境下开发应用程序的区别。首先,在VC环境下,程序员需要自己管理内存的申请和释放,而.NET采用了垃圾回收机制,由.NET框架自行判断内存回收的时机并实行回收,从而解决了令C++程序员头痛的内存泄漏问题。也正是由于这个特点,在.NET环境下不能象在C++环境下那样利用析构函数释放其他的资源,需要程序员在程序中显式地释放。在.NET API中,主要通过Dispose来函数进行资源的释放。* S* o! J3 z# P. j$ D; G

4 A% a9 i! _  q% M& s: {9 Q其次,ObjectARX中的各种反应器(Reactor)在.NET API中由外包类映射为各种事件(Event),可通过定义这些事件的响应函数来响应AutoCAD的各种操作。同时对于错误信息的处理也从函数返回值改变为通常异常来处理,使其更好地兼容.NET。由于VB.NET、C#等语言都是完全面向对象的,没有全局函数的概念,所以.NET API将ObjectARX下的全局函数封装为.NET API下的某些对象或对象的属性,如ObjectARX下与用户交互的系列全局函数被封装为CommandLinePrompt类。4 P/ F" m1 N4 S0 o% y7 U8 d1 ]: v
. ~; s% k4 Y% N9 C2 y8 Z1 D; [
3.使用.NET API
0 Y9 v5 p2 D# c1 t3 m% M. @3 n, l3 Z4 ~9 F
下面以C#为例,在Microsoft Visual C# 2005 Express Edition Beta平台上,先新建一个Class Library项目,再将AutoCAD2005安装目录下的acdbmgb.dll与acmgb.dll作为引用添加进项目中。这两个文件包含了.NET API中所有的外包类。; y) s! L: d& W9 Q4 l
% D' l3 o% A2 f1 \
然后在要使用.NET API的类中添加以下语句以引用.NET API的命名空间。需要添加的语句如下:& ]$ P0 }  R: L# ?. Z, J
; U# r6 s* T$ j. l
using Autodesk.AutoCAD.ApplicationServices;
, s( y7 L" u6 F& u; nusing Autodesk.AutoCAD.DatabaseServices;
5 O2 T' {2 n4 d* uusing Autodesk.AutoCAD.Runtime;; V# B) ?9 D$ V% E% Q
using Autodesk.AutoCAD.Geometry;+ F) Y$ X. M0 X9 M+ F3 U0 M6 c  b
8 I1 T0 v8 u' T) A; w! ]$ ?- M
这样就可以利用.NET API进行开发了。以下代码可在AutoCAD注册为一个命令"AddLine",该命令可在当前工作空间中添加一条起点为(0,0,0),终点(200,200,0)的直线。代码如下:9 m$ O/ f/ \  I: Y1 b+ ]) z- g
8 n* m+ r5 x1 @9 v1 N: X
[CommandMethod ("AddLine")]* z( \: S* V6 s% V6 ], t4 @. ~5 R8 E
public static void AddLineCmd()8 d3 @9 |" m) T/ V' p/ y# r# S4 x
{( D1 L9 b" R+ I4 }) t
Database db = HostApplicationServices.WorkingDatabase;//获得当前工作空间的数据库& _0 V3 O5 Y; `6 U, }
BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead); //获得块表* q: y) P2 D4 t8 l1 q% D# N
BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite); //获得模型空间的块表记录( h/ S! t  o& f8 N
Line line = new Line(new Point3d(0, 0, 0), new Point3d(200, 200, 0));//创建一条直线
) G$ a* L( P# z0 [. N/ {4 ltry {; _/ L0 ~/ n* Z! u- o1 g
btr.AppendEntity(line);//将直线添加到模型空间中, y+ c3 r3 ~* N) H9 _- k2 U/ g
line.Close();//关闭该直线
* U1 n) l# C  }% [% i3 S+ b}6 l/ Q; h, F2 H# _. n" v
finally {
4 v/ |; B# W* ?% z( Cbtr.Close();//关闭块表记录# f$ B' R4 L1 H% u+ h
bt.Close();//关闭块表
; j( ?4 k# w: A' p. N}5 h. Q8 u2 }+ u& M
}. K; ?+ m/ p- {- u7 n" O% {* A

  x" g) D8 y' D, w: @由此可见,上述语句与在VC下的开发非常类似,其过程都是先得到数据库,然后依次打开块表、块表记录,接着添加实体,最后关闭块表、块表记录。值得注意的是finally语句,无论try块中的语句是否发生异常,finally块中的语句都会被执行,从而确保关闭块表和块表记录的操作会被执行。
, H/ U) e7 J/ a# c
! p/ V7 s3 n: C写完代码后进行编译,编译完成将得到一个dll文件。在AutoCAD 2006中通过"netload"命令即可选择该dll文件进行加载,加载成功后即可以通过"AddLine"命令执行上述代码。遗憾的是目前的.NET API版本还不支持卸载,若要卸载只能关闭AutoCAD。, }' m, {, }& q$ s6 k, J' s
5 z5 k( H5 Y- S( C9 \' E* e7 ?
4..NET API的初始化与清除+ K; R: [% j* ^
3 M: u. R. Z6 d9 D+ V. \7 D4 h
在ObjectARX中,"acrxEntryPoint"函数是ARX程序的载入点,程序的初始化和清除均可在该函数中进行。而在.NET API中则首先需要将初始化代码封装在一个类中,同时该类需要压迫实现
) L. k0 Y+ ~& H" Z& V- a
0 C# T9 `, H9 u; v2 c1 jIExtensionApplication接口。该接口包含Initialize与Terminate两个函数。其中Initialize负责加载程序时的初始化操作,Terminate则负责进行卸载程序时的清除操作。代码如下:* @1 b4 G; I- B1 R2 C2 a
) c6 ^) b  {9 L3 o
namespace ARXExample {; g! j& Z0 y+ B* |* R2 Q7 }
public class MyARX : IExtensionApplication {+ Y1 L3 y$ x- n; ^
……
1 y" x# g+ C1 S1 L- hpublic void Initialize() {
2 J4 P( S% \1 r//初始化操作
- t7 Z2 s, q& _1 U& p6 h+ ?3 D}
. a) c9 z! H% Y, Mpublic void Terminate() {
, z9 C* f4 a' H& e( u7 }//清除操作
& m4 u2 F0 R3 Q5 ^' [# T3 U6 O2 @}) l% v0 S9 _2 F8 G" d
……
5 }- `1 v% D* K1 R( C* R& I
# K; U( L& o+ o}
1 R) z* i, v& B
; ]3 _/ j+ p; W/ C$ l同时,为加快加载速度,可在MyARX.cs的文件头加入以下语句:
6 T7 P5 ^6 O; W4 z- @6 }' o) O. r/ R8 ]% @- ?, F9 z. o: i
[assembly: ExtensionApplication (typeof (ARXExample.MyARX) ) ]
) L/ K! n7 }0 a/ t' d5 x[assembly: CommandClass (typeof (ARXExample.MyARX) ) ]' I$ a7 ?' U" N/ |

. o3 H0 M5 r- w" _2 ?1 S5 Q这样在加载程序时AutoCAD将直接通过MyARX中的Initialize语句进行初始化,同时注册MyARX中的命令。否则,AutoCAD将搜索dll中所有的类以找到实现IExtensionApplication接口的类进行初始化,如找不到则不进行初始化。同样,通过CommandClass属性,AutoCAD也会直接到MyARX类中搜索要注册的命令。当程序中包含的类数目较多时,通过ExtensionApplication和CommandClass这两个属性可显著地加快程序的加载速度。* Z( S1 K# s/ t9 Q! t
/ o+ N2 h5 {, ~5 |6 `7 I4 L! x  w
5..NET API与COM交互操作
/ S  A6 g/ \* O# K( p& u6 w7 \3 C
在目前的.NET API中,其功能与传统的ObjectARX相比有所不及,有相当的ObjectARX函数目前还没有封装到.NET API中,如GetPoint等。但可以通过COM方式使用ActiveX来弥补.NET API的不足。
- }0 v& I! `* a6 e: D9 g. F& E9 _% r4 g& m0 [9 [( X% X
增加了COM引用后,程序就可以使用许多VBA中的功能了。以AutoCAD ActiveX中的事件为例,以下代码可以为当前工作空间中所有的图元添加Modified事件:
0 {2 _* }9 o( l3 _5 |' |3 X( i6 j7 v7 Q7 |% D
Database db = HostApplicationServices.WorkingDatabase;
0 x2 w# i" x8 [BlockTable bt = (BlockTable)db.BlockTableId.Open(OpenMode.ForRead);
5 B0 ], M3 ~' |( z' c5 EBlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite);' d+ Z& \0 ~, K( v  Y2 u! u0 x
try {
2 g6 M4 a6 Q# W0 k1 H+ e* `AcadObject obj;9 o- J3 J. K1 N: w
//遍历块表记录) r5 ^8 I4 d) S- u' p( ]  E
foreach (ObjectId objId in btr) {; B4 s) b0 J) ~1 C
//由ObjectId得到ActiveX中的AcadObject对象
$ {: F2 G9 @# J- L# W$ ?! wobj = (AcadObject)((AcadDatabase)db.AcadDatabase).ObjectIdToObject(objId.OldId);1 P$ d- |2 S6 D4 y) L8 Q( C
//为obj添加响应Modified事件5 _& L$ B  |2 @3 y9 u
obj.Modified += new IAcadObjectEvents_ModifiedEventHandler(obj_Modified);5 M8 h# N. Y1 w% i, u, H
}6 M3 u) Y* S; a0 A2 D
}! X' `* N; `6 b" F
finally {
2 a, e3 o$ d2 W3 v- c# kbtr.Close();) W( O+ y3 `: C! F" E2 u! o
bt.Close();
; v" ^6 H  H3 _/ {}' n7 I1 \& M1 x  Y8 B3 E
, T" ?1 J1 W' P/ u' K
其中事件响应函数obj_Modified的表示如下所示:" q+ ^- h, T1 L1 F

: Y! o5 ^! G/ u1 _public static void obj_Modified(AcadObject obj) {
; a# i2 d4 a1 L5 f% NCommandLinePrompts.Message("object modified!" + obj.ObjectID + "\n");7 r% ]: u* X8 z( ]9 G
}5 R6 ]8 G+ Q6 m5 S4 P. w

0 q9 E( R2 ^7 u1 I二、结论
' T/ Y! [: d3 Q7 g: b  F& r/ G# ^8 [$ u) \# _, A8 R( l
本文以C#为例,对基于.NET API的AutoCAD二次开发作了较详细的介绍。.NET API在具有ObjectARX强大功能的同时具有VBA使用方便易用的优点,同时具有C++的强大功能,是较为理想的开发工具。但目前.NET API在某些方面还有些不足,但随着其版本的更新、完善,定会成为众多开发人员的首选工具。
发表于 2006-9-22 15:49 | 显示全部楼层

谢谢!

感谢高手的指导!
' B$ {; J3 H+ z  O/ o/ V3 t够我学一年半载的了!
发表于 2007-5-15 21:12 | 显示全部楼层
最好是先介绍一下啊,我是出学者,这方面不懂.希望那位能提供一些关于二次开发方面的书.
发表于 2007-12-30 13:52 | 显示全部楼层
学开发的话,上不是LISP和VBA什么的都要学呢,还是只选其一就可以了呢
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于|免责|隐私|版权|广告|联系|手机版|CAD设计论坛

GMT+8, 2026-8-17 00:20

CAD设计论坛,为工程师增加动力。

© 2005-2026 askcad.com. All rights reserved.

快速回复 返回顶部 返回列表