如何通过 .NET API 打开 AutoCAD 2015
Posted
技术标签:
【中文标题】如何通过 .NET API 打开 AutoCAD 2015【英文标题】:How can I open AutoCAD 2015 through the .NET API 【发布时间】:2014-08-14 21:53:49 【问题描述】:我已经浏览了一个小时,但还没有找到可以对此有所帮助的东西。我正在使用 C# 从 VS2013 中的 .NET API 打开 AutoCAD,但由于某种原因,我永远无法真正启动 AutoCAD。我正在使用以下代码:
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
namespace IOAutoCADHandler
public static class ACADDocumentManagement
[CommandMethod("ConnectToAcad")]
public static void ConnectToAcad()
AcadApplication acAppComObj = null;
// no version number so it will run with any version
const string strProgId = "AutoCAD.Application";
// Get a running instance of AutoCAD
try
acAppComObj = (AcadApplication)Marshal.GetActiveObject(strProgId);
catch // An error occurs if no instance is running
try
// Create a new instance of AutoCAD
acAppComObj = (AcadApplication)Activator.CreateInstance(Type.GetTypeFromProgID(strProgId), true);
catch //// STOPS HERE
// If an instance of AutoCAD is not created then message and exit
// NOTE: always shows this box and never opens AutoCAD
System.Windows.Forms.MessageBox.Show("Instance of 'AutoCAD.Application'" +
" could not be created.");
return;
// Display the application and return the name and version
acAppComObj.Visible = true;
System.Windows.Forms.MessageBox.Show("Now running " + acAppComObj.Name +
" version " + acAppComObj.Version);
// Get the active document
AcadDocument acDocComObj;
acDocComObj = acAppComObj.ActiveDocument;
// Optionally, load your assembly and start your command or if your assembly
// is demandloaded, simply start the command of your in-process assembly.
acDocComObj.SendCommand("(command " + (char)34 + "NETLOAD" + (char)34 + " " +
(char)34 + @"C:\Users\Administrator\Documents\All Code\main-libraries\IOAutoCADHandler\bin\Debug\IOAutoCADHandler.dll" + (char)34 + ") ");
acDocComObj.SendCommand("DRAWCOMPONENT");
不幸的是,它总是在嵌套的catch
语句处停止,并且总是在不打开 AutoCAD 的情况下显示弹出框。关于如何至少让 AutoCAD 为我打开的任何建议?
编辑:错误消息
【问题讨论】:
您对确切的问题不是很准确。无论如何,有几个建议:将“catch”语句更改为“catch (Exception e1)”和“catch (Exception e2)”。在 Visual Studio 调试器下运行程序,并在每个 catch 子句的第一条语句上放置断点。当异常被捕获时,你应该能够看到异常的确切类型,这应该(希望)给你一些线索。 @RenniePet 是的,意识到这一点并包含错误输出。 您是否将其作为 NETLOADed DLL 运行?如果是,那么 Application 对象是Autodesk.AutoCAD.ApplicationServices.Application
如果不是,那么 [CommandMethod("ConnectToAcad")]
属性会让我们感到困惑。
我是 CAD 专家,你为什么要把进程内和互操作混在一起?如果需要,您可以将两者放在同一个程序集中,但我会将它们排除在相同的类和命名空间之外。
检查这个常见的新手错误:所有 AutoCAD 参考都需要将“本地复制”设置为 false。我们都做到了。
【参考方案1】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Tekkit
class Program
static void Main(string[] args)
//make sure to add last 2 using statements
ProcessStartInfo start = new ProcessStartInfo("calc.exe");
Process.Start(start);//starts the process
【讨论】:
是的...但是之后从正在运行的实例中获取自动化对象并非易事(需要反复遍历全局对象表,直到出现您要查找的内容)。您还缺少通过在注册表中查找其 LocalServer32 键来获取进程路径的代码。以及 DCOM 远程处理服务器在通过 COM 以正常方式启动时传递给应用程序的-Embedding
标志。
比遍历表更糟糕的是,ROT 只注册第一个启动的实例。因此,如果您打开了多个会话,您将只能使用第一个会话,到那时谁知道是哪个会话。我实际上在我的一个产品中使用了它,但是如果一个会话已经打开或者有多个会话打开,我会提示用户并从那里开始。我不玩游戏。【参考方案2】:
我以非常直接的方式打开应用程序。首先,一定要引用正确的类型库。我使用的是 AutoCAD 2014 类型库,位于: c:\program files\common files\autodesk shared\acax19enu.tlb
初始化应用程序:
using AutoCAD;
namespace test
class Program
static void Main(string[] args)
AutoCAD.AcadApplication app;
app = new AcadApplication();
app.Visible = true;
Console.Read();
【讨论】:
【参考方案3】:问题是您正在(正确地)编码到 AutoCAD 互操作界面。我建议不要这样做(由于潜在的版本更改)。
另一个问题是使用较新的 .net api 的 AutoCAD 插件的文档适用于 AutoCAD 已经运行时的插件。
最后一个问题可能是 AutCAD 的程序 ID 是个谜。我已将其设为可配置设置,但默认为“AutoCAD.Application”,它将在生产机器上采用当前注册的 AutoCAD.Application。如果机器上安装了多个版本并且您想要具体,那么您可以将版本号(您需要研究)附加到 ProgID,例如:“AutoCAD.Application.19”或“AutoCAD.Application .20" 为 2015 年。
对于第一个问题,一种技术是对 autoCad 对象使用动力学,特别是在创建实例时。我使用 ObjectARX api 在一个虚拟项目中创建我的应用程序,然后当我对属性和方法名称感到满意时切换到动态。
在启动 AutoCAD 的独立 .Net 应用程序中,您可以使用以下内容:
// I comment these out in production
//using Autodesk.AutoCAD.Interop;
//using Autodesk.AutoCAD.Interop.Common;
//...
//private static AcadApplication _application;
private static dynamic _application;
static string _autocadClassId = "AutoCAD.Application";
private static void GetAutoCAD()
_application = Marshal.GetActiveObject(_autocadClassId);
private static void StartAutoCad()
var t = Type.GetTypeFromProgID(_autocadClassId, true);
// Create a new instance Autocad.
var obj = Activator.CreateInstance(t, true);
// No need for casting with dynamics
_application = obj;
public static void EnsureAutoCadIsRunning(string classId)
if (!string.IsNullOrEmpty(classId) && classId != _autocadClassId)
_autocadClassId = classId;
Log.Activity("Loading Autocad: 0", _autocadClassId);
if (_application == null)
try
GetAutoCAD();
catch (COMException ex)
try
StartAutoCad();
catch (Exception e2x)
Log.Error(e2x);
ThrowComException(ex);
catch (Exception ex)
ThrowComException(ex);
【讨论】:
【参考方案4】:当计算机上安装了多个版本的 AutoCAD 时,使用 ProgID“AutoCAD.Application”创建实例将运行当前用户在此计算机上启动的最新版本。如果使用的互操作程序集的版本与正在启动的版本不匹配,您将收到带有 HRESULT 0x80004002 (E_NOINTERFACE) 的 System.InvalidCastException。
在您的具体情况下,错误消息中的 070AA05D-DFC1-4E64-8379-432269B48B07 IID 是 R19 64 位(AutoCAD 2013 和 2014)中 AcadApplication
interface 的 GUID。所以有一个 AutoCAD 2013 或 2014 正在启动,并且您不能将此 COM 对象转换为 2015 类型,因为 2015 是 R20(不兼容二进制)。
为避免这种情况,您可以将特定版本添加到 ProgID(例如 AutoCAD 2015 (R20.0) 到 2016 (R20.1) 的“AutoCAD.Application.20”)以启动与您的互操作程序集匹配的版本或您可以使用后期绑定(例如,删除对 Autodesk.AutoCAD.Interop* 的引用并使用 dynamic
关键字而不是 AutoCAD 类型)。
在最后一种情况下,您将失去自动完成功能,但您的程序将适用于所有版本的 AutoCAD。
还要检查 32 位和 64 位,因为 TypeLib/Interop 程序集不一样。
【讨论】:
【参考方案5】:试试这个:
“sourcefile”是原始文件 “newfile”是新文件
[CommandMethod("ModifyAndSaveas", CommandFlags.Redraw | CommandFlags.Session)]
public void ModifyAndSaveAs()
Document acDoc = Application.DocumentManager.Open(sourcefile);
Database acDB = acDoc.Database;
Transaction AcTran = acDoc.Database.TransactionManager.StartTransaction();
using (DocumentLock acLckDoc = acDoc.LockDocument())
using (AcTran)
BlockTable acBLT = (BlockTable)AcTran.GetObject(acDB.BlockTableId, OpenMode.ForRead);
BlockTableRecord acBLTR = (BlockTableRecord)AcTran.GetObject(acBLT[BlockTableRecord.ModelSpace], OpenMode.ForRead);
var editor = acDoc.Editor;
var SelectionSet = editor.SelectAll().Value;
foreach (ObjectId id in SelectionSet.GetObjectIds())
Entity ent = AcTran.GetObject(id, OpenMode.ForRead) as Entity;
//modify entities
AcTran.Commit();
acDB.SaveAs(newfile, DwgVersion.AC1021);
【讨论】:
以上是关于如何通过 .NET API 打开 AutoCAD 2015的主要内容,如果未能解决你的问题,请参考以下文章
AutoCAD二次开发——AutoCAD.NET API开发环境搭建
AutoCAD.Net/C#.Net QQ群:193522571 C#判断文件夹是否已经打开
如何使用设计自动化 API 从上传的 AutoCAD 文件中提取元数据?