.NET 4.0 Interop新特性ICustomQueryInterface (转载)
.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!!!
Published Monday, August 10, 2009 11:34 AM by SilverlightShanghai
轉自:http://blogs.msdn.com/silverlightshanghai/archive/2009/08/10/net-4-0-interop-icustomqueryinterface.aspx
?
轉載于:https://www.cnblogs.com/wuhenke/archive/2010/01/23/1654657.html
總結
以上是生活随笔為你收集整理的.NET 4.0 Interop新特性ICustomQueryInterface (转载)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 修眉多少钱啊?
- 下一篇: 禁止拖放对象文本被选择