知识大全 C#中COM操作(一)---实例化

Posted

篇首语:鸟贵有翼,人贵有志。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 C#中COM操作(一)---实例化相关的知识,希望对你有一定的参考价值。

C#中COM操作(一)---实例化  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  用C#做WinForm程序 时间长了难免会遇到和组件打交道的地方 用什么方式创建对象也成了我们必须面对的一个问题 据我所知道的创建对象的方法一共有以下几种:

   使用 NET包装组件

  这是最简单的就是导入组件所在的DLL 让IDE生成 NET一个IL包装加到项目中 这样原来里面所有实现了IDispatch Dual的类型及其相关类型就可以直接在 NET程序里面使用 比如以前在 时代 想要写自己的基于IE的浏览器 就得手动加入与IWebBrowser 接口相关的DLL 这种方式是大家最常用的 也是最傻瓜化的 因此也没什么可解释的

  但是这种方式有个至命的缺点——不是所有的对象都能用这种方式导出 正如前面所说的 只有实现了IDispatch Dual类型的接口才支持被导出 而且面对不同版本的或许会生成不一样的导出DLL 比如说A机器上写代码时导入了一个Jet 版本的包装DLL 代码编译了拿到B机器上去运行 但是B机器上的Jet版本是 的 就可能会出现运行时错误

   用反射动态创建

  包括使用Type GetTypeFromCLSID和Type GetFromProgID两种方法获取对象的Type再创建 这种方式也好理解 就是说使用这两个方法之前 必须得知道对象的GUID或ProgID 好在这也不是什么难事 一般我们要使一个对象 多多少少都了解一些这个对象的GUID或ProgID信息 用这种方获取到了一个Type对象后 就可以用 NET里面通用的反射创建对象的方法来做了

  这里给出一个创建JetEngine 的对象的代码实例:

  

      public object GetActiveXObject(Guid clsid)          Type t = Type GetTypeFromCLSID(clsid);       if (t == null) return null;          return Activator CreateInstance(t);         Guid g = new Guid( DE C FF C D BB F C FAE DA ); // JetEngine  object jet = GetActiveXObject(g);

  是不是觉得最后调用GetActiveXObject(g)的地方和IE里面Javascript里面用new ActiveXOjbect创建对象的方法很相像?

   声明CoCreateInstance外部函数 用这个函数去创建相应的实例

  M$在 里面包装的WebBrowser控件内部就是用这个函数去创建的 使用这种方式创建 就跟在C++里面不什么两样了 有一点需要说明的是 一般我们在代码中引入外部方法的时候 方法的参数和返回值的类型不一定是唯一的一种 只要在逻辑上相互能转化 一般都可以使用

  比如说如下几种声明都是正确的:  

  

      [return: MarshalAs(UnmanagedType Interface)]   [DllImport( ole dll  ExactSpelling=true  PreserveSig=false)]   public static extern object CoCreateInstance([In] ref Guid clsid         [MarshalAs(UnmanagedType Interface)] object punkOuter  int context  [In] ref Guid iid);        [DllImport( ole dll  ExactSpelling=true  PreserveSig=false)]   public static extern IntPtr CoCreateInstance([In] ref Guid clsid         IntPtr punkOuter  int context  [In] ref Guid iid);      [DllImport( ole dll  ExactSpelling=true)]  public static extern int CoCreateInstance([In] ref Guid clsid        IntPtr punkOuter  int context  [In] ref Guid iid  [Out] out IntPtr pVoid);     [DllImport( ole dll  ExactSpelling=true)]  public static extern int CoCreateInstance([In] ref Guid clsid        [MarshalAs(UnmanagedType Interface)] object punkOuter  int context        [In] ref Guid iid  [MarshalAs(UnmanagedType Interface)  Out] out object pVoid); 

  甚至于当你有里面对应的接口类型的声明的时候 完全可以把上面的object或IntPtr换成相应的接口类型 前提是你的接口类型的声明一定要正确 读者中用C++做过的一定对这种方式记忆犹新吧 只不过这里不再需要什么CoInitialize和CoUninitialize NET内部自己帮你搞定了 顺便提一下 上面例子中的object与IntPtr声明是相通的 我们可以用Marshal GetObjectForIUnknown和Marshal GetIUnknownForObject这两个方法在object和IntPtr之间互转 前题当然是这两种方式所指向的都是对象才行 这种方式提供的传入参数最多 创建对象也最灵活

   直接声明空成员的类

  可能很多程序员对于这个不太理解这是什么意思 没关系咱还是 用代码来说话

  

      [ComImport  Guid( DE C FF C D BB F C FAE DA )]   public class JetEngineClass            [ComImport  CoClass(typeof(JetEngineClass))  Guid( F D FF D BB F C FAE DA )]   public interface IJetEngine          void CompactDatabase(          [In  MarshalAs(UnmanagedType BStr)] string SourceConnection            [In  MarshalAs(UnmanagedType BStr)] string Destconnection          );      void RefreshCache([In  MarshalAs(UnmanagedType Interface)] object Connection);      JetEngineClass engine = new JetEngineClass();  IJetEngine iengine = engine as IJetEngine;  // iengine即是所要用的接口的引用

  大家看到了上面声明的JetEngineClass类只有一个单单的类声明 但是没有一个成员声明 但是和一般的类声明有些不一样的是这个类多了两个特性(Attribute) 把这个类和对象联系在一起的就是这两个特性了 其中一个是ComImportAttribute 这个特性指明了所作用的类是从对象中来的 GuidAttribute指明了对象的GUID 也就是说明了创建这个需用到的GUID 有了这两个特性以后 这个类就不是一个普通的类了 当我们使用new去创建实例的时候 CLR看到了声明的这两特性就知道要创建的是一个对象 根据提供的GUID也就能创建出指定的对象 并和new返回的对象实例关联在一起了

  终上 种方法我们可以看出来 第一种方式只对特定的对象有效 不具有通用性 第二种方式只需要知道对象的CLSID或PROGID就可以了 是我们在 NET里平时比较常用的创建对象的方法 第三种方式需要自己声明一个外部方法 而且需要传入若干的参数 还需要知道对象模型 是单线程呢还是多线程 进程内呢还是进程外 两个字 麻烦 对CoCreateInstance这个方法不是很熟悉的人来说 用起来就不那么顺手了 第四种方式用起来最像是 NET的方式 也最简单省事 和其它 NET对象的创建方式最为接近 四种方法各有各有好处 我觉得简单的对象 用第二种和第四种是最好的(我个人来说最喜欢第四种)又不生成额外的程序集 要是对象相关的比较多 比如说Excel之类的对象 我建议还是用导入类型库包装吧 虽然是有可能出现版本问题 但这种应该很容易要求目标机器上运行的版和开发的时候一致的 更何况版本问题也不是 %出现 只是很少一部分会出这样的问题 最不推荐的就是第三种方式了 这种方式在我看来唯一用到的地方就是使用IntPtr作为对象和接口的指针的时候 或者是想要在创建对象的时候 对参数作最灵活的控制的时候 因为其它三种方式既不能返回IntPtr指针(其实也可以通过前面提到的的Marshal类的方法把 NET包装的对象转成指针) 也不能提供与直接调用CoCreateInstance函数提供最全面的参数相匹配的方式

  最后提个小问题

   读者有兴趣的话可以去看看这几种方式(不包括第三种)生成的对象的引用的类型是否是一致的 也就是用GetType得到的Type是否是一致的

   大家猜猜这段代码运行后 iengine的类型会是什么(GetType的结果) 会和engine的类型一样吗?

  

    JetEngineClass engine = new JetEngineClass();  IJetEngine iengine = engine as IJetEngine;  // iengine即是所要用的接口的引用    IntPtr p = Marshal GetIUnknownForObject(engine);  iengine = Marshal GetObjectForIUnknown(p) as IJetEngine;

cha138/Article/program/net/201311/13971

相关参考

知识大全 C#中COM操作(一)---实例化[2]

C#中COM操作(一)---实例化[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  直接声明

知识大全 C#中让程序只运行一个实例的操作方法

C#中让程序只运行一个实例的操作方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  让程序只运行

知识大全 asp调用c#编制的com组件实例

 新建类库MyTestDLL  右击项目“MyTestDLL”》属性》生成》勾选“为互操作注册”  打开 AssemblyInfocs&nb

知识大全 编程中使用C#的BitmapData实例

编程中使用C#的BitmapData实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  最近要转

知识大全 C#多线程编程实例

C#多线程编程实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  问题的提出  所谓单个写入程序

知识大全 C#数据回滚实例

C#数据回滚实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  privatevoidsave_

知识大全 使用C#的BitmapData 编程实例

使用C#的BitmapData编程实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  最近要转开

知识大全 C#高级编程读写文本文件实例

C#高级编程读写文本文件实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  理论上可以使用Fil

知识大全 C#接口基础知识实例讲解

C#接口基础知识实例讲解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  从技术上讲接口是一组包含

知识大全 C# TextBox事件实现实例详解

C#TextBox事件实现实例详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  C#TextB