cad c# 二次开发 ——动态加载dll 文件制作(loada netloadx)

原理:制作一个dll工具,此dll工具可动态加载调试代码所生成的dll。

cs 复制代码
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using LoadaDotNet;
namespace load
{
  public class Class1
  {
    private bool ev = false;
    [CommandMethod("netloadx")]
        public void Netloadx()//输入netloadx可动态加载程序的二进制文件
        {
            //IL_0017: Unknown result type (might be due to invalid IL or missing references)
            //IL_001d: Expected O, but got Unknown
            //IL_0036: Unknown result type (might be due to invalid IL or missing references)
            //IL_003c: Invalid comparison between Unknown and I4
            Editor editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            string text = "山水qq443440204";
            OpenFileDialog val = new OpenFileDialog();
            ((FileDialog)val).Filter = "dll文件(*.dll)|*.dll";
            ((FileDialog)val).Title = "打开dll文件";
            if ((int)((CommonDialog)val).ShowDialog() != 1)
            {
                return;
            }

            text = ((FileDialog)val).FileName;
            AssemblyDependent assemblyDependent = new AssemblyDependent(text);
            bool flag = true;
            AssemblyDependent.LoadDllMessage[] array = assemblyDependent.Load().ToArray();
            foreach (AssemblyDependent.LoadDllMessage loadDllMessage in array)
            {
                if (!loadDllMessage.LoadYes)
                {
                    editor.WriteMessage("\n" + loadDllMessage.Path + "失败!");
                    flag = false;
                }
            }

            if (flag)
            {
                editor.WriteMessage("\n加载成功!\n");
            }
        }
        [CommandMethod("ww")]
        public void ww()//输入ww可自动加载目录下的ifoxdemo
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var ad = new AssemblyDependent(@"G:\Csharp\Ifox\IfoxDemo\IfoxDemo\bin\Debug\net48\IfoxDemo.dll");  //写上你dll的路径
            var msg = ad.Load();

            bool allyes = true;
            foreach (var item in msg)
            {
                if (!item.LoadYes)
                {
                    ed.WriteMessage("\n**" + item.Path + "**重复版本号,无需再次加载!" + System.Environment.NewLine);
                    allyes = false;
                }
            }
            if (allyes)
            {
                ed.WriteMessage("\n加载成功!\n");
            }
            if (!ev) { System.AppDomain.CurrentDomain.AssemblyResolve += RunTimeCurrentDomain.DefaultAssemblyResolve; ev = true; }

        }
        [CommandMethod("www")]
        public void www()//输入www自动加载路径下的demo.dll
        {
          var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
          var db = doc.Database;
          var ed = doc.Editor;
          var ad = new AssemblyDependent(@"G:\Csharp\Demo\Demo\bin\Debug\Demo.dll");  //写上你dll的路径
          var msg= ad.Load();

          bool allyes = true;
          foreach (var item in msg)
          {
            if (!item.LoadYes)
            {
              ed.WriteMessage("\n**" + item.Path +"**重复版本号,无需再次加载!" + System.Environment.NewLine);
              allyes = false;
            }
          }
          if (allyes)
          {
            ed.WriteMessage( "\n加载成功!\n");
          }
          if (!ev) { System.AppDomain.CurrentDomain.AssemblyResolve += RunTimeCurrentDomain.DefaultAssemblyResolve; ev = true; }
     
    }

        [CommandMethod("sxcx")]
        public void 属性查询()//输入sxcs可查询实体属性
        {
            List<Entity> ents = SelectEntities<Entity>();
            if (ents is null || ents.Count == 0)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("未选择!\n");
                return;
            }
            object obj = ents[0];
            string str = "";
            str += "对象全部属性:   \n";
            str += "类型:    " + obj.GetType() + "\n";
            PropertyInfo[] pis = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in pis)
            {
                try { str += pi.Name + " :    " + pi.GetValue(obj, null).ToString() + "\n"; }
                catch { str += pi.Name + "     " + "Null" + "\n"; }
            }
            str += "\n";
            //MessageBox.Show(str);
            TextForm f = new TextForm();
            f.richTextBox1.Text = str;
            Autodesk.AutoCAD.ApplicationServices.Application.ShowModalDialog(f);
        }
        public  List<T> SelectEntities<T>() where T : Entity
        {
            List<T> result = new List<T>();
            Editor editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            var pso = new PromptSelectionOptions();
            pso.MessageForAdding = "\n请选择:";
            PromptSelectionResult psr = editor.GetSelection(pso);
            if (psr.Status == PromptStatus.OK)
            {
                ObjectId[] objectids = psr.Value.GetObjectIds();
                Database database = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = database.TransactionManager.StartTransaction())
                {
                    foreach (var item in objectids)
                    {
                        Entity entity = item.GetObject(OpenMode.ForRead) as Entity;
                        if (entity is T)
                        {
                            result.Add(entity as T);
                        }

                    }
                }
            }
            return result;
        }

    }
}

第二个:

cs 复制代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace load
{
  [Serializable]
  public class AssemblyDependent : IDisposable
  {
    string _dllFile;
    /// <summary>
    /// cad程序域依赖_内存区(不可以卸载)
    /// </summary>
    private Assembly[] _cadAs;

    /// <summary>
    /// cad程序域依赖_映射区(不可以卸载)
    /// </summary>
    private Assembly[] _cadAsRef;

    /// <summary>
    /// 加载DLL成功后获取到的程序集
    /// </summary>
    public List<Assembly> MyLoadAssemblys { get; private set; }

    /// <summary>
    /// 当前域加载事件,运行时出错的话,就靠这个事件来解决
    /// </summary>
    public event ResolveEventHandler CurrentDomainAssemblyResolveEvent
    {
      add
      {
        AppDomain.CurrentDomain.AssemblyResolve += value;
      }
      remove
      {
        AppDomain.CurrentDomain.AssemblyResolve -= value;
      }
    }

    /// <summary>
    /// 链式加载dll依赖
    /// </summary>
    /// <param name="dllFile"></param>
    public AssemblyDependent(string dllFile)
    {
      _dllFile = Path.GetFullPath(dllFile);//相对路径要先转换 Path.GetFullPath(dllFile);

      //cad程序集的依赖
      _cadAs = AppDomain.CurrentDomain.GetAssemblies();

      //映射区
      _cadAsRef = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies();

      //被加载的都存放在这里
      MyLoadAssemblys = new List<Assembly>();
    }

    /// <summary>
    /// 返回的类型,描述加载的错误
    /// </summary>
    public class LoadDllMessage
    {
      public string Path;
      public bool LoadYes;

      public LoadDllMessage(string path, bool loadYes)
      {
        Path = path;
        LoadYes = loadYes;
      }

      public override string ToString()
      {
        if (LoadYes)
        {
          return "加载成功:" + Path;
        }
        return "加载失败:" + Path;
      }
    }
    /// <summary>
    /// 加载信息集合
    /// </summary>
    List<LoadDllMessage> LoadYesList;


    bool _byteLoad;
    /// <summary>
    /// 加载程序集
    /// </summary>
    /// <param name="byteLoad">true字节加载,false文件加载</param>
    /// <returns>返回加载链的</returns>
    public List<LoadDllMessage> Load(bool byteLoad = true)
    {
      _byteLoad = byteLoad;
      if (!File.Exists(_dllFile))
      {
        throw new ArgumentNullException("路径不存在");
      }
      LoadYesList = new List<LoadDllMessage>();

      //查询加载链之后再逆向加载,确保前面不丢失
      var allRefs = GetAllRefPaths(_dllFile);
      allRefs.Reverse();

      foreach (var path in allRefs)
      {
        try
        {
          //路径转程序集名
          string assName = AssemblyName.GetAssemblyName(path).FullName;
          //路径转程序集名
          var assembly = _cadAs.FirstOrDefault(a => a.FullName == assName);
          if (assembly != null)
          {
            LoadYesList.Add(new LoadDllMessage(path, false));//版本号没变不加载
            continue;
          }

          byte[] buffer = null;
          bool flag = true;
          //实现字节加载
          if (path == _dllFile)
          {
            LoadOK = true;
          }
#if DEBUG
          //为了实现Debug时候出现断点,见链接,加依赖
          // https://www.cnblogs.com/DasonKwok/p/10510218.html
          // https://www.cnblogs.com/DasonKwok/p/10523279.html

          var dir = Path.GetDirectoryName(path);
          var pdbName = Path.GetFileNameWithoutExtension(path) + ".pdb";
          var pdbFullName = Path.Combine(dir, pdbName);
          if (File.Exists(pdbFullName) && _byteLoad)
          {
            var pdbbuffer = File.ReadAllBytes(pdbFullName);
            buffer = File.ReadAllBytes(path);
            var ass = Assembly.Load(buffer, pdbbuffer);
            MyLoadAssemblys.Add(ass);
            flag = false;
          }
#endif
          if (flag)
          {
            Assembly ass = null;
            if (_byteLoad)
            {
              buffer = File.ReadAllBytes(path);
              ass = Assembly.Load(buffer);
            }
            else
            {
              ass = Assembly.LoadFile(path);
            }
            MyLoadAssemblys.Add(ass);
          }
          LoadYesList.Add(new LoadDllMessage(path, true));//加载成功
        }
        catch
        {
          LoadYesList.Add(new LoadDllMessage(path, false));//错误造成
        }
      }
      MyLoadAssemblys.Reverse();
      return LoadYesList;
    }

    //链条后面的不再理会,因为相同的dll引用辨识无意义
    /// <summary>
    /// 第一个dll加载是否成功
    /// </summary>
    public bool LoadOK { get; private set; }

    /// <summary>
    /// 加载出错信息
    /// </summary>
    public string LoadErrorMessage
    {
      get
      {
        var sb = new StringBuilder();
        bool allyes = true;
        foreach (var item in LoadYesList)
        {
          if (!item.LoadYes)
          {
            sb.Append(Environment.NewLine + "** 此文件已加载过,重复名称,重复版本号,本次不加载!");
            sb.Append(Environment.NewLine + item.ToString());
            sb.Append(Environment.NewLine);
            allyes = false;
          }
        }
        if (allyes)
        {
          sb.Append(Environment.NewLine + "** 链式加载成功!");
          sb.Append(Environment.NewLine);
        }
        return sb.ToString();
      }
    }

    /// <summary>
    /// 获取加载链
    /// </summary>
    /// <param name="dll"></param>
    /// <param name="dlls"></param>
    /// <returns></returns>
    List<string> GetAllRefPaths(string dll, List<string> dlls = null)
    {
      if (dlls == null)
      {
        dlls = new List<string>();
      }
      if (dlls.Contains(dll) || !File.Exists(dll))
      {
        return dlls;
      }
      dlls.Add(dll);

      //路径转程序集名
      string assName = AssemblyName.GetAssemblyName(dll).FullName;

      //在当前程序域的assemblyAs内存区和assemblyAsRef映射区找这个程序集名
      Assembly assemblyAs = _cadAs.FirstOrDefault(a => a.FullName == assName);
      Assembly assemblyAsRef;

      //内存区有表示加载过
      //映射区有表示查找过但没有加载(一般来说不存在.只是debug会注释掉Assembly.Load的时候用来测试)
      if (assemblyAs != null)
      {
        assemblyAsRef = assemblyAs;
      }
      else
      {
        assemblyAsRef = _cadAsRef.FirstOrDefault(a => a.FullName == assName);

        //内存区和映射区都没有的话就把dll加载到映射区,用来找依赖表
        if (assemblyAsRef == null)
        {
          // assemblyAsRef = Assembly.ReflectionOnlyLoad(dll); 没有依赖会直接报错
          var byteRef = File.ReadAllBytes(dll);
          assemblyAsRef = Assembly.ReflectionOnlyLoad(byteRef);
        }
      }

      //遍历依赖,如果存在dll拖拉加载目录就加入dlls集合
      foreach (var assemblyName in assemblyAsRef.GetReferencedAssemblies())
      {
        //dll拖拉加载路径-搜索路径(可以增加到这个dll下面的所有文件夹?)
        string directoryName = Path.GetDirectoryName(dll);

        var path = directoryName + "\\" + assemblyName.Name;
        var paths = new string[]
        {
                    path + ".dll",
                    path + ".exe"
        };
        foreach (var patha in paths)
        {
          GetAllRefPaths(patha, dlls);
        }
      }
      return dlls;
    }



    /// <summary>
    /// 递归删除文件夹目录及文件
    /// </summary>
    /// <param name="dir"></param>
    /// <returns></returns>
    static void DeleteFolder(string dir)
    {
      if (Directory.Exists(dir)) //如果存在这个文件夹删除之
      {
        foreach (string d in Directory.GetFileSystemEntries(dir))
        {
          if (File.Exists(d))
            File.Delete(d); //直接删除其中的文件
          else
            DeleteFolder(d); //递归删除子文件夹
        }
        Directory.Delete(dir, true); //删除已空文件夹
      }
    }

    /// <summary>
    /// Debug的时候删除obj目录,防止占用
    /// </summary>
    public void DebugDelObjFiles()
    {
      try
      {
        var filename = Path.GetFileNameWithoutExtension(_dllFile);
        var path = Path.GetDirectoryName(_dllFile);

        var pdb = path + "\\" + filename + ".pdb";
        if (File.Exists(pdb))
        {
          File.Delete(pdb);
        }

        var list = path.Split('\\');
        if (list[list.Length - 1] == "Debug" && list[list.Length - 2] == "bin")
        {
          var bin = path.LastIndexOf("bin");
          var proj = path.Substring(0, bin);
          var obj = proj + "obj";
          DeleteFolder(obj);
        }
      }
      catch
      { }
    }



    #region Dispose
    public bool Disposed = false;

    /// <summary>
    /// 显式调用Dispose方法,继承IDisposable
    /// </summary>
    public void Dispose()
    {
      //由手动释放
      Dispose(true);
      //通知垃圾回收机制不再调用终结器(析构器)_跑了这里就不会跑析构函数了
      GC.SuppressFinalize(this);
    }

    /// <summary>
    /// 析构函数,以备忘记了显式调用Dispose方法
    /// </summary>
    ~AssemblyDependent()
    {
      //由系统释放
      Dispose(false);
    }


    /// <summary>
    /// 释放
    /// </summary>
    /// <param name="ing"></param>
    protected virtual void Dispose(bool ing)
    {
      if (Disposed)
      {
        //不重复释放
        return;
      }
      //让类型知道自己已经被释放
      Disposed = true;

      GC.Collect();
    }
    #endregion
  }
}

第三个:

cs 复制代码
using System;
using System.Linq;
using System.Reflection;

namespace load
{
  public static class RunTimeCurrentDomain
  {
    #region  程序域运行事件 
    // 动态编译要注意所有的引用外的dll的加载顺序
    // cad2008若没有这个事件,会使动态命令执行时候无法引用当前的程序集函数
    // 跨程序集反射
    // 动态加载时,dll的地址会在系统的动态目录里,而它所处的程序集(运行域)是在动态目录里.
    // netload会把所处的运行域给改到cad自己的,而动态编译不通过netload,所以要自己去改.
    // 这相当于是dll注入的意思,只是动态编译的这个"dll"不存在实体,只是一段内存.

    /// <summary>
    /// 程序域运行事件
    /// </summary>   
    public static Assembly DefaultAssemblyResolve(object sender, ResolveEventArgs args)
    {
      var cad = AppDomain.CurrentDomain.GetAssemblies();

      /*获取名称和版本号都一致的,调用它*/
      Assembly load = null;
      load = cad.FirstOrDefault(a => a.GetName().FullName == args.Name);
      if (load == null)
      {
        /*获取名称一致,但是版本号不同的,调用最后的可用版本*/
        var ag = args.Name.Split(',')[0];
        //获取 最后一个符合条件的,
        //否则a.dll引用b.dll函数的时候,b.dll修改重生成之后,加载进去会调用第一个版本的b.dll            
        foreach (var item in cad)
        {
          if (item.GetName().FullName.Split(',')[0] == ag)
          {
            //为什么加载的程序版本号最后要是*
            //因为vs会帮你迭代这个版本号,所以最后的可用就是循环到最后的.
            load = item;
          }
        }
      }
      return load;
    }
    #endregion
  }
}

第四个sxcx:

cs 复制代码
namespace LoadaDotNet
{
    partial class TextForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            // 
            // richTextBox1
            // 
            this.richTextBox1.Location = new System.Drawing.Point(11, 11);
            this.richTextBox1.Margin = new System.Windows.Forms.Padding(2);
            this.richTextBox1.Name = "richTextBox1";
            this.richTextBox1.Size = new System.Drawing.Size(455, 947);
            this.richTextBox1.TabIndex = 0;
            this.richTextBox1.Text = "";
            // 
            // TextForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(477, 969);
            this.Controls.Add(this.richTextBox1);
            this.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Margin = new System.Windows.Forms.Padding(2);
            this.Name = "TextForm";
            this.Text = "属性查询 (山水443440204)";
            this.TransparencyKey = System.Drawing.Color.White;
            this.ResumeLayout(false);

        }

        #endregion

        public System.Windows.Forms.RichTextBox richTextBox1;
    }
}

(咨询收费)联系↓↓↓

相关推荐
yongshao87 小时前
C#上位机通过NetToPLCsim与西门子PLC仿真连接通信
机器人·c#·信息与通信
yngsqq8 小时前
加载dll插件自动提示文字信息——cad c#二次开发
开发语言·c#
CoreFMEA软件13 小时前
0 - 1 背包问题介绍与 C# 代码实现
开发语言·算法·c#·背包问题
FAREWELL0007517 小时前
C#基础学习(六)函数的变长参数和参数默认值
学习·c#·数组
[abcdem]18 小时前
c#个人向总结
开发语言·c#
旧厂街小江20 小时前
LeetCode第95题:不同的二叉搜索树 II
python·算法·c#
程序设计实验室20 小时前
基于.NetCore开发 StarBlog 番外篇 (3) StarBlog Publisher,跨平台一键发布,DeepSeek加持的文章创作神器
c#·avalonia·starblog博客开发笔记
yngsqq20 小时前
AutoCAD C#二次开发中WinForm与WPF的对比
c#
欣然~21 小时前
基于词袋模型(Bag-of-Words)的简单神经网络的对话
开发语言·c#
csdn_aspnet21 小时前
C# 如何检查给定的四个点是否形成一个正方形(How to check if given four points form a square)
算法·c#