ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

cad.net 反射Acad获取com调用包围盒返回数据

2021-03-28 15:35:17  阅读:342  来源: 互联网

标签:Acad object comObjectName using new net null com acAcadApp


故事

首先是飞诗在问了一个问题:Acad2007的com包围盒无法正确获取文字的包围盒,问有没有其他方法?
但是他测试了lisp的获取是正确的,所以他想反射调用里面内置的,而他会反射,但是获取不到在参数传回返回值.

edata解决了这个问题,然后我测试的时候发现net5桌面程序不能用:Marshal.GetActiveObject
真是一个问题接一个.....这可怎么呢?

虽然我在学net5的教学中知道了这个,但是它没有给我解决方案.

然后南胜提醒了我一下,有using Microsoft.VisualBasic.Interaction.CreateObject可以用.
为此我完成了之前没有完成的东西:com启动Acad

开干

写一个net5的控制台调用这个,当然了,你喜欢低版本也可以...

new ReflectionAcad().GetBoundingBox();

然后复制粘贴这个就好了,各种的com技术都蛮有意思的.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using Microsoft.VisualBasic;

namespace 测试_exe发送cad
{
    //http://www.cadgj.com/?p=297
    public partial class AcadComTool
    {
        [DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
        static extern int _CreateBindCtx(int reserved, out IBindCtx ppbc);

        /// <summary>
        /// 获取已经启动的CAD进程的com
        /// </summary>
        /// <param name="apps"></param>
        public static void GetActiveAcadCom(List<object> apps, string cadDisplayName)
        {
            _CreateBindCtx(0, out IBindCtx pbc);
            pbc.GetRunningObjectTable(out IRunningObjectTable pprot);

            pprot.EnumRunning(out IEnumMoniker ppenumMoniker);
            ppenumMoniker.Reset();
            IMoniker[] rgelt = new IMoniker[1];
            rgelt[0] = null;
            int rc = ppenumMoniker.Next(1, rgelt, IntPtr.Zero);
            while (rgelt[0] != null)
            {
                rgelt[0].GetDisplayName(pbc, null, out string ppszDisplayName);
#if DEBUG
                //不启动cad的时候运行一次,看看有什么GUID,然后再启动一个cad对比就知道了
                Debug.WriteLine(ppszDisplayName);
#endif
                if (ppszDisplayName == cadDisplayName)
                {
                    pprot.GetObject(rgelt[0], out object obj);
                    if (obj == null)
                    {
                        continue;
                    }
                    apps.Add(obj);
                }
                rgelt[0] = null;
                rc = ppenumMoniker.Next(1, rgelt, IntPtr.Zero);
            }
        }
    }


    public partial class ReflectionAcad
    {
        const string ProgID = "AutoCAD.Application";

        /// <summary>
        /// com方式启动cad
        /// </summary>
        /// <returns></returns>
        private object StartAcad()
        {
            object acAcadApp = null;
            //只能获取已经打开的Acad,如果不存在会触发异常,暂未处理

#if !NET50
            dynamic acAcadApp = Marshal.GetActiveObject(progID); 
#else
            //两种方法,都会启动一个新的Acad.
#if true2
            //**不阻塞启动**
            var path = @"C:\Program Files\Autodesk\AutoCAD 2021\acad.exe";
            path = @"C:\Program Files (x86)\AutoCAD 2008\acad.exe";
            int acadid = Interaction.Shell(path, AppWinStyle.NormalFocus); //正常大小启动 ,返回进程id
#else
            //**阻塞启动**                 
            // acAcadApp = Interaction.GetObject("", ProgID);
            acAcadApp = Interaction.CreateObject(ProgID);
#endif
#endif    
            //acAcadApp = Activator.CreateInstance(comObjectName);

            return acAcadApp;
        }

        /// <summary>
        /// 通过cad的com进行反射调用VBA函数获取包围盒
        /// </summary>
        public void GetBoundingBox()
        {
            //与指定 ProgID 关联的类型,即获取相应的Com对象       
            var comObjectName = Type.GetTypeFromProgID(ProgID);
            if (comObjectName == null)
            {
                MessageBox.Show($"本机不存在:{ProgID}");
                return;
            }

            List<object> apps = new();
            AcadComTool.GetActiveAcadCom(apps, "!{6AB55F46-2523-4701-A912-B226F46252BA}");
            if (apps.Count == 0)
            {
                // Acad没有启动,那就去启动它
                var acAcadApp2 = StartAcad();
                if (acAcadApp2 == null)
                {
                    MessageBox.Show($"无法打开程序:{ProgID}");
                    return;
                }
                apps.Add(acAcadApp2);
            }

            foreach (var acAcadApp in apps)
            {
#if true
                //参数
                object[] args = new object[1];
                //设置需要设置的参数值
                args[0] = true;
                //设置属性-可视,显示窗体
                comObjectName.InvokeMember("Visible", BindingFlags.SetProperty, null, acAcadApp, args);

                //获取属性
                object comAcDoc = comObjectName.InvokeMember("ActiveDocument", BindingFlags.GetProperty, null, acAcadApp, null);
                object comAcMsSpace = comObjectName.InvokeMember("ModelSpace", BindingFlags.GetProperty, null, comAcDoc, null);
                //调用VBA函数也就是com暴露的函数,画在"激活的文档"的"模型空间"然后输入画一条线的坐标数据.
                object[] lines = new object[] { new double[] { 100, 100, 0 }, new double[] { 300, 300, 0 } };
                object comAcLine = comObjectName.InvokeMember("AddLine", BindingFlags.InvokeMethod, null, comAcMsSpace, lines);

                //pts就是包围盒返回的点集
                object[] pts = new object[2] { null, null };

                //由于需要从参数中返回结果,所以需要设置 ParameterModifier 作用在 InvokeMember 上
                var paramMod = new ParameterModifier(2);
                paramMod[0] = true;//设置为true才能改写
                paramMod[1] = true;

                //求得这条线的包围盒,返回给pts.
                comObjectName.InvokeMember("GetBoundingBox",
                    BindingFlags.SuppressChangeType | BindingFlags.InvokeMethod,
                    null, comAcLine, pts, new ParameterModifier[] { paramMod }, null, null);

                //全屏显示
                comObjectName.InvokeMember("ZoomAll", BindingFlags.InvokeMethod, null, acAcadApp, null);
#else
                //c#4等效代码
                acAcadApp.ZoomAll();
                dynamic acAcadDoc = acAcadApp.ActiveDocument;
                if (acAcadDoc != null)
                {
                    //acAcadDoc.SendCommand("_.Line 100,100 300,300  ");
                    dynamic acMsSpace = acAcadDoc.ModelSpace;
                    double[] p1 = new double[3] { 100.0, 100.0, 0.0 };
                    double[] p2 = new double[3] { 300.0, 300.0, 0.0 };

                    dynamic acLine = acMsSpace.AddLine(p1, p2);
                    object ptMin = new object();
                    object ptMax = new object();
                    acLine.GetBoundingBox(out ptMin, out ptMax);
                    MessageBox.Show(ptMin.ToString() + "\n" + ptMax.ToString());
                }
#endif
                 

                var a = (double[])pts[0];
                var b = (double[])pts[1]; 
                Debug.WriteLine($"MinPoint={a[0]},{a[1]},{a[2]}");
                Debug.WriteLine($"MaxPoint={b[0]},{b[1]},{b[2]}");
            }
        }
    }
}

(完)

标签:Acad,object,comObjectName,using,new,net,null,com,acAcadApp
来源: https://www.cnblogs.com/JJBox/p/14588762.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有