今天我們來分析QueryInterface函數。
<a href="https://s5.51cto.com/oss/201711/22/38d0cab7fa23ec2768adbcc1cfed8117.png-wh_500x0-wm_3-wmp_4-s_3770056964.png" target="_blank"></a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<code>HRESULT</code> <code>CDictionary::QueryInterface(</code><code>const</code> <code>IID& iid, </code><code>void</code> <code>**ppv)</code>
<code>{</code>
<code> </code><code>if</code><code>(iid == IID_IUnknown)</code>
<code> </code><code>{</code>
<code> </code><code>*ppv = (IDictionary*)</code><code>this</code><code>;</code>
<code> </code><code>((IDictionary*)(*ppv))->AddRef(); </code>
<code> </code><code>}elseif(iid == IID_Dictionary)</code>
<code> </code><code>((IDictionary*)(*ppv))->AddRef();</code>
<code> </code><code>}elseif(iid == IID_SpellCheck)</code>
<code> </code><code>*ppv = (ISpellCheck*)</code><code>this</code><code>;</code>
<code> </code><code>((ISpellCheck*)(*ppv))->AddRef();</code>
<code> </code><code>}</code>
<code> </code><code>else</code>
<code> </code><code>*ppv = NULL;</code>
<code> </code><code>return</code> <code>E_NOINTERFACE;</code>
<code> </code>
<code> </code><code>return</code> <code>S_OK; </code>
<code>}</code>
根據COM接口的記憶體接口以及C++語言中類多重繼承的記憶體結構,我們實作QueryInterface函數。
QueryInterface函數對于iid的三種可能值分别進行了處理,不管客戶要想查詢字典對象所支援的哪個接口,QueryInterface都會傳回相應的接口指針,如圖,當我們将this指針轉換為基類指針時,所得到的指針正好指向接口的vtable,是以我們用類型轉換函數就可以得到每個接口的vtable,也就是接口指針。
在第一個if語句塊中,我們并沒有把this指針直接轉換為IUnknown指針,根據C++文法,由于在CDictionary的基類樹中,有兩個IUnknown節點,是以直接把this指針轉換成IUnknown指針存在二義性。
先把this指針轉換成IDictionary或者ISpellCheck,再轉換成IUnknown,但必須保證每次查到的IUnknown接口完全一緻。
這個程式直接把IDictionary接口指針當做IUnknown接口指針,這樣的轉換是符合COM規範的。
根據CDictionary的基類樹,這裡的繼承關系不能用虛拟繼承,否則就不能保證IDictionary和ISpellCheck的vtable與COM接口的vtable的一緻性。
本文轉自 liam2199 部落格,原文連結: http://blog.51cto.com/liam2199 如需轉載請自行聯系原作者