雪山飞狐_lzh 发表于 2015-4-17 22:36:00

C#后绑定Com库全攻略

使用C#做Com调用确实麻烦 比VB要麻烦多了,至于为什么使用后绑定显然是为了程序的通用性
然而Com对象在后绑定时不显示实际类型,只有使用反射
一、使用IDispatch接口
大多数Com类都是基于IDispatch接口,IDispatch接口在.Net中没有定义
下面是IDispatch接口的简易定义,没有Invoke函数的具体定义,那么Com类的方法调用就要获取实际类型
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
namespace TlsCad.Common.Runtime
{
   
    public interface IDispatch
    {
      
      int GetTypeInfoCount();
      
      int GetTypeInfo( int index, int lcid, out ITypeInfo pTypeInfo);
      
      int GetIDsOfNames();
      
      int Invoke();
    }
}

雪山飞狐_lzh 发表于 2015-4-17 22:36:00


二、自定义类AcVersion从注册表获取AutoCadCom库在GAC中的.Net程序集,以进行实际的反射,下面的代码主要应用于XP,如果在更高版本,你可能需要做些更改
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace TlsCad.Common.Runtime
{
    public class AcVersion
    {
      public int Major
      { private set; get; }
      public int Minor
      { private set; get; }
      public double ProgId
      {
            get { return Major + Minor / 10.0; }
      }
      public string ProductName
      { private set; get; }
      public string ProductRootKey
      { private set; get; }
      private string _appAssemblyName;
      private string _dbxAssemblyName;
      public Assembly AppAssembly
      { private set; get; }
      public Assembly DbxAssembly
      { private set; get; }
      static string _appClassNameHead = "Autodesk.AutoCAD.Interop.";
      static string _dbxClassNameHead = "Autodesk.AutoCAD.Interop.Common.";
      ///
      /// 获取Com对象的接口类型
      ///
      /// Com对象
      /// 接口类型
      public Type GetType(object obj)
      {
            IDispatch idisp = obj as IDispatch;
            ITypeInfo t;
            idisp.GetTypeInfo(0, 0, out t);
            string name = Marshal.GetTypeInfoName(t);
            return
                AppAssembly.GetType(_appClassNameHead + name) ??
                DbxAssembly.GetType(_dbxClassNameHead + name);
      }
      private static List _versions;
      public static List Versions
      {
            get
            {
                if (_versions == null)
                {
                  string[] copys =
                     Registry.LocalMachine
                     .OpenSubKey(@"SOFTWARE\Autodesk\Hardcopy")
                     .GetValueNames();
                  _versions = new List();
                  foreach (var rootkey in copys)
                  {
                        Regex r = new Regex(@"Autodesk\\AutoCAD\\R(\d+)\.(\d+)\\.*?");
                        if (r.IsMatch(rootkey))
                        {
                            var gs = r.Match(rootkey).Groups;
                            var ver =
                              new AcVersion
                              {
                                    ProductRootKey = rootkey,
                                    ProductName =
                                        Registry.LocalMachine
                                        .OpenSubKey("SOFTWARE")
                                        .OpenSubKey(rootkey)
                                        .GetValue("ProductName")
                                        .ToString(),
                                    Major = int.Parse(gs.Value),
                                    Minor = int.Parse(gs.Value),
                              };
                            ver.GetAssemblyName();
                            _versions.Add(ver);
                        }
                  }
                }
                return _versions;
            }
      }
      public static AcVersion FromApp(dynamic app)
      {
            var gs = Regex.Match(app.Version, @"(\d+)\.(\d+).*?").Groups;
            int major = int.Parse(gs.Value);
            int minor = int.Parse(gs.Value);
            foreach (var ver in Versions)
            {
                if (ver.Major == major && ver.Minor == minor)
                  return ver;
            }
            return null;
      }
      public void LoadAssembly()
      {
            AppAssembly = Assembly.Load(_appAssemblyName);
            DbxAssembly = Assembly.Load(_dbxAssemblyName);
      }
      private void GetAssemblyName()
      {
            _appAssemblyName = GetAssemblyName("AutoCad.Application", ProgId.ToString());
            _dbxAssemblyName = GetAssemblyName("ObjectDBX.AxDbDocument", Major.ToString());
      }
      private string GetAssemblyName(string name, string id)
      {
            string clsId =
                Registry.ClassesRoot
                .OpenSubKey(name + "." + id)
                .OpenSubKey("CLSID")
                .GetValue("")
                .ToString();
            return
                Registry.ClassesRoot
                .OpenSubKey(string.Format("CLSID\\{0}\\InprocServer32", clsId))
                .GetValue("Assembly").ToString();
      }
      public override string ToString()
      {
            return
                string.Format(
                  "名称:{0}\n版本号:{1}\n注册表位置:{2}\nApp_Com类库:{3}\nDbx_Com类库:{4}",
                  ProductName,
                  ProgId,
                  ProductRootKey,
                  _appAssemblyName,
                  _dbxAssemblyName);
      }
    }
}

雪山飞狐_lzh 发表于 2015-4-17 23:08:00

三、反射类AcObject继承于DynamicObject,以便在.Net4.0中使用动态特性
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Dynamic;
namespace TlsCad.Common.Runtime
{
    public class AcObject : DynamicObject
    {
      public static dynamic Application
      { private set; get; }
      public static dynamic Preferences
      {
            get { return Application.Preferences; }
      }
      public static AcVersion Version
      { private set; get; }
      public Type Type
      { private set; get; }
      public object Value
      { private set; get; }
      #region Wrapper
      protected AcObject() { }
      public static dynamic Wrapper(dynamic obj, Type type)
      {
            if (obj != null && Marshal.IsComObject(obj))
            {
                var wrapper =
                  new AcObject
                  {
                        Value = obj,
                        Type =
                            Regex.IsMatch(type.Name, "^Acad.*?$") ?
                            type.GetInterfaces() :
                            Version.GetType(obj)
                  };
                if (wrapper.Type.GetMethod("Item") != null)
                  return wrapper.AsItems();
                return wrapper;
            }
            else
            {
                return obj;
            }
      }
      public static dynamic Wrapper(object obj)
      {
            return Wrapper(obj, Version.GetType(obj));
      }
      #endregion
      #region Invoke
      private dynamic Invoke(MethodInfo mi, object[] args)
      {
            object obj = mi.Invoke(Value, args);
            return Wrapper(obj, mi.ReturnType);
      }
      public dynamic InvokeMember(string name, params object[] args)
      {
            try
            {
                //获取接口函数
                MethodInfo mi = Type.GetMethod(name);
                //配置参数
                var pars = mi.GetParameters();
                object[] realargs = new object;
                Array.Copy(args, realargs, args.Length);
                for (int i = args.Length; ilst = new List { Invoke(mi, realargs) };
                for (int i = args.Length; i
    {
      internal AcItems() { }
      public AcObject this
      {
            get { return (AcObject)this.InvokeMember("Item", id); }
      }
      public AcObject this
      {
            get { return (AcObject)this.InvokeMember("Item", id); }
      }
      public int Count
      {
            get { return (int)this.GetMember("Count").Value; }
      }
      public IEnumerator GetEnumerator()
      {
            int count = Count;
            for (int i = 0; iv.ToString()).ToArray()));
            if (!AcObject.GetApp())
                AcObject.OpenApp(AcVersion.Versions);
            var pref = AcObject.Preferences;
            var files = pref.Files;
            var app = AcObject.Application;
            app.Visible = true;
            var doc = app.ActiveDocument;
            var util = doc.Utility;
            var res = util.GetEntity();
            if (res != null)
            {
                var obj = res;
                var pt = res;
                var p = obj.ObjectName;
            }
      }

雪山飞狐_lzh 发表于 2015-4-17 23:09:00

这个很高端啊!给你点个赞!
页: [1]
查看完整版本: C#后绑定Com库全攻略