.NET 4.0 Interop新特性ICustomQueryInterface
在.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相关推荐
- .NET 4.0 Interop新特性ICustomQueryInterface (转载)
.NET 4.0 Interop新特性ICustomQueryInterface 在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServ ...
- .NET Framework 4.0的新特性
本文将揭示.NET 4.0中的3个新特性:图表控件.SEO支持以及ASP.NET 4可扩展的输出缓存. 图表控件 微软向开发者提供了大量可免费下载的图表控件,可以在.NET 3.5 ASP.NET或W ...
- mysql 5.0 php_PHP 5.0的新特性
PHP 5.0的新特性 最近,读者可以从PHP 4.x版本转移到PHP 5.0版本.正如读者期望的那样,在一个新的主要版本中,它做出了一些重要变更.在这个版本中,PHP后台的Zend引擎经过了完全的重 ...
- Tensorflow 2.0的新特性
Tensorflow 2.0的新特性 几天前,Tensorflow刚度过自己的3岁生日,作为当前最受欢迎的机器学习框架,Tensorflow在这个宝座上已经盘踞了近三年.无论是成熟的Keras,还是风 ...
- java 7.0 特性_JDK7.0语法新特性
JDK7.0语法新特性 1,菱形语法(泛型实例化类型自动推断) List list = new ArrayList<>(); // <>这个真的很像菱形 2,在目前版本中,不可 ...
- 盘点Greenplum 6.0六大新特性及展望
导读:本文介绍Greenplum 6.0的新特性. 作者:王春波 来源:大数据DT(ID:hzdashuju) Greenplum 6.0于2019年9月4日正式发布,内核版本从PostgreSQL ...
- C# 8.0 的新特性概览和讲解
本文转自 https://blog.csdn.net/hez2010/article/details/84036742 C# 8.0 的新特性概览和讲解 前言 新的改变 可空引用类型(Nullable ...
- jdk5.0的新特性
jdk的版本在1.4后变化很大,所以叫jdk5.0 下面是总结jdk5.0的新特性: (1)泛型(***) 泛型简介 泛型是J2SE 5.0最重要的特性.他们让你写一个type(类或接口)和创建一个 ...
- 《iOS9开发快速入门》——第2章,第2.1节Xcode 7.0的新特性
本节书摘来自异步社区<iOS9开发快速入门>一书中的第2章,第2.1节Xcode 7.0的新特性,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众 ...
最新文章
- xpath 获取当前节点的父节点,兄弟节点的方法
- Storm概念学习系列之storm-starter项目(完整版)(博主推荐)
- button 样式_实战PyQt5: 111-可以使用QSS样式表的部件
- Ruby Regexp
- 50 CO配置-控制-获利能力分析-维护经营关注点
- 图解HTTP知识框架
- IOHK与World Mobile合作以在坦桑尼亚建立新移动网络
- 【十四】无验证码登录配置:通过登录接口获取 token 配置全局变量
- 【风马一族_C】进制转化
- IBM T43 开机停止在LOGO画面
- 简单的使用git克隆上传创建下载删除
- VC++ Call Stack调试
- 信道编码与matlab仿真 刘东华,【网安学术】交织技术对信道编码的性能影响研究...
- Windows安全中心内存完整性无法打开问题的处理方法
- 学习笔记 Tianmao 篇 recyclerView 辅助的RecycleAdapterImpl类(适配自定义care 一型 使用了frecso SimpleDraweeView)
- 【面试概率】52张扑克牌,红桃A和黑桃A同时被一个人拿到的概率
- codeup3692 星期英文单词
- 《迷人的8051单片机》——导读
- 延长SQLyog试用期
- Java日志(slf4j+logback)及打印彩色日志
热门文章
- 数据权限简单设计思路
- 基于Ant Design vue框架之三 删除功能细分
- mysql多条件count_Mysql中使用count加条件统计
- 使用printf语句输出名言:“贵有恒,何必三更起五更睡:最无益,只怕一日曝十日寒。“
- Ubuntu16.04使用ninja编译安装LLVM
- scaling之旅_【scaling】什么意思_英语scaling的翻译_音标_读音_用法_例句_在线翻译_有道词典...
- c语言case2什么意思,switchCase2
- SAP 移动价(V)与标准价(S)
- 程序员的选择,技术or管理
- ZZULIOJ: 1187: 棒棒糖(结构体专题)