明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 2320|回复: 5

[运行时] C#后绑定Com库全攻略

  [复制链接]
发表于 2015-4-17 22:36 | 显示全部楼层 |阅读模式
本帖最后由 雪山飞狐_lzh 于 2015-4-17 23:06 编辑

使用C#做Com调用确实麻烦 比VB要麻烦多了,至于为什么使用后绑定显然是为了程序的通用性
然而Com对象在后绑定时不显示实际类型,只有使用反射
一、使用IDispatch接口
大多数Com类都是基于IDispatch接口,IDispatch接口在.Net中没有定义
下面是IDispatch接口的简易定义,没有Invoke函数的具体定义,那么Com类的方法调用就要获取实际类型
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Runtime.InteropServices.ComTypes;
  4. using System.Security;

  5. namespace TlsCad.Common.Runtime
  6. {
  7.     [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  8.     public interface IDispatch
  9.     {
  10.         [PreserveSig, Obsolete("Bad signature. Fix and verify signature before use.", true), SecurityCritical]
  11.         int GetTypeInfoCount();
  12.         [PreserveSig, SecurityCritical]
  13.         int GetTypeInfo([In] int index, [In] int lcid, [MarshalAs(UnmanagedType.Interface)] out ITypeInfo pTypeInfo);
  14.         [PreserveSig, SecurityCritical]
  15.         int GetIDsOfNames();
  16.         [PreserveSig, SecurityCritical]
  17.         int Invoke();
  18.     }
  19. }

 楼主| 发表于 2015-4-17 22:36 | 显示全部楼层
本帖最后由 雪山飞狐_lzh 于 2015-4-17 23:07 编辑

二、自定义类AcVersion从注册表获取AutoCadCom库在GAC中的.Net程序集,以进行实际的反射,下面的代码主要应用于XP,如果在更高版本,你可能需要做些更改
  1. using System;
  2. using System.Collections.Generic;
  3. using Microsoft.Win32;
  4. using System.Text.RegularExpressions;
  5. using System.Reflection;
  6. using System.Runtime.InteropServices;
  7. using System.Runtime.InteropServices.ComTypes;


  8. namespace TlsCad.Common.Runtime
  9. {

  10.     public class AcVersion
  11.     {

  12.         public int Major
  13.         { private set; get; }

  14.         public int Minor
  15.         { private set; get; }


  16.         public double ProgId
  17.         {
  18.             get { return Major + Minor / 10.0; }
  19.         }

  20.         public string ProductName
  21.         { private set; get; }

  22.         public string ProductRootKey
  23.         { private set; get; }

  24.         private string _appAssemblyName;
  25.         private string _dbxAssemblyName;

  26.         public Assembly AppAssembly
  27.         { private set; get; }

  28.         public Assembly DbxAssembly
  29.         { private set; get; }

  30.         static string _appClassNameHead = "Autodesk.AutoCAD.Interop.";
  31.         static string _dbxClassNameHead = "Autodesk.AutoCAD.Interop.Common.";

  32.         /// <summary>
  33.         /// 获取Com对象的接口类型
  34.         /// </summary>
  35.         /// <param name="obj">Com对象</param>
  36.         /// <returns>接口类型</returns>
  37.         public Type GetType(object obj)
  38.         {

  39.             IDispatch idisp = obj as IDispatch;
  40.             ITypeInfo t;
  41.             idisp.GetTypeInfo(0, 0, out t);

  42.             string name = Marshal.GetTypeInfoName(t);
  43.             return
  44.                 AppAssembly.GetType(_appClassNameHead + name) ??
  45.                 DbxAssembly.GetType(_dbxClassNameHead + name);

  46.         }

  47.         private static List<AcVersion> _versions;
  48.         public static List<AcVersion> Versions
  49.         {
  50.             get
  51.             {

  52.                 if (_versions == null)
  53.                 {

  54.                     string&#91;&#93; copys =
  55.                        Registry.LocalMachine
  56.                        .OpenSubKey(@"SOFTWARE\Autodesk\Hardcopy")
  57.                        .GetValueNames();
  58.                     _versions = new List<AcVersion>();
  59.                     foreach (var rootkey in copys)
  60.                     {
  61.                         Regex r = new Regex(@"Autodesk\\AutoCAD\\R(\d+)\.(\d+)\\.*?");
  62.                         if (r.IsMatch(rootkey))
  63.                         {
  64.                             var gs = r.Match(rootkey).Groups;
  65.                             var ver =
  66.                                 new AcVersion
  67.                                 {

  68.                                     ProductRootKey = rootkey,
  69.                                     ProductName =
  70.                                         Registry.LocalMachine
  71.                                         .OpenSubKey("SOFTWARE")
  72.                                         .OpenSubKey(rootkey)
  73.                                         .GetValue("ProductName")
  74.                                         .ToString(),

  75.                                     Major = int.Parse(gs&#91;1&#93;.Value),
  76.                                     Minor = int.Parse(gs&#91;2&#93;.Value),

  77.                                 };

  78.                             ver.GetAssemblyName();
  79.                             _versions.Add(ver);

  80.                         }
  81.                     }
  82.                 }
  83.                 return _versions;
  84.             }
  85.         }

  86.         public static AcVersion FromApp(dynamic app)
  87.         {

  88.             var gs = Regex.Match(app.Version, @"(\d+)\.(\d+).*?").Groups;
  89.             int major = int.Parse(gs&#91;1&#93;.Value);
  90.             int minor = int.Parse(gs&#91;2&#93;.Value);
  91.             foreach (var ver in Versions)
  92.             {
  93.                 if (ver.Major == major && ver.Minor == minor)
  94.                     return ver;
  95.             }

  96.             return null;

  97.         }

  98.         public void LoadAssembly()
  99.         {
  100.             AppAssembly = Assembly.Load(_appAssemblyName);
  101.             DbxAssembly = Assembly.Load(_dbxAssemblyName);
  102.         }

  103.         private void GetAssemblyName()
  104.         {
  105.             _appAssemblyName = GetAssemblyName("AutoCad.Application", ProgId.ToString());
  106.             _dbxAssemblyName = GetAssemblyName("ObjectDBX.AxDbDocument", Major.ToString());
  107.         }

  108.         private string GetAssemblyName(string name, string id)
  109.         {

  110.             string clsId =
  111.                 Registry.ClassesRoot
  112.                 .OpenSubKey(name + "." + id)
  113.                 .OpenSubKey("CLSID")
  114.                 .GetValue("")
  115.                 .ToString();

  116.             return
  117.                 Registry.ClassesRoot
  118.                 .OpenSubKey(string.Format("CLSID\\{0}\\InprocServer32", clsId))
  119.                 .GetValue("Assembly").ToString();

  120.         }

  121.         public override string ToString()
  122.         {
  123.             return
  124.                 string.Format(
  125.                     "名称:{0}\n版本号:{1}\n注册表位置:{2}\nApp_Com类库:{3}\nDbx_Com类库:{4}",
  126.                     ProductName,
  127.                     ProgId,
  128.                     ProductRootKey,
  129.                     _appAssemblyName,
  130.                     _dbxAssemblyName);
  131.         }


  132.     }
  133. }

 楼主| 发表于 2015-4-17 23:08 | 显示全部楼层
三、反射类AcObject继承于DynamicObject,以便在.Net4.0中使用动态特性
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Runtime.InteropServices;
  5. using System.Text.RegularExpressions;
  6. using System.Dynamic;

  7. namespace TlsCad.Common.Runtime
  8. {

  9.     public class AcObject : DynamicObject
  10.     {

  11.         public static dynamic Application
  12.         { private set; get; }

  13.         public static dynamic Preferences
  14.         {
  15.             get { return Application.Preferences; }
  16.         }

  17.         public static AcVersion Version
  18.         { private set; get; }

  19.         public Type Type
  20.         { private set; get; }

  21.         public object Value
  22.         { private set; get; }

  23.         #region Wrapper

  24.         protected AcObject() { }

  25.         public static dynamic Wrapper(dynamic obj, Type type)
  26.         {

  27.             if (obj != null && Marshal.IsComObject(obj))
  28.             {

  29.                 var wrapper =
  30.                     new AcObject
  31.                     {
  32.                         Value = obj,
  33.                         Type =
  34.                             Regex.IsMatch(type.Name, "^Acad.*?$") ?
  35.                             type.GetInterfaces()[0] :
  36.                             Version.GetType(obj)
  37.                     };

  38.                 if (wrapper.Type.GetMethod("Item") != null)
  39.                     return wrapper.AsItems();
  40.                 return wrapper;

  41.             }
  42.             else
  43.             {
  44.                 return obj;
  45.             }

  46.         }

  47.         public static dynamic Wrapper(object obj)
  48.         {
  49.             return Wrapper(obj, Version.GetType(obj));
  50.         }

  51.         #endregion

  52.         #region Invoke

  53.         private dynamic Invoke(MethodInfo mi, object[] args)
  54.         {
  55.             object obj = mi.Invoke(Value, args);
  56.             return Wrapper(obj, mi.ReturnType);
  57.         }

  58.         public dynamic InvokeMember(string name, params object[] args)
  59.         {
  60.             try
  61.             {

  62.                 //获取接口函数
  63.                 MethodInfo mi = Type.GetMethod(name);

  64.                 //配置参数
  65.                 var pars = mi.GetParameters();
  66.                 object[] realargs = new object[pars.Length];
  67.                 Array.Copy(args, realargs, args.Length);
  68.                 for (int i = args.Length; i < realargs.Length; i++)
  69.                     realargs = pars.IsOptional ? Type.Missing : null;

  70.                 List<dynamic> lst = new List<dynamic> { Invoke(mi, realargs) };
  71.                 for (int i = args.Length; i < realargs.Length; i++)
  72.                 {
  73.                     if (pars.IsOut)
  74.                         lst.Add(Wrapper(realargs, pars.ParameterType));
  75.                 }

  76.                 if (lst.Count == 1)
  77.                     return lst[0];
  78.                 return lst;

  79.             }
  80.             catch
  81.             {
  82.                 return null;
  83.             }

  84.         }

  85.         #endregion

  86.         #region Property

  87.         public AcItems AsItems()
  88.         {
  89.             return
  90.                 new AcItems
  91.                 {
  92.                     Value = Value,
  93.                     Type = Type
  94.                 };
  95.         }

  96.         public dynamic GetMember(string name)
  97.         {
  98.             try
  99.             {
  100.                 var mi = Type.GetMember("get_" + name)[0] as MethodInfo;
  101.                 return Invoke(mi, new object[0]);

  102.             }
  103.             catch
  104.             {
  105.                 return null;
  106.             }
  107.         }

  108.         public void SetMember(string name, object value)
  109.         {
  110.             try
  111.             {
  112.                 var mi = Type.GetMember("set_" + name)[0] as MethodInfo;
  113.                 mi.Invoke(Value, new object[] { value });
  114.             }
  115.             catch
  116.             { }
  117.         }

  118.         #endregion

  119.         #region App

  120.         public static bool GetApp()
  121.         {
  122.             object app;
  123.             try
  124.             {
  125.                 app = Marshal.GetActiveObject("AutoCad.Application");
  126.                 return GetApp(app);
  127.             }
  128.             catch
  129.             {
  130.                 return false;
  131.             }

  132.         }

  133.         public static bool GetApp(object app)
  134.         {
  135.             try
  136.             {
  137.                 Version = AcVersion.FromApp(app);
  138.                 Version.LoadAssembly();
  139.                 Application = (AcObject)Wrapper(app);
  140.                 return true;
  141.             }
  142.             catch
  143.             {
  144.                 return false;
  145.             }

  146.         }

  147.         public static bool OpenApp(AcVersion ver)
  148.         {
  149.             try
  150.             {
  151.                 var app =
  152.                     Activator.CreateInstance(Type.GetTypeFromProgID("AutoCad.Application." + ver.ProgId));
  153.                 return GetApp(app);
  154.             }
  155.             catch
  156.             {
  157.                 return false;
  158.             }

  159.         }

  160.         #endregion

  161.         #region DynamicObject

  162.         public override bool TryGetMember(GetMemberBinder binder, out object result)
  163.         {
  164.             result = GetMember(binder.Name);
  165.             return true;
  166.         }

  167.         public override bool TrySetMember(SetMemberBinder binder, object value)
  168.         {
  169.             SetMember(binder.Name, value);
  170.             return true;
  171.         }

  172.         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  173.         {
  174.             result = InvokeMember(binder.Name, args);
  175.             return true;
  176.         }

  177.         #endregion

  178.     }

  179. }
 楼主| 发表于 2015-4-17 23:09 | 显示全部楼层
AcItems类,对应集合类
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections;

  4. namespace TlsCad.Common.Runtime
  5. {
  6.     public class AcItems : AcObject,IEnumerable<AcObject>
  7.     {

  8.         internal AcItems() { }

  9.         public AcObject this[int id]
  10.         {
  11.             get { return (AcObject)this.InvokeMember("Item", id); }
  12.         }

  13.         public AcObject this[string id]
  14.         {
  15.             get { return (AcObject)this.InvokeMember("Item", id); }
  16.         }

  17.         public int Count
  18.         {
  19.             get { return (int)this.GetMember("Count").Value; }
  20.         }

  21.         public IEnumerator<AcObject> GetEnumerator()
  22.         {
  23.             int count = Count;
  24.             for (int i = 0; i < count; i++)
  25.                 yield return (AcObject)this.InvokeMember("Item", i);
  26.         }

  27.         IEnumerator IEnumerable.GetEnumerator()
  28.         {
  29.             return this.GetEnumerator();
  30.         }



  31.     }
  32. }
 楼主| 发表于 2015-4-17 23:10 | 显示全部楼层
调用例子
  1.         private void button1_Click(object sender, EventArgs e)
  2.         {

  3.             MessageBox.Show("你安装了如下版本的AutoCad\n" + string.Join("\n", AcVersion.Versions.Select(v => v.ToString()).ToArray()));

  4.             if (!AcObject.GetApp())
  5.                 AcObject.OpenApp(AcVersion.Versions[0]);

  6.             var pref = AcObject.Preferences;
  7.             var files = pref.Files;

  8.             var app = AcObject.Application;
  9.             app.Visible = true;
  10.             var doc = app.ActiveDocument;
  11.             var util = doc.Utility;

  12.             var res = util.GetEntity();

  13.             if (res != null)
  14.             {
  15.                 var obj = res[1];
  16.                 var pt = res[2];
  17.                 var p = obj.ObjectName;
  18.             }

  19.         }
发表于 2021-11-6 09:19 | 显示全部楼层
这个很高端啊!给你点个赞!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-18 15:53 , Processed in 0.337790 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表