雪山飞狐_lzh 发表于 2015-4-4 18:09:34

.C#4.0 实现晚绑定来调用Com库

本帖最后由 雪山飞狐_lzh 于 2015-4-4 18:45 编辑


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using stdole;

namespace TlsCad.RunTime
{
    public partial class Form1 : Form
    {
      public Form1()
      {

            //获取当前AutoCad实例
            string pid = "AutoCad.Application";
            dynamic app;
            try
            {
                app = Marshal.GetActiveObject(pid);
            }
            catch
            {
                //如果没有就创建之
                Type t = Type.GetTypeFromProgID(pid);
                app = Activator.CreateInstance(t);
                app.Visible = true;
            }

            //获取当前文档
            dynamic doc = app.ActiveDocument;

            double[] p1 = { 0, 0, 0 };
            double[] p2 = { 0, 10, 0 };
            double[] p3 = { 10, 10, 0 };
            double[] p4 = { 10, 0, 0 };

            //Com对象数组必须封装为IDispatch数组
            //注意应引用stdole.dll
            IDispatch[] ents =
            {
                doc.ModelSpace.AddLine(p1, p2),
                doc.ModelSpace.AddLine(p2, p3),
                doc.ModelSpace.AddLine(p3, p4),
                doc.ModelSpace.AddLine(p4, p1)
            };

            //测试生成面域
            dynamic r = doc.ModelSpace.AddRegion(ents);
            double[] min, max;
            r.GetBoundingBox(out min, out max);
            app.ZoomWindow(min, max);

            InitializeComponent();

      }
    }
}



雪山飞狐_lzh 发表于 2015-4-5 15:33:42

本帖最后由 雪山飞狐_lzh 于 2015-4-5 16:13 编辑


调试结果

ps:有没有朋友按4楼的方法 把其他版本cad的这两个dll贴上。。。

qinnaixuan 发表于 2016-10-16 18:52:10

雪山飞狐_lzh 发表于 2015-4-5 14:53
变体参数的反射

Utiility类中大量的函数使用了变体。。。


能否帮忙将这个单个CAD版本的应用程序修改为适合多个CAD版本的应用程序,如2010,2013等版本,本人愿意支付一定的费用,联系QQ:1067426844。程序码如下:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualBasic;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;

namespace CAD二次开发
{
    public partial class Form1 : Form
    {
      public static Autodesk.AutoCAD.Interop.AcadApplication AcadApp;
      public static Autodesk.AutoCAD.Interop.AcadDocument AcadDoc;
      public Form1()
      {
            InitializeComponent();
      }
      public static void 启动CAD()
      {
            try
            {
                AcadApp = (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");
                AcadDoc = AcadApp.ActiveDocument;
            }
            catch
            {
                AcadApp = new AcadApplication();
                AcadDoc = AcadApp.ActiveDocument;
            }
            AcadApp.Application.Visible = true;
            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);
      }

      private void button1_Click(object sender, EventArgs e)
      {
            启动CAD();

            double Ks =0;
            double Ke = 2000;
            double Dmax = 150;
            double Dmin = -150;

            string VerCAD = (AcadApp.Version.ToString()).Substring(0, 2);//获取AutoCAD版本号,从左边截取2位字符
            AcadAcCmColor color1 = (AcadAcCmColor)AcadDoc.Application.GetInterfaceObject("AutoCAD.AcCmColor." + VerCAD);//新建一AcadAcCmColor对象,该对象用来给图形对象的颜色属性赋值
            AcadLayer acLayer;
            AcadText TextObj;

            acLayer = AcadDoc.Layers.Add("中心线");
            acLayer.color = AcColor.acYellow;
            acLayer.Lineweight = ACAD_LWEIGHT.acLnWt025;

            acLayer = AcadDoc.Layers.Add("文字标注");
            acLayer.color = AcColor.acGreen;

            acLayer = AcadDoc.Layers.Add("主网格");
            color1.SetRGB(66, 112, 138);
            acLayer.TrueColor = color1;
            acLayer.Lineweight = ACAD_LWEIGHT.acLnWt015;

            acLayer = AcadDoc.Layers.Add("副网格");
            color1.SetRGB(95, 58, 69);
            acLayer.TrueColor = color1;
            acLayer.Lineweight = ACAD_LWEIGHT.acLnWt005;

            double[] lineStartPoint = new Double;
            double[] lineEndPoint = new Double;
            double[] TextPoint = new Double;

            //水平网格线
            for (int i = Convert.ToInt32(Math.Ceiling(Dmin / 10)) * 10; i <= Math.Floor(Dmax / 10) * 10; i = i + 10)
            {
                lineStartPoint = Ks ; lineStartPoint = i;
                lineEndPoint = Ke ; lineEndPoint = i;

                if (i % 50 == 0)
                {
                  if (i == 0)
                  {
                        AcadDoc.ModelSpace.AddLine(lineStartPoint, lineEndPoint).Layer = "中心线";
                  }
                  else
                  {
                        AcadDoc.ModelSpace.AddLine(lineStartPoint, lineEndPoint).Layer = "主网格";
                  }
                }
                else
                {
                  AcadDoc.ModelSpace.AddLine(lineStartPoint, lineEndPoint).Layer = "副网格";
                }
            }

            //竖向网格线
            for (int i = Convert.ToInt32(Math.Ceiling(Ks / 10)) * 10; i <= Math.Floor(Ke / 10) * 10; i = i + 10)
            {
                lineStartPoint = i ; lineStartPoint = Math.Ceiling(Dmin / 10) * 10;
                lineEndPoint = i ; lineEndPoint = Math.Floor(Dmax / 10) * 10;

                if (i % 50 == 0)
                {
                  AcadDoc.ModelSpace.AddLine(lineStartPoint, lineEndPoint).Layer = "主网格";
                  if (i % 100 == 0)
                  {
                        //标注里程
                        TextPoint = i ; TextPoint = Math.Ceiling(Dmin / 10) * 10 - 10;
                        string strText;
                        if (i % 1000 == 0)
                        {
                            strText = "K" + (i / 1000).ToString();
                        }
                        else
                        {
                            strText = ((i / 100) % 10).ToString();
                        }
                        TextObj = AcadDoc.ModelSpace.AddText(strText, TextPoint, 7.5);
                        TextObj.Alignment = AcAlignment.acAlignmentMiddleCenter;//文本对齐方式
                        TextObj.TextAlignmentPoint = TextPoint;
                        TextObj.Layer = "文字标注";

                        //标注拨量
                        if (i % 1000 == 0)
                        {
                            for (int j = Convert.ToInt32(Math.Ceiling(Dmin / 50)) * 50; j <= Math.Floor(Dmax / 50) * 50; j = j + 50)
                            {
                              TextPoint = i- 5; TextPoint = j;
                              TextObj = AcadDoc.ModelSpace.AddText(j.ToString(), TextPoint, 7.5);
                              TextObj.Alignment = AcAlignment.acAlignmentMiddleRight;//文本对齐方式
                              TextObj.TextAlignmentPoint = TextPoint;                //文本对齐点
                              TextObj.Layer = "文字标注";
                            }
                        }
                  }
                }

            }

            AcadDoc.ActiveLayer = AcadDoc.Layers.Add("0");//恢复0图层
            AcadDoc.SendCommand("_z\ne\n");
            AcadDoc.SendCommand("_regenall\n");//全部重生成模型

            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);

      }
    }
}

hector 发表于 2018-5-1 09:17:59

飞狐大侠,你好。从你的帖子中学到了很多,非常感谢。
有一个问题请教 一下:使用C# COM,怎么调用sendcommand命令,实现两条直线trim的功能?(在sendcommand命令中,可以使用handent,但是无法使用list()),或者不用调用sendcommand,有无其它命令。
非常期待能获得你的指点。

雪山飞狐_lzh 发表于 2015-4-4 18:14:07

4.0使用dynamic确实大大的简化了反射的难度,唯一的问题是没有智能提示 O(∩_∩)O~

Real_King 发表于 2015-4-4 20:52:09

不错,C#在com方面的介绍比起VB太少了,面域的示例正好参考

雪山飞狐_lzh 发表于 2015-4-5 14:53:51

本帖最后由 雪山飞狐_lzh 于 2015-4-5 15:20 编辑


变体参数的反射

Utiility类中大量的函数使用了变体。。。
比如GetEntity
如果直接使用下面的代码
dynamic util = doc.Utility;
util.GetEntity(out obj, out pt);
始终调用不了
下面的办法不知道是不是最好的,以AutoCad2008/2010为例
首先在项目中引用AutoCad Type和ObjuectDBX两个Com类型库
修改引用项目中两个dll的
嵌入互操作为false
复制本地为True
生成一次项目 在应用程序目录下出现这两个dll

Autodesk.AutoCAD.Interop.dll
Autodesk.AutoCAD.Interop.Common.dll
把它们Copy到相应的版本目录下
最后去除这两个引用,


            string path = Assembly.GetExecutingAssembly().Location;
            path = path.Substring(0, path.LastIndexOf("\\"));
            string id = app.Version.Substring(0, 4);
            Dictionary<string, string> vers =
                new Dictionary<string,string>
                {
                  {"17.1", "2008"},
                  {"18.0", "2010"},
                };

            string file =
                string.Format(
                  "{0}\\{1}\\Autodesk.AutoCAD.Interop.dll",
                  path,
                  vers);
            Assembly ass = Assembly.LoadFile(file);

            dynamic util = doc.Utility;
            Type utilType = ass.GetType("Autodesk.AutoCAD.Interop.IAcadUtility");
            Object[] myArgs = new Object;
            myArgs = Type.Missing;
            MethodInfo m = utilType.GetMethod("GetEntity");
            m.Invoke(util, myArgs);

雪山飞狐_lzh 发表于 2015-4-5 18:10:21

本帖最后由 雪山飞狐_lzh 于 2015-4-5 21:17 编辑

可能的更好方法

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
using stdole;
using System.Text.RegularExpressions;
using System.Collections;

namespace TlsCad.RunTime
{
    public partial class Form1 : Form
    {

      
      static extern IntPtr SetActiveWindow(IntPtr hWnd);

      
      static extern bool SetForegroundWindow(IntPtr hWnd);

      public Form1()
      {

            InitializeComponent();

            AcadX.Connection();
            dynamic app = AcadX.Application;

            //获取当前文档
            dynamic doc = app.ActiveDocument;

            double[] p1 = { 0, 0, 0 };
            double[] p2 = { 0, 10, 0 };
            double[] p3 = { 10, 10, 0 };
            double[] p4 = { 10, 0, 0 };

            //Com对象数组必须封装为IDispatch数组
            //注意应引用stdole.dll
            IDispatch[] ents =
            {
                doc.ModelSpace.AddLine(p1, p2),
                doc.ModelSpace.AddLine(p2, p3),
                doc.ModelSpace.AddLine(p3, p4),
                doc.ModelSpace.AddLine(p4, p1)
            };

            //测试生成面域
            dynamic r = doc.ModelSpace.AddRegion(ents);
            double[] min, max;
            r.GetBoundingBox(out min, out max);
            app.ZoomWindow(min, max);

            //测试Utility,或者var util = new AcadUtility(doc);
            var util = new AcadX(".IAcadUtility", doc.Utility);
            object[] args = new object[]{ null, null, Type.Missing };
            if (util.Invoke("GetEntity", ref args))
            {
               
                dynamic obj = args;
                var pt = args as double[];

                string info = string.Format("你选择了{0}实体", obj.ObjectName);
                info += string.Format("\n在{0},{1},{2}", pt.Cast<object>().ToArray());
                MessageBox.Show(info);

            }

      }

    }

    public class AcadX
    {

      public static dynamic Application
      { private set; get; }

      virtual protected string TypeName
      {
            get { return "Autodesk.AutoCAD.Interop"; }
      }

      protected static Assembly _assem
      { private set; get; }

      protected Type _type;
      protected object _obj;

      protected AcadX()
      {
         _type = _assem.GetType(TypeName);
      }

      public AcadX(string typeName, object obj)
      {
            _type = _assem.GetType(TypeName + typeName);
            _obj = obj;
      }

      public bool Invoke(string methodName, ref object[] args)
      {
            
            try
            {

                MethodInfo mi = _type.GetMethod(methodName);
                List<object> lst = new List<object> { mi.Invoke(_obj, args) };

                var pars = mi.GetParameters();
                for(int i = 0; i< pars.Count(); i++)
                {
                  if (pars.IsOut)
                        lst.Add(args);
                }

                args = lst.ToArray();
                return true;

            }
            catch
            {

                args = new object;
                return false;

            }

      }

      public static void Connection()
      {
            //获取当前AutoCad实例
            string pid = "AutoCad.Application";
            try
            {
                Application = Marshal.GetActiveObject(pid);
            }
            catch
            {
                //如果没有就创建之
                Type t = Type.GetTypeFromProgID(pid);
                Application = Activator.CreateInstance(t);
                Application.Visible = true;
            }

            GetComAssembly(Application);

      }

      private static void GetComAssembly(dynamic app)
      {
            string id = app.Version.Substring(0, 4);
            Dictionary<string, string> vers = new Dictionary<string, string>();

            string vername = null;
            DirectoryInfo di = new DirectoryInfo("C:\\windows\\assembly\\gac_msil\\Autodesk.AutoCAD.Interop");
            var sdis = di.GetDirectories();
            foreach (var sdi in sdis)
            {
                if (sdi.Name.Contains(id))
                {
                  vername = sdi.Name;
                  break;
                }
            }

            var verinfos = Regex.Split(vername, "__");

            _assem =
                Assembly.Load(
                  string.Format(
                        "Autodesk.AutoCAD.Interop, Version={0}, Culture=neutral, PublicKeyToken={1}",
                        verinfos));
      }

    }

    public class AcadUtility : AcadX
    {

      protected override string TypeName
      {
            get { return base.TypeName + ".IAcadUtility"; }
      }

      public AcadUtility(dynamic doc)
      {
            _obj = doc.Utility;
      }

      public dynamic Document
      {
            set { _obj = value.Utility; }
      }

    }


}

hmxmylove 发表于 2015-4-5 18:40:28

学习了

雪山飞狐_lzh 发表于 2015-4-5 21:01:40

优化代码 6楼已更新

SurveyCAD 发表于 2016-4-7 09:55:15

我把你的代码原样拷贝到一个新项目,执行的时候没有错误提示,但是只是画了一个正方形,并没有成功创建一个面域,请问是什么原因呢?

52幕墙设计 发表于 2016-4-9 16:40:08

有帮助学习一下
页: [1] 2
查看完整版本: .C#4.0 实现晚绑定来调用Com库