在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServices新增加了一个叫做ICustomQueryInterface的Interface, 顾名思义,这个Interface的功能就是使得用户可以自己控制QueryInterface这个COM最常用的函数的行为。在v4.0以前,所有作用于托管组件上的QI行为,都是由CLR内部的IUnkown:QueryInterface控制的,比如,如果你QI著名的IDispatch接口时,你得到的永远都是CLR提供的那个IDispatch,诸如此类的还有IMarshal/IProvideClassInfo等一些常用的Interface。如果你非常希望用自己的IDispatch实现来替换clr提供的实现,那么恭喜你,ICustomQueryInterface就是为你而生的!当然,ICustomQueryInterface所带来的,不仅仅是简单的Interface替换,它甚至可以使得Aggregate托管组件也成为现实,wow,如果你了解Aggregation的话,一定会因此而雀跃不已的。我会在另一篇文章中通过例程给大家做一个详细的介绍。

让我们来看看这个Interface的定义吧

  1: public interface ICustomQueryInterface

  2: {

  3:     CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv);

  4: }

  5: 

是的,就是这么简单,就一个GetInterface方法,再仔细看看它的方法参数,是不是和c++里面的QueryInterface有点神似啊。哈哈,其实你可以把它理解成QueryInterface的托管实现也无妨啊!不过它还有个小小的功能,就是如果自己不想处理这个QI,就返回NotHandled, clr看到这个返回值,就会调用自己的QI实现来帮你处理这个请求,爽吧。

让我们来看看有了这个Interface之后clr内部关于QI的处理流程图吧(画的是英文版,烦请大家将就一下啦,没装viso,画图超级累啊!!!!)

从这个图上我们可以看到,除了不能处理对IUnknown的QI请求(要求别太高嘛),其他统统OK!

理论一大堆了,来实战一下。

看看我们的托管组件的实现

  1: using System;

  2: using System.Runtime.InteropServices;

  3:

  4: namespace States

  5: {

  6:     [Guid("00020400-0000-0000-C000-000000001147")]

  7:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

  8:     public interface ICQ

  9:     {

 10:         int func();

 11:         void slot2();

 12:         void slot3();

 13:         void slot4();

 14:     }

 15:

 16:     [Guid("11120400-0000-0000-C000-000000001148")]

 17:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

 18:     public interface IA

 19:     {

 20:         int FuncA();

 21:     }

 22:

 23:     [Guid("22220400-0000-0000-C000-000000001149")]

 24:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

 25:     public interface IB

 26:     {

 27:         int FuncB();

 28:     }

 29:

 30:

 31:

 32:     [Guid("00020400-0000-0000-C000-000000001150")]

 33:     [ClassInterface(ClassInterfaceType.None)]

 34:     public class StatesComServer : ICustomQueryInterface, ICQ, IA, IB

 35:     {

 36:           public readonly Guid IID_IA = new Guid("11120400-0000-0000-C000-000000001148");

 37:

 38:           public CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr intf)

 39:           {

 40:                 if (iid == WellKnownGuids.IID_IDispatch)

 41:                 {

 42:                     intf = Marshal.GetComInterfaceForObject(this, typeof(ICQ), CustomQueryInterfaceMode.Ignore);

 43:                     return CustomQueryInterfaceResult.Handled;

 44:                 }

 45:

 46:                 if (iid == IID_IA)

 47:                 {

 48:                     intf = IntPtr.Zero;

 49:                     return CustomQueryInterfaceResult.Failed;

 50:                 }

 51:

 52:                 intf = IntPtr.Zero;

 53:                 return CustomQueryInterfaceResult.NotHandled;

 54:           }

 55:

 56:           public int func()

 57:           {

 58:               Console.WriteLine("This is Interface ICQ, not the IDispatch!!!");

 59:                return 2008;

 60:           }

 61:

 62:           public int FuncA()

 63:           {

 64:               Console.WriteLine("This is Interface IA!!!");

 65:               return 3008;

 66:           }

 67:

 68:           public int FuncB()

 69:           {

 70:               Console.WriteLine("This is Interface IB!!!");

 71:               return 4008;

 72:           }

 73:

 74:

 75:         #region Empty Functions

 76:           public void slot2() { }

 77:           public void slot3() { }

 78:           public void slot4() { }

 79:         #endregion

 80:     }

 81:

 82: }

 83: 

这里有两个地方需要解释一下

1)对于ICQ这个接口,他实际上是作为自定义的IDispatch出现的,所以理论上应该他所有的函数声明应该和IDispatch保持一致,但是个人比较偷懒,毕竟这只是一个例程,主要是将如何使用ICustomQueryInterface这个接口,所以后三个方法的用途仅仅是为了保持ICQ的虚拟函数表(一共4个函数)和IDispatch保持一致,如果真的有人在客户端调IDispatch.Invoke(函数表中的第四个函数)的话,那调用必然会被重定向到ICQ.slot4,因为两个函数的参数声明完全不一样,AccessViolationException就无法避免了。

2)再讲一下GetInterface的返回值,如果是CustomQueryInterfaceResult.Failed,意思是QI失败。CustomQueryInterfaceResult.NotHandled意思是让clr去处理这个请求,CustomQueryInterfaceResult.Handled是告诉clr,已经处理好了,指针值保存在intf里面,直接返回给用户就可以了。

再来看看我们的客户端

  IDispatch * pDisp = NULL;

  printf("Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface/n");

  hresult = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDisp);



  UINT count  = 0;

  hresult = pDisp->GetTypeInfoCount(&count);

  printf("Return value of GetTypeInfoCount is %d/n", count);



  IA * pA = NULL;

  printf("Scenario 2: QI IA interface, Expected failed/n");

  hresult = pUnknown->QueryInterface(IID_IA, (void**)&pA);

  if (FAILED(hresult))

  {

    printf("Failed to QI IA with error code %x/n", count);

  }

  IB * pB = NULL;

  printf("Scenario 3: QI IB interface interface, Expected the IB interface/n");

  hresult = pUnknown->QueryInterface(IID_IB, (void**)&pB);

  long i  = 0;

  hresult = pB->FuncB(&i);

    

再来看看我们的输出结果。

Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface

This is Interface ICQ, not the IDispatch!!!

Return value of GetTypeInfoCount is 2008

Scenario 2: QI iA interface, Expected failed

Failed to QI IA with error code 7d8

Scenario 3: QI IB interface interface, Expected the IB interface

This is Interface IB!!!
												

.NET 4.0 Interop新特性ICustomQueryInterface相关推荐

  1. .NET 4.0 Interop新特性ICustomQueryInterface (转载)

    .NET 4.0 Interop新特性ICustomQueryInterface 在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServ ...

  2. .NET Framework 4.0的新特性

    本文将揭示.NET 4.0中的3个新特性:图表控件.SEO支持以及ASP.NET 4可扩展的输出缓存. 图表控件 微软向开发者提供了大量可免费下载的图表控件,可以在.NET 3.5 ASP.NET或W ...

  3. mysql 5.0 php_PHP 5.0的新特性

    PHP 5.0的新特性 最近,读者可以从PHP 4.x版本转移到PHP 5.0版本.正如读者期望的那样,在一个新的主要版本中,它做出了一些重要变更.在这个版本中,PHP后台的Zend引擎经过了完全的重 ...

  4. Tensorflow 2.0的新特性

    Tensorflow 2.0的新特性 几天前,Tensorflow刚度过自己的3岁生日,作为当前最受欢迎的机器学习框架,Tensorflow在这个宝座上已经盘踞了近三年.无论是成熟的Keras,还是风 ...

  5. java 7.0 特性_JDK7.0语法新特性

    JDK7.0语法新特性 1,菱形语法(泛型实例化类型自动推断) List list = new ArrayList<>(); // <>这个真的很像菱形 2,在目前版本中,不可 ...

  6. 盘点Greenplum 6.0六大新特性及展望

    导读:本文介绍Greenplum 6.0的新特性. 作者:王春波 来源:大数据DT(ID:hzdashuju) Greenplum 6.0于2019年9月4日正式发布,内核版本从PostgreSQL ...

  7. C# 8.0 的新特性概览和讲解

    本文转自 https://blog.csdn.net/hez2010/article/details/84036742 C# 8.0 的新特性概览和讲解 前言 新的改变 可空引用类型(Nullable ...

  8. jdk5.0的新特性

    jdk的版本在1.4后变化很大,所以叫jdk5.0 下面是总结jdk5.0的新特性: (1)泛型(***)  泛型简介 泛型是J2SE 5.0最重要的特性.他们让你写一个type(类或接口)和创建一个 ...

  9. 《iOS9开发快速入门》——第2章,第2.1节Xcode 7.0的新特性

    本节书摘来自异步社区<iOS9开发快速入门>一书中的第2章,第2.1节Xcode 7.0的新特性,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众 ...

最新文章

  1. xpath 获取当前节点的父节点,兄弟节点的方法
  2. Storm概念学习系列之storm-starter项目(完整版)(博主推荐)
  3. button 样式_实战PyQt5: 111-可以使用QSS样式表的部件
  4. Ruby Regexp
  5. 50 CO配置-控制-获利能力分析-维护经营关注点
  6. 图解HTTP知识框架
  7. IOHK与World Mobile合作以在坦桑尼亚建立新移动网络
  8. 【十四】无验证码登录配置:通过登录接口获取 token 配置全局变量
  9. 【风马一族_C】进制转化
  10. IBM T43 开机停止在LOGO画面
  11. 简单的使用git克隆上传创建下载删除
  12. VC++ Call Stack调试
  13. 信道编码与matlab仿真 刘东华,【网安学术】交织技术对信道编码的性能影响研究...
  14. Windows安全中心内存完整性无法打开问题的处理方法
  15. 学习笔记 Tianmao 篇 recyclerView 辅助的RecycleAdapterImpl类(适配自定义care 一型 使用了frecso SimpleDraweeView)
  16. 【面试概率】52张扑克牌,红桃A和黑桃A同时被一个人拿到的概率
  17. codeup3692 星期英文单词
  18. 《迷人的8051单片机》——导读
  19. 延长SQLyog试用期
  20. Java日志(slf4j+logback)及打印彩色日志

热门文章

  1. 数据权限简单设计思路
  2. 基于Ant Design vue框架之三 删除功能细分
  3. mysql多条件count_Mysql中使用count加条件统计
  4. 使用printf语句输出名言:“贵有恒,何必三更起五更睡:最无益,只怕一日曝十日寒。“
  5. Ubuntu16.04使用ninja编译安装LLVM
  6. scaling之旅_【scaling】什么意思_英语scaling的翻译_音标_读音_用法_例句_在线翻译_有道词典...
  7. c语言case2什么意思,switchCase2
  8. SAP 移动价(V)与标准价(S)
  9. 程序员的选择,技术or管理
  10. ZZULIOJ: 1187: 棒棒糖(结构体专题)