|  | 
 
| 众所周知,对AutoCAD进行二次开发用到的主要工具有:ObjectArx,VBA,VLisp。但它们的优缺点是显而易见的:ObjectArx功能强大,编程效率高,但它的缺点是编程者必须掌握VC++,而这门语言非常的难学;VBA和VLisp虽然简单易上手,但它们对于开发大型的程序好象无能为力。那究竟有没有一种语言能结合它们的优点而尽量避免它们的缺点呢? 回答是肯定的,那就是微软新推出的21世纪编程语言C#。关于C#的详细介绍,大家可以参考有关的文章。 C#是通过AutoCAD ActiveX 这座桥梁来和AutoCAD之间进行通讯的。AutoCAD ActiveX 使用户能够从 AutoCAD 的内部或外部以编程方式来操作 AutoCAD。它是通过将 AutoCAD 对象显示到“外部世界”来做到这一点的。一旦这些对象被显示,许多不同的编程语言和环境就可以访问它们。关于AutoCAD ActiveX 的情况,大家可以参考AutoCAD自带的帮助。
 呵呵,说了这么多无聊的,还是让我们通过一个具体的例子来说明怎样利用C#进行AutoCAD的二次开发吧。在介绍例子之前先讲一下有关的配置:
 (1)Visual Studio .net (2003和2002都可以,我用的是2002)
 
 (2)AutoCAD2000以上版本(我用的是2004)
 这个例子非常简单,就是通过C#建立的窗体来启动AutoCAD并画一条直线。下面是编程的具体步骤:
 (1)通过Visual Studio .net 建立一C#的windows应用程序。
 (2)在“解决方案资源管理器”中右击“引用”标签,在弹出的菜单中选择“添加引用”,在“添加引用”对话框中选择“com"选项卡下的下拉列表框中的“AutoCAD 2004 Type Library"项(注意:不同版本的CAD的数字不同),单击右边的“选择”按钮,最后单击下面的“确定”按钮。
 (3)在C#窗体中加入两个文本框和一个按钮,分别用于输入直线起点、终点的坐标和在CAD中画直线。下面主要解释一下添加的代码。
 (a)在程序的开头加入:using AutoCAD;//导入AutoCAD引用空间
 (b)在窗体的变量声明部分加入: private AcadApplication a;//声明AutoCAD对象
 (c)在窗体的构造函数部分加入:a=new AcadApplicationClass();//创建AutoCAD对象
 a.Visible=true;//使AutoCAD可见
 (d)在按钮的消息处理函数中加入:
 double[] startPoint=new double[3]; //声明直线起点坐标
 double[] endPoint=new double[3];//声明直线终点坐标
 string[] str=textBox1.Text.Split(',');//取出直线起点坐标输入文本框的值,文本框的输入模式为"x,y,z"
 for(int i=0;i<3;i++)
 startPoint=Convert.ToDouble(str);//将str数组转为double型
 str=textBox2.Text.Split(',');//取出直线终点坐标输入文本框的值
 for(int i=0;i<3;i++)
 endPoint=Convert.ToDouble(str);
 a.ActiveDocument.ModelSpace.AddLine(startPoint,endPoint);//在AutoCAD中画直线
 a.Application.Update();//更新显示
 好了,简单吧,你可以试着编译一下。关于上面一些语句的用法,我会在下一讲中作详细介绍。
 大家好,今天我继续给各位介绍利用C#进行AutoCAD的二次开发。在这一讲中,主要介绍上一讲例子中存在的问题。
 
 在上一次的例子中我是通过引用AutoCAD 2004 Type Library来进行C#与AutoCAD之间的通信,但这种方法存在两个致命的缺点。第一个缺点是每次调试程序的时候C#都要重新启动AutoCAD,如果调试的次数非常多(比如跟踪错误然后调试),那么编程的效率就很低,因为启动一次CAD还是需要较长的时间。相对于第一个缺点,第二个缺点则更要命。由于.NET本身的问题,Interop.AutoCAD.dll文件(就是通过它才实现了C#与AutoCAD之间的通信)存在着一些bug,因此虽然有时你的代码是完全正确的,但C#编译器还是抛出莫名其妙的错误。那不是完蛋了吗?我曾经有一阶段就因为这两个要命的东东差一点放弃了C#而想改学ObjectArx了,呵呵,不过还是运气好,我偶尔一次在网上看了一篇外国人写的文章,他专门介绍了这两个问题的解决办法。下面就来解决这两个问题。
 
 首先来看第二个难题,按以下步骤来进行:
 
 1. 随便用Visual Studio .NET建立一个C#应用程序,然后按照上一篇文章中的设置加入AutoCAD 2004 Type Library,然后不加入任何代码,编译你的程序。
 
 2. 在Visual Studio .NET命令行工具下用ildasm.exe(这个工具可以在Visual Studio .NET安装光盘中找到)把Interop.AutoCAD.dll文件(这个文件在步骤1中生成的项目的Bin\Release文件夹中)编译成中间语言Interop. AutoCAD.il。注意:在步骤1中建立的项目的编译设置为Release模式。
 
 ildasm.exe /source Interop.AutoCAD.dll /output=Interop. AutoCAD.il
 
 又要注意了:把ildasm.exe,Interop.AutoCAD.dll放在同一目录下。
 
 3.在记事本中打开Interop. AutoCAD.il文件,然后查找结尾是“SinkHelper”而开头为 ".class private auto ansi sealed _DAcad“的语句,把语句中的private 改为public,然后保存Interop. AutoCAD.il文件。
 
 4.使用ilasm.exe把Interop. AutoCAD.il文件编译为Interop.AutoCAD.dll文件,同样是在Visual Studio .NET命令行工具下进行。
 
 ilasm.exe /resource=Interop.AutoCAD.res /dll Interop.AutoCAD.il /output=Interop. AutoCAD.dll
 
 Interop.AutoCAD.res文件是在步骤1中生成的。
 
 5.显然你不愿意每次编写应用程序时都通过上一篇文章中介绍的方法来加入Interop. AutoCAD.dll,那太麻烦了。你可以用下面的方法来让程序自动加入该文件:找到C:\Program Files\Microsoft.NET\ Primary Interop Assemblies 文件夹,然后把上面生成的
 
 Interop.AutoCAD.dll文件拷贝进去。
 
 好了,第二个问题解决了,接下来看第一个。
 
 在VBA中,编程者可以使用GetObject函数来获得当前活动的AutoCAD对象,但在C#中却没有,为了这个函数我几乎把MSDN给翻遍了,然后去各种C#论坛问各位高手,结果都没得到解决,呵呵,可能国内使用C#的人比较少吧。还是在老外的论坛上看到了一篇就是讲这个问题的文章才把这个难题给解决了。使用下面的语句就可以获得当前活动的AutoCAD对象了:
 
 (AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.16")
 
 (对于CAD2000和CAD2002,则把16改为15)
 
 当然以上语句必须在AutoCAD打开的情况下才能使用,否则会发生错误,对于AutoCAD没打开的情况,可以使用上一篇文章的方法来处理。完整的连接AutoCAD与C#的源程序如下所示:
 
 using System;
 
 using AutoCAD;
 
 using System.Runtime.InteropServices;
 
 namespace AcadExample
 
 {
 
 public class AutoCADConnector : IDisposable
 
 {
 
 private AcadApplication _application;
 
 private bool _initialized;
 
 private bool _disposed;
 
 public AutoCADConnector()
 
 {
 
 try
 
 {
 
 // Upon creation, attempt to retrieve running instance
 
 _application = (AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.16");
 
 }
 
 catch
 
 {
 
 try
 
 {
 
 // Create an instance and set flag to indicate this
 
 _application = new AcadApplicationClass();
 
 _initialized = true;
 
 }
 
 catch
 
 {
 
 throw;
 
 }
 
 }
 
 }
 
 // If the user doesn't call Dispose, the
 
 // garbage collector will upon destruction
 
 ~AutoCADConnector()
 
 {
 
 Dispose(false);
 
 }
 
 
 
 public AcadApplication Application
 
 {
 
 get
 
 {
 
 // Return our internal instance of AutoCAD
 
 return _application;
 
 }
 
 }
 
 
 
 // This is the user-callable version of Dispose.
 
 // It calls our internal version and removes the
 
 // object from the garbage collector's queue.
 
 public void Dispose()
 
 {
 
 Dispose(true);
 
 GC.SuppressFinalize(this);
 
 }
 
 
 
 // This version of Dispose gets called by our
 
 // destructor.
 
 protected virtual void Dispose(bool disposing)
 
 {
 
 // If we created our AutoCAD instance, call its
 
 // Quit method to avoid leaking memory.
 
 if(!this._disposed && _initialized)
 
 _application.Quit();
 
 
 
 _disposed = true;
 
 }
 
 }
 
 }
 
 利用Visual Studio.net 把上面的程序编译成一个类库,你就可以在以后的程序中使用它了,下面的这个例子说明了它的用法。(首先把AcadExample类库包含在项目中)
 
 using System;
 
 using AcadExample;
 
 using AutoCAD;
 
 namespace ConsoleApplication6
 
 {
 
 class Class1
 
 {
 
 [STAThread]
 
 static void Main(string[] args)
 
 {
 
 using (AutoCADConnector connector = new AutoCADConnector())
 
 {
 
 Console.WriteLine(connector.Application.ActiveDocument.Name);
 
 }
 
 Console.ReadLine();
 
 }
 
 }
 
 }
 
 这个例子是在C#窗口中显示AutoCAD中当前文档的标题。
 | 
 |