如何通过 .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)中 AcadApplicationinterface 的 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#判断文件夹是否已经打开

如何提高 .NET 插件开发的速度?

如何使用设计自动化 API 从上传的 AutoCAD 文件中提取元数据?

有没有办法使用 Forge Viewer API 在查看器上运行 Autocad 命令?

在 VB.NET 中导入 Autodesk.AutoCAD