利用C#进行AutoCAD的二次开发
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
利用C#进行AutoCAD的二次开发(一)转自明经通道
众所周知,对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的二次开发(二)
大家好,今天我继续给各位介绍利用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\\ 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 把上面的程序编译成一个类库,你就可以在以后的程序中使用它了,下面的这个例子说明了它的用法。
(首先把AcadExample类库包含在项目中)
using System;
using AcadExample;
using AutoCAD;
namespace ConsoleApplication6
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
using (AutoCADConnector connector = new AutoCADConnector())
{
Console.WriteLine();
}
Console.ReadLine();
}
}
}
这个例子是在C#窗口中显示AutoCAD中当前文档的标题。
利用C#进行AutoCAD的二次开发(三)
C#才鸟
这一讲的主要内容是介绍AutoCAD对象模型,如果你对VBA开发AutoCAD了解的话,这部分内容应该是超简单的。
对象是AutoCAD ActiveX 接口的主要构造块,每一个显示的对象均精确代表一个AutoCAD 组件。
AutoCAD ActiveX 接口的主要对象有:
• 直线、圆弧、文字和标注等图形对象。
• 线型与标注样式等样式设置对象
• 图层、编组和块等组织结构对象
• 视图与视口等图形显示对象。
• 图形、AutoCAD 应用程序本身也是对象
所有对象的根对象是AutoCAD 应用程序本身,它用AcadApplication类来表示。
获得当前运行的AcadApplication对象可以使用上一讲中介绍的方法来得到。
AcadApplication对象下有四个子对象构成,分别是:
υ AcadPreferences 对象,通过此对象可以访问和设置“选项”对话框中的相关选项
AcadDocuments对象,它表示AutoCADυ图形
AcadMenuBar 对象,它表示AutoCAD主菜单栏(注意不是AcadMenuBars,因为应用程序只有一个主菜单栏)υ
υ AcadMenuGroups对象, 它表示AutoCAD 菜单和工具栏
上面介绍了AutoCAD ActiveX 接口对象模型的大致组成,下面重点介绍AcadDocuments对象,因为大部分的编程都与它有关。
首先大家看到它是复数的形式,因此它是当前打开的AutoCAD所有图形的集合,这种对象称为集合对象(呵呵,好像在讲废话)。
集合对象有一些比较重要的方法和特性。
其中最主要的是:Count特性用于获取集合中的对象个数(从零开始);Item 方法用于获取集合中的任何对象。
关于它们的用法我会在下面的例子中介绍。
而AcadDocuments的单数形式AcadDocument表示当前打开的一个AutoCAD图形。
AcadDocument对象由以下几个主要对象组成:
υ AcadModelSpace 集合和AcadPaperSpace集合,提供对图形对象(直线、圆、圆弧等)的访问
υ AcadLayers、AcadLinetypes 和AcadTextStyles,则提供对非图形对象(图层、线型、文本样式等)的访问
υ AcadPlot 对象提供对“打印”对话框中设置的访问,并为应用过程提供了打印图形的各种方法
AcadUtilityυ对象提供用户输入和转换函数
图形对象的创建使用Add方法,比如要创建一个圆,就是用AddCircle方法,而非图形对象的创建使用Add方法。
下面通过一个简单的例子来说明上面介绍的内容。
这个例子是在AutoCAD中建立一个新的层,然后在该层中画一个红色的圆和一条绿色的直线。
这是程序的源代码:(请先把上一讲中生成的interop.AutoCAD.dll 和AutoCADExample.dll文件包含在工程中)
using System;
using AcadExample;
using AutoCAD;
namespace CircleLine
{
///
/// Class1 的摘要说明。
///
class Class1
{
///
/// 应用程序的主入口点。
///
[STAThread]
static void Main(string[] args)
{
//
// TODO: 在此处添加代码以启动应用程序
//
using(AutoCADConnector connector=new AutoCADConnector()) //连接AutoCAD
{
AcadDocument aDocument=connector.Application.ActiveDocument;
//取得当前AutoCAD活动图形对象
double[] center=new Double[3]{20,20,0};//设置圆心
double radius=20;//设置圆的半径
double[] startPoint=new Double[3]{0,0,0};//设置直线的起点
double[] endPoint=new Double[3]{40,40,0};//设置直线的终点
AcadLayer newLayer=yers.Add("CircleLine");
//创建一个名为CircleLine的新层
aDocument.ActiveLayer=newLayer;//把CircleLine层设置为当前层
AcadCircle circle=aDocument.ModelSpace.AddCircle(center,radius);//加入圆
AcadLine line=aDocument.ModelSpace.AddLine(startPoint,endPoint);//加入直线
circle.color=ACAD_COLOR.acRed;//把圆变为红色
line.color=ACAD_COLOR.acGreen;//把直线变为绿色
connector.Application.Update();//更新显示
for(int i=0;i Console.WriteLine("这是第{0}个对象:{1}",i+1,aDocument.ModelSpace.Item(i)); //遍历当前图形
}
Console.ReadLine();
}
}
}
好了,今天就到这里。
利用C#进行AutoCAD的二次开发(四)
---使用通用对话框看了本站出的“AutoCAD VBA 开发精彩实例教程”以后,深有启发。
但书中用到通用对话框时,总是调用windows api函数,我一看就头大了。
想到C#可以调用通用对话框,因此试验了一下,没想到在C#中可以非常容易地解决这个问题,下面就把我的做法给写出来。
本文的例子是调用颜色对话框,对于其他通用对话框做法是一样的。
但由于要使用到AutoCAD2004新增加的TrueColor属性,因此,本文所举的例子只能用于AutoCAD2004,对于其他通用对话框(如文件对话框),则可以使用其他版本的AutoCAD。
要求:
会用C#编程
读过我写的“利用C#进行AutoCAD的二次开发“(在明经通道中有)
开始:
在visual 中新建一C#控制台程序,在引用选项卡中添加下列类库:
interop.AutoCAD.dll
AcadExample.dll using System;
using System.Drawing;
using System.Collections;
using ponentModel;
using System.Windows.Forms;
using System.Data;
using AutoCAD;
using AcadExample;
namespace WindowsApplication3
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private ponentModel.Container components = null; public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent(); //
// TODO: 在InitializeComponent 调用后添加任何构造函数代码
//
} /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
} #region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法- 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(96, 112);
= "button1";
this.button1.Size = new System.Drawing.Size(64, 32);
this.button1.TabIndex = 0;
this.button1.Text = "确定";
this.button1.Click += new System.EventHandler(this.button1_Click); //
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(280, 213);
this.Controls.Add(this.button1);
= "Form1";
this.Text = "Form1";
this.ResumeLayout(false); }
#endregion /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
} private void button1_Click(object sender, System.EventArgs e)
{
AutoCADConnector connector=new AutoCADConnector();
AcadDocument document=connector.Application.ActiveDocument;
AcadAcCmColor color=(AcadAcCmColor)document.Application.GetInterfaceObject("AutoCAD.AcCmColor.16");
//新建一AcadAcCmColor对象,该对象用来给直线的颜色属性赋值
AcadLine line=document.ModelSpace.AddLine(new double[]{0,0,0},new double[]{200,200,0});
//加入直线
ColorDialog dlg=new ColorDialog();//生成一颜色对话框
if(dlg.ShowDialog()==DialogResult.OK)//显示颜色对话框,并按确定按钮后
{
color.SetRGB(dlg.Color.R,dlg.Color.G,dlg.Color.B);//设置颜色为颜色对话框中选择的颜色
line.TrueColor=color;//设置直线的颜色
}
line.Update();//更新显示
}
}
}
给AutoCAD的对象设置颜色,注意不是使用Color属性,而是使用TrueColor属性。
TrueColor属性是一个AcadAcCmColor对象,它必须使用GetInterfaceObject方法而不能用new AcadAcCmColor()方法声明。
给AcadAcCmColor对象设置颜色时,由于要使用.net颜色对话框中选择的值,因此可使用SetRGB的方法,它的三个参数分别是RGB颜色的红,绿,蓝的值。
在C#中使用ObjectDBX技术从未打开图形中获得图块的信息
C#才鸟(QQ:2491785)
从未打开图形中能获得图块的信息吗?明经通道的VBA版块已经介绍了VBA的实现方法,那在C#中能否做到呢?
回答是肯定的。
下面就来说明具体的实现方法。
要求:
会用C#编程
读过我写的“利用C#进行AutoCAD的二次开发“(在明经通道中有)
开始:
在visual 中新建一C#控制台程序
在引用选项卡中添加下列类库:
interop.AutoCAD.dll
AcadExample.dll
ObjectDBX16(在“解决方案资源管理器”中右击“引用”标签,在弹出的菜单中选择“添加引用”,在“添加引用”对话框中选择“com"选项卡下的下拉列表框中的“AutoCAD/ObjectDBX Common 16.0 Type Library"项)
然后键入以下代码:
1: using System;
2: using AutoCAD;
3: using dbx = AXDBLib;
4: using AcadExample;
5:
6: namespace ConsoleApplication1
7: {
8: /// <summary>
9: /// Summary description for Class1.
10: /// </summary>
11: class Class1
12: {
13: /// <summary>
14: /// The main entry point for the application.
15: /// </summary>
16: [STAThread]
17: static void Main(string[] args)
18: {
19: using (AutoCADConnector connector = new AutoCADConnector())
20: {
21: string progid = "ObjectDBX.AxDbDocument.16"//注意,这是AutoCAD2004的写法,
// 若是AutoCAD2002和AutoCAD2000i则是”ObjectDBX.AxDbDocument.1“
22: AcadApplication acadApp = connector.Application;
23: dbx.AxDbDocument dbxDoc;
24: dbxDoc = (dbx.AxDbDocument)acadApp.GetInterfaceObject(progid);
25: dbxDoc.Open(@"F:\Test.dwg");
26: foreach (dbx.AcadEntity entity in dbxDoc.ModelSpace)
27: {
28: if (entity.EntityName == "AcDbBlockReference")//判断实体是否是块参照
29: {
30: dbx.AcadBlockReference blkRef;
31: blkRef = (dbx.AcadBlockReference)entity; //将是块参照的实体强制转换为块参照类型
32: object[] atts = (object[])blkRef.GetAttributes();//获取块参照中的属性(为对象类型)
33: for (int i = 0; i < atts.Length; i++) //遍历块参照属性
34: {
35: dbx.AcadAttributeReference att;
36: att = (dbx.AcadAttributeReference)atts;//将块参照属性(对象类型)强制转换为块参照属性类型
37: Console.WriteLine("Tag: {0}\tValue: {1}\n",
38: att.TagString,
39: att.TextString);//显示块参照属性的Tag和Text的值
40: }
41: }
42: }
43: Console.ReadLine();
44: }
45: }
46: }
47: }
第一个要注意的是第三行,使用了一个别名。
因为AutoCAD和ObjectDBX命名空间有许多相同的类名,因此,你必须使用全名,而不能使用简写的形式,但ObjectDBX写起来比较麻烦,所以用别名dbx来使输入方便一些。
程序前面部分的代码,你可以参考我写的“利用C#进行AutoCAD的二次开发“这篇文章。
让我们来看第21行,程序定义了一个字符串progid,作为第24句的函数GetInterfaceObject的参数,该函数是用来产生一个AxDbDocument对象。
但要注意,GetInterfaceObject函数返回的类型是object,所以你必须用强制转换把它变为AxDbDocument类。
然后在第25行使用24行产生的AxDbDocument对象来”打开“一个.dwg文件(其实没有打开),需要注意的是这个文件的路径必须是正确的。
这个文件就是我们要获得的块信息所在的文件。
由于ObjectDBX 没有选择集,所以只有通过遍历文件的模型空间来获得块的信息(26-28行)。
余下语句的说明我已经写在程序的注释中了。
你可以发现ObjectDBX的工作原理在C#中与VBA是类似的,只不过要进行必要的类型转换。
二次开发AutoCAD中画圆示例
Imports Autodesk
Imports Autodesk.AutoCAD.Interop
Imports mon
imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.Geometry
Imports System
Private Sub btnCircle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCircle.Click '定义圆的圆心
Dim center As Point3d = New Point3d(100, 100, 0)
'定义圆的半径
Dim radius As Double = 50
'定义一个Circle对象来表示你要生成的圆,传入的第二个参数为圆的法向,
'就是把圆生、//成在什么面上,因为AutoCAD程序一般都是平面问题,
'因此你一般都把这个法向量定义成//z轴方向。
Dim circle As Circle
circle = New Circle(center, New Vector3d(0, 0, 1), radius)
Dim bt As BlockTable
Dim btr As BlockTableRecord
Dim db As Database
'获得当前活动AutoCAD文档所在的数据库
db = Application.DocumentManager.MdiActiveDocument.Database
'获得事务处理管理器
Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager
tm = db.TransactionManager
'定义事务处理
Dim trans As Transaction
Try
'开始事务处理,也就是往CAD中加入东西
trans = tm.StartTransaction
bt = tm.GetObject(db.BlockTableId, OpenMode.ForRead, False)
'获得块表记录
btr = tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite, False)
'向块表记录加入圆的相关信息
btr.AppendEntity(Circle)
'向AutoCAD加入圆
tm.AddNewlyCreatedDBObject(Circle, True)
mit()
Catch ex As Exception
Throw New ApplicationException(ex.Message)
End Try
end sub
(参照了明经通道里的二次开发相关内容)。