今天我們來分析QueryInterface函數。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQjN5YTNwAzN3MzXz1CNfBXb31yMf12dtADewATNfh2dtcmbw5yNxEDOkVmZjFzYjJGZhhjN3IzYlNjMhZ2NiF2YwQGOz8CXyIzLcFTM3EDMy8CXzN3bvwVbvNmLvR3YxUjL1M3Lc9CX6MHc0RHaiojIsJye.png)
HRESULT CDictionary::QueryInterface(const IID& iid, void **ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (IDictionary*)this;
((IDictionary*)(*ppv))->AddRef();
}elseif(iid == IID_Dictionary)
{
*ppv = (IDictionary*)this;
((IDictionary*)(*ppv))->AddRef();
}elseif(iid == IID_SpellCheck)
{
*ppv = (ISpellCheck*)this;
((ISpellCheck*)(*ppv))->AddRef();
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
根據COM接口的記憶體接口以及C++語言中類多重繼承的記憶體結構,我們實作QueryInterface函數。
QueryInterface函數對于iid的三種可能值分别進行了處理,不管客戶要想查詢字典對象所支援的哪個接口,QueryInterface都會傳回相應的接口指針,如圖,當我們将this指針轉換為基類指針時,所得到的指針正好指向接口的vtable,是以我們用類型轉換函數就可以得到每個接口的vtable,也就是接口指針。
在第一個if語句塊中,我們并沒有把this指針直接轉換為IUnknown指針,根據C++文法,由于在CDictionary的基類樹中,有兩個IUnknown節點,是以直接把this指針轉換成IUnknown指針存在二義性。
先把this指針轉換成IDictionary或者ISpellCheck,再轉換成IUnknown,但必須保證每次查到的IUnknown接口完全一緻。