.NET 4.0的ICustomQueryInterface新特性

开发 后端
本文介绍了.NET 4.0的命名空间中的ICustomQueryInterface新特性。顾名思义,这个Interface的功能就是使得用户可以自己控制QueryInterface这个COM最常用的函数的行为。

在.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的话,一定会因此而雀跃不已的。我会在另一篇文章中通过例程给大家做一个详细的介绍。

让我们来看看这个ICustomQueryInterface的定义吧:

  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的处理流程图吧:

关于QI的处理流程图
.NET 4.0新特性:ICustomQueryInterface

从这个图上我们可以看到,除了不能处理对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:

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

再来看看我们的客户端

  1. IDispatch * pDisp = NULL;  
  2. printf("Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface\n");  
  3. hresult = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDisp);  
  4.  
  5. UINT count  = 0;  
  6. hresult = pDisp->GetTypeInfoCount(&count);  
  7. printf("Return value of GetTypeInfoCount is %d\n", count);    
  8.  
  9. IA * pA = NULL;  
  10. printf("Scenario 2: QI IA interface, Expected failed\n");  
  11. hresult = pUnknown->QueryInterface(IID_IA, (void**)&hresult);  
  12. if (FAILED(hresult))  
  13. {  
  14.   printf("Failed to QI IA with error code %x\n", count);    
  15. }  
  16. IB * pB = NULL;  
  17. printf("Scenario 3: QI IB interface interface, Expected the IB interface\n");  
  18. hresult = pUnknown->QueryInterface(IID_IB, (void**)&pB);  
  19. long i  = 0;  
  20. hresult = pB->FuncB(&i);  
  21.    

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

  1. Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface 
  2. This is Interface ICQ, not the IDispatch!!!  
  3. Return value of GetTypeInfoCount is 2008  
  4. Scenario 2: QI iA interface, Expected failed  
  5. Failed to QI IA with error code 7d8  
  6. Scenario 3: QI IB interface interface, Expected the IB interface 
  7. This is Interface IB!!!  
  8.  

以上就介绍了.NET 4.0的命名空间中的ICustomQueryInterface新特性。

【编辑推荐】

  1. C#数据库查询和操作大全
  2. 简单介绍C#预处理
  3. 学习C#无词尾符号经验谈
  4. C#调用QuickTest自动化
  5. 详解C#正规表达式
责任编辑:yangsai 来源: CSDN博客
相关推荐

2009-09-04 16:28:05

ASP.NET 4.0

2009-12-30 10:21:36

.NET 4.0

2010-01-05 09:26:13

.NET 4.0

2010-02-24 14:24:35

.NET 4.0

2009-08-18 09:37:42

ASP.NET 4.0

2009-07-06 11:00:56

.NET 4.0新特性.NET

2018-11-15 14:05:24

MongoDB数据库事务

2009-08-19 16:51:14

C# 4.0 dyna

2009-05-26 09:28:22

C# 4.0dynamic动态类型

2009-07-30 13:17:44

STM.NET.NET 4 Beta

2009-05-26 11:15:31

C# 4.0dynamicVisual Stud

2012-01-09 16:00:56

2010-08-17 09:57:39

C#

2009-07-30 14:55:43

ASP.NET 2.0

2009-03-12 11:26:35

Data ServicADO.NET.NET

2009-11-04 14:17:34

ADO.NET 2.0

2009-11-04 15:44:39

ADO.NET Sql

2009-11-03 09:37:33

VB.NET重载

2011-01-14 10:27:18

C#.netasp.net

2011-01-15 23:07:59

点赞
收藏

51CTO技术栈公众号