C++ COM編程之QueryInterface函數(shù)(一)
前言
組件對(duì)外公布的是接口;一個(gè)組件可以實(shí)現(xiàn)多個(gè)接口,也就是說(shuō)可以對(duì)外公布多個(gè)接口,之前也總結(jié)過(guò)了,你很少會(huì)100%的去完全了解一個(gè)組件的所有接口,就像你去學(xué)習(xí)編程一樣,你幾乎不可能去成為編程中的全才。那么,既然我們不能去完全的了解一個(gè)組件提供的所有接口,那么我們?cè)趯?shí)際開(kāi)發(fā)中,如何去判斷一個(gè)組件是否提供對(duì)應(yīng)的接口呢?看文檔?是的,是個(gè)好主意,在文檔的海洋,找到一個(gè)知識(shí)點(diǎn),真的很難,浪費(fèi)時(shí)間和精力;其實(shí),組件本身就提供對(duì)自己查詢(xún)的一個(gè)接口,讓客戶(hù)去詢(xún)問(wèn)組件,問(wèn)它是否支持某個(gè)接口,在經(jīng)過(guò)多次的這種詢(xún)問(wèn)之后,客戶(hù)對(duì)于組件的認(rèn)識(shí)將越來(lái)越清晰;而我這篇文章和下一篇文章就是對(duì)這種詢(xún)問(wèn)機(jī)制進(jìn)行詳細(xì)的剖析和總結(jié)。
關(guān)于IUnknown
上面說(shuō)到組件本身提供一個(gè)對(duì)自己查詢(xún)的接口,那么這個(gè)接口是什么呢?這就是大名鼎鼎的IUnknown接口了,IUnknown接口在Windows SDK的unknwn.h中定義,它的定義如下:
interface IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void **ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
};
這里的STDMETHODCALLTYPE表示調(diào)用方式,也就是windows API的__stdcall方式??梢钥吹剑贗Unknown中定義了一個(gè)名為QueryInterface的函數(shù)??蛻?hù)可以調(diào)用QueryInterface來(lái)判斷組件是否支持某個(gè)特定的接口,而對(duì)于剩下的AddRef和Release兩個(gè)接口操作,我會(huì)在之后的文章中進(jìn)行總結(jié)。
所有的COM接口都需要繼承IUnknown接口;因此,如果某個(gè)客戶(hù)擁有一個(gè)IUnknown接口的指針,它并不需要知道它所擁有的接口指針到底是指向什么類(lèi)型的,而只需要知道此接口可以用來(lái)查詢(xún)其它接口就行了。
由于所有的COM接口都首先繼承了IUnknown,再根據(jù)對(duì)之前的文章COM編程——接口的背后 的理解,我們可以知道每個(gè)接口的vtbl中的前三個(gè)函數(shù)都是QueryInterface,AddRef和Release。這就使得所有的COM接口都可以被當(dāng)成IUnknown接口來(lái)處理。如果某個(gè)接口的vtbl中的前三個(gè)函數(shù)不是這三個(gè),那么它將不是一個(gè)COM接口。由于所有的接口都是從IUnknown繼承而來(lái)的,因此所有的接口都支持QueryInterface。所以,組件的任何一個(gè)接口都可以被客戶(hù)用來(lái)獲取它所支持的其他接口。由于所有的接口指針同時(shí)也將是IUnknown指針,客戶(hù)并不需要單獨(dú)維護(hù)一個(gè)代表組件的指針,它所關(guān)心的將僅僅是接口的指針。
既然,我們可以只用QueryInterface去詢(xún)問(wèn)組件是否支持某個(gè)接口,但是,這一切都是基于獲得了IUnknown接口指針之后,才能進(jìn)行的操作,那么如何獲得一個(gè)指向組件的IUnknown接口指針呢?我們可以實(shí)現(xiàn)一個(gè)CreateInstance函數(shù),它建立一個(gè)組件并返回一個(gè)IUnknown指針;對(duì)于客戶(hù)來(lái)說(shuō),可以調(diào)用CreateInstance獲得IUnknown指針,而不用使用new操作符了。在系統(tǒng)的總結(jié)了COM的所有基礎(chǔ)知識(shí)之后,我再說(shuō)說(shuō)系統(tǒng)提供的一個(gè)創(chuàng)建組件實(shí)例的API函數(shù)。
關(guān)于QueryInterface
IUnknown中包含一個(gè)名為QueryInterface的成員函數(shù),客戶(hù)可以通過(guò)此函數(shù)來(lái)查詢(xún)某個(gè)組件是否支持某個(gè)特定的接口。若支持,QueryInterface將返回一個(gè)指向此接口的指針;否則返回值將是一個(gè)錯(cuò)誤代碼;然后客戶(hù)可以接著查詢(xún)其它接口。
從QueryInterface函數(shù)的聲明中可以看出,QueryInterface有兩個(gè)參數(shù),第一個(gè)參數(shù)標(biāo)識(shí)客戶(hù)所需的接口,這個(gè)參數(shù)是一個(gè)接口標(biāo)識(shí)符(IID)結(jié)構(gòu),在之后的文章中,我會(huì)總結(jié)有關(guān)IID的知識(shí)的;第二個(gè)參數(shù)用來(lái)存放所請(qǐng)求的接口的地址。QueryInterface返回的是一個(gè)HRESULT值,它是一個(gè)具有特定結(jié)構(gòu)的32位值,之后我也會(huì)進(jìn)行總結(jié)的;對(duì)于返回的HRESULT值,在實(shí)際開(kāi)發(fā)中,需要使用SUCCEEDED宏或FAILED宏去進(jìn)行判斷HRESULT值是表示成功還是失敗。
QueryInterface的簡(jiǎn)單實(shí)現(xiàn)
總結(jié)了QueryInterface的簡(jiǎn)單實(shí)現(xiàn),說(shuō)白了,就是簡(jiǎn)單工廠(chǎng)模式的實(shí)現(xiàn);上面也說(shuō)了,就是根據(jù)客戶(hù)提供的IID接口標(biāo)識(shí)符,然后獲得對(duì)應(yīng)的接口的指針,返回對(duì)應(yīng)的接口的指針;如果組件支持客戶(hù)指定的接口,那么應(yīng)返回S_OK以及相應(yīng)的指針;若不支持,返回值應(yīng)是E_NOINTERFACE,并將相應(yīng)的指針?lè)祷刂抵贸蒒ULL。下面通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明QueryInterface的簡(jiǎn)單實(shí)現(xiàn):
比如有上述的一個(gè)結(jié)構(gòu);接口IX和IY都繼承自IUnknown接口,組件CA實(shí)現(xiàn)了IX和IY接口,那么QueryInterface的實(shí)現(xiàn)應(yīng)該像下面這樣:
HRESULT __stdcall CA::QueryInterface(const IID &iid, void **ppv)
{
if (iid == IID_IUnknown)
{
*ppv = static_cast<IX *>(this);
}
else if (iid == IID_IX)
{
*ppv = static_cast<IX *>(this);
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY *>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown *>(*ppv)->AddRef();
return S_OK;
}
QueryInterface的簡(jiǎn)單使用
當(dāng)我獲得了一個(gè)IUnknown指針以后,就可以調(diào)用對(duì)應(yīng)的QueryInterface進(jìn)行查詢(xún)了,如下:
void Fod(IUnknown *pI)
{
IX *pIX = NULL;
// Ask for interface IX
HRESULT hr = pI->QueryInterface(IID_IX, (void **)&pIX);
// Check the return value
if (SUCCEEDED(hr))
{
// Use the interface
pIX->Fx();
}
}
完整的例子
上面說(shuō)了那么多了,現(xiàn)在提供一個(gè)完整的例子,將上面的各種理論知識(shí)都在實(shí)際代碼中進(jìn)行了實(shí)踐,讓各位能更好的理解QueryInterface。(下載)。
總結(jié)
QueryInterface理解起來(lái)比較簡(jiǎn)單,但是,它的理論知識(shí)還是必須要去掌握的,理論是一切的基礎(chǔ),沒(méi)有理論作為支撐,任何實(shí)際的操作都不會(huì)那么可靠和可信,所以,這篇文章總結(jié)的偏于理論多一些。由于QueryInterface部分的內(nèi)容比較多,使用一篇文章無(wú)法總結(jié)的齊全,所以,之后我還會(huì)繼續(xù)總結(jié)關(guān)于QueryInterface的第二部分。
欄 目:C語(yǔ)言
下一篇:C++設(shè)計(jì)模式之外觀(guān)模式
本文標(biāo)題:C++ COM編程之QueryInterface函數(shù)(一)
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3322.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類(lèi)算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解
- 01-10深入理解C/C++混合編程


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實(shí)例總結(jié)
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什