基于COM Interop的AutoCAD二次开发如何在程序内部加载dll文件

基于COM Interop的AutoCAD二次开发如何在程序内部加载dll文件


前言

我的上一篇文章已经介绍了如何通过COM Interop创建一个独立的AuoCAD二次开发应用程序。但是在开发过程感觉有些吃力,一方面是对这种开发方式运用还不熟练,另一方面是这种方法网上的资料真的很少。而基于.net api来开发AutoCAD的资料却很多,但是这种方式只能编译出一个dll文件,用起来不是很方便。于是我灵机一动,能否用COM Interop方式做主界面,然后在程序内部调用.net api方式生成的dll文件呢?嘿嘿,好一个围魏救赵,曲线救国…


一、开发工具

我使用的是 Visual Studio 2017 + AutoCAD 2019 + .NET Framework 4.7.2。版本不是重点,可根据自己实际来选择。

二、通过.net api创建类库项目

(一)新建项目

打开Visual Studio,新建一个类库(.Net Framework)项目。
在这里插入图片描述

(二)添加引用

  1. 选择创建的项目然后右键→添加→引用→浏览,在弹出的窗口中找到AutoCAD安装目录,依次添加accoremgd、AcCui、acdbmgd、acmgd这4个dll文件。注意:我用的是 AutoCAD 2019对应这4个类库文件,其它低版本可能只有其中3个,可自行去网上查询。
    在这里插入图片描述
  2. 选中这4个引用,在属性栏中将复制本地属性改为false。
    在这里插入图片描述
  3. 选择创建的项目然后右键→属性→调试,启动操作一栏选择启动外部程序,点击浏览并定位到AutoCAD安装目录,选择AutoCAD主程序“acad.exe”文件。
    在这里插入图片描述

(三)代码编写

回到Class1.cs代码编辑界面,添加如下代码:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

namespace DrawCircle
{
    public class Class1
    {
        [CommandMethod("Drawcircle")]//注册一个CAD命令
        public void drawcircle()
        {
            Transaction trans = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction();
            BlockTable bt = (BlockTable)trans.GetObject(HostApplicationServices.WorkingDatabase.BlockTableId, OpenMode.ForRead);
            BlockTableRecord btr = (BlockTableRecord)trans.GetObject(HostApplicationServices.WorkingDatabase.CurrentSpaceId, OpenMode.ForWrite);
            Circle circle = new Circle(new Point3d(0, 0, 0), Vector3d.ZAxis, 100);
            btr.AppendEntity(circle);
            trans.AddNewlyCreatedDBObject(circle, true);
            trans.Commit();
            trans.Dispose();
        }
    }
}

(四)运行调试

在Visual Studio界面点击运行按钮,此时AutoCAD会自动打开。在CAD界面输入命令“netload”,定位到本项目“…\bin\Debug”文件夹,选择生成的"DrawCircle.dll"文件,然后点击打开按钮。在弹出的安全性窗口中选择“始终加载”。在CAD界面输入命令“Drawcircle”,然后就能在CAD中生成一个如下图所示的圆。至此,已经成功通过.net api生成了dll文件,且该dll文件运行无误。

在这里插入图片描述
在这里插入图片描述

三、通过COM Interop窗体应用

(一)新建项目

打开Visual Studio,新建一个Windows 窗体应用(.Net Framework)。
在这里插入图片描述

(二)添加引用

选择创建的项目然后右键→添加→引用,在弹出的窗口中选择COM目录下的AutoCAD 20xx Type Library。我安装的是AutoCAD 2019,所以这里就选AutoCAD 2019 Type Library。注意:这里出现了多个AutoCAD 2019 Type Library选项,勾选第一个就行。然后点击确定。
在这里插入图片描述

(三)窗体布局

由于本次只是为了验证在程序内部加载dll功能,因此窗体只是简单的添加了两个Button,如下图:
在这里插入图片描述

(四)代码编写

  1. 添加引用AutoCAD 命名空间(using AutoCAD),申明3个全局变量(acadApp、doc、modelSpace)为后面开发做准备。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AutoCAD;

namespace LoadDllFile
{
    public partial class Form1 : Form
    {
        private AcadApplication acadApp;
        private AcadDocument doc;
        private AcadModelSpace modelSpace;
        public Form1()
        {
            InitializeComponent();
        }
    }
}
  1. 回到窗体设计界面,双击“Start”按钮,在弹出的button1_Click事件中添加如下代码:
 private void button1_Click(object sender, EventArgs e)
        {
            if (!isCADopen())//如果AutoCAD没有打开
            {
                OpenAutoCAD();
            }
            if (acadApp == null)
            {
                acadApp = (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application.23");//避免acadApp=null而报错
            }
            int count = acadApp.Documents.Count;//如果用户只打开了CAD但是没有打开文档(通过count值判断),则需要新建一个空白文档          
            if (count == 0)
            {
                doc = acadApp.Documents.Add("acad.dwt");
            }
            else
            {
                doc = acadApp.ActiveDocument;
            }
            int secureLoad = (int)doc.GetVariable("SECURELOAD");
            if (secureLoad != 0)
            {
                DialogResult dr = MessageBox.Show($"当前系统安全级别过高(安全级别:{secureLoad}),无法自动加载插件。请确认是否降低安全级别?", "提示",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (dr == DialogResult.Yes)
                {
                    doc.SendCommand("(setvar \"SECURELOAD\" 0) ");
                }
                else
                {
                    goto remark;
                }
            }
            string path = @"E:\Demo\DrawCircle\DrawCircle\bin\Debug\DrawCircle.dll";
            string dllPath = path.Replace("\\", "\\\\");
            string command = $"(command \"netload\" \"{dllPath}\")" + " ";
            doc.SendCommand(command);
            doc.SendCommand("DRAWCIRCLE" + "\n");
            acadApp.ZoomAll();           
        remark:;
        }
        public bool isCADopen()
        {
            Process[] processes = Process.GetProcesses();
            foreach (Process process in processes) // 遍历每个进程,检查进程名称是否为 "acad(AutoCAD的进程名)
            {
                if (process.ProcessName.Equals("acad", StringComparison.OrdinalIgnoreCase)) return true;
            }
            return false;
        }

        public AcadApplication OpenAutoCAD()
        {
            try
            {
                acadApp = (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application.23"); // 版本23代表AutoCAD 2019               
                return acadApp;
            }
            catch
            {
                acadApp = new AcadApplication(); // 未找到实例则启动新进程
                acadApp.Visible = true;
                acadApp.WindowState = AutoCAD.AcWindowState.acMax;//窗口最大化              
                return acadApp;
            }
        }

简单说明:

  • secureLoad表示当前CAD的安全级别,其值0、1、2分别代表“关”、“中等”、“高”。
    在这里插入图片描述
    secureLoad的值为1或2时,调用“netload”命令加载dll文件时会弹出系统提示窗口,阻断程序运行。因此需要提前将secureLoad的值设置为0。
    在这里插入图片描述
  • path表示dll文件的路径,但是在CAD中这个路径中的“\”需要转义,dllPath为转义后的路径。
  • 成功加载dll后,通过SendCommand方法调用dll中注册的方法。
  1. 回到窗体设计界面,双击“Exit”按钮,在弹出的button2_Click事件中添加如下代码:
 private void button2_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

(五)运行调试

在Visual Studio界面点击运行按钮,系统会弹出我们自定义的窗体。点击“Start”按钮,此时:

  • 若AutoCAD没有打开,则程序会先打开AutoCAD并新建一个空白文档;
  • 若AutoCAD已经打开,则程序会直接执行后续操作。

执行途中程序会弹出一个MessageBox用于提示用户是否同意降低安全级别,如下图:
在这里插入图片描述

  • 若用户点击“是”,则会成功加载指定的dll文件并运行,最终在模型空间绘制一个圆;
  • 若用户点击“否”,则不会执行任何操作。

在这里插入图片描述

至此,已经成功完成在程序内部自动加载dll文件。其核心操作是先通过 SendCommand方法将secureLoad值设置为0。然后通过 SendCommand方法调用AutoCAD中的“netload”指令。

值得一提的是,DeepSeak给出了另一种改变secureLoad值方法,不需要使用SendCommand,代码如下:

acadApp.ActiveDocument.SetVariable("SECURELOAD", 0);

然而实际运行中会报错,目前还没找到原因(也许是AI自己编造的方法?),有兴趣的童鞋可以帮忙研究下。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

98岁拄杖冲浪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值