COM元件非常好的分析文章
轉載於http://blog.sina.com.cn/s/blog_470ecf2a01014ahy.html
(1)COM元件有三個最基本的介面類,分別是IUnknown、IClassFactory、IDispatch。
COM規範規定任何元件、任何介面都必須從IUnknown繼承,IUnknown包含三個函式,分別是 QueryInterface、AddRef、Release。這三個函式是無比重要的,而且它們的排列順序也是不可改變的。
IClassFactory的作用是建立COM元件。我們已經知道COM元件實際上就是一個類,那我們平常是怎麼例項化一個類物件的?是用'new’命令!很簡單吧,COM元件也一樣如此。但是誰來new它呢?不可能是客戶程式,因為客戶程式不可能知道元件的類名字,如果客戶知道元件的類名字那元件的可重用性就要打個大大的折扣了,事實上客戶程式只不過知道一個代表著元件的128位的數字串而已,這個等會再介紹。所以客戶無法自己建立元件,而且考慮一下,如果元件是在遠端的機器上,你還能new出一個物件嗎?所以建立元件的責任交給了一個單獨的物件,這個物件就是類廠。每個元件都必須有一個與之相關的類廠,這個類廠知道怎麼樣建立元件,當客戶請求一個元件物件的例項時,實際上這個請求交給了類廠,由類廠建立元件例項,然後把例項指標交給客戶程式。這個過程在跨程序及遠端建立元件時特別有用,因為這時就不是一個簡單的new操作就可以的了,它必須要經過排程,而這些複雜的操作都交給類廠物件去做了。IClassFactory最重要的一個函式就是CreateInstance,顧名思議就是建立元件例項,一般情況下我們不會直接呼叫它,API函式都為我們封裝好它了,只有某些特殊情況下才會由我們自己來呼叫它,這也是VC編寫COM元件的好處,使我們有了更多的控制機會,而VB給我們這樣的機會則是太少太少了。
IDispatch叫做排程介面。它的作用何在呢?這個世上除了C++還有很多別的語言,比如VB、 VJ、VBScript、JavaScript等等。可以這麼說,如果這世上沒有這麼多亂七八糟的語言,那就不會有IDispatch。:-) 我們知道COM元件是C++類,是靠虛擬函式表來呼叫函式的,對於VC來說毫無問題,這本來就是針對C++而設計的,以前VB不行,現在VB也可以用指標了,也可以通過VTable來呼叫函數了,VJ也可以,但還是有些語言不行,那就是指令碼語言,典型的如 VBScript、JavaScript。不行的原因在於它們並不支援指標,連指標都不能用還怎麼用多型性啊,還怎麼調這些虛擬函式啊。唉,沒辦法,也不能置這些指令碼語言於不顧吧,現在網頁上用的都是這些指令碼語言,而分散式應用也是COM元件的一個主要市場,它不得不被這些指令碼語言所呼叫,既然虛擬函式表的方式行不通,我們只能另尋他法了。時勢造英雄,IDispatch應運而生。:-) 排程介面把每一個函式每一個屬性都編上號,客戶程式要呼叫這些函式屬性的時侯就把這些編號傳給IDispatch介面就行了,IDispatch再根據這些編號呼叫相應的函式,僅此而已。當然實際的過程遠比這複雜,僅給一個編號就能讓別人知道怎麼呼叫一個函式那不是天方夜潭嗎,你總得讓別人知道你要呼叫的函式要帶什麼引數,引數型別什麼以及返回什麼東西吧,而要以一種統一的方式來處理這些問題是件很頭疼的事。IDispatch介面的主要函式是Invoke,客戶程式都呼叫它,然後Invoke再呼叫相應的函式,如果看一看MS的類庫裡實現 Invoke的程式碼就會驚歎它實現的複雜了,因為你必須考慮各種引數型別的情況,所幸我們不需要自己來做這件事,而且可能永遠也沒這樣的機會。:-)
IUnknown
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void __RPC_FAR *__RPC_FAR *ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
};
QueryInterface用於查詢元件實現的其它介面。COM規範規定任何元件、任何介面都必須從IUnknown繼承,IUnknown包含三個函式,分別是 QueryInterface、AddRef、Release。這三個函式是無比重要的,而且它們的排列順序也是不可改變的。
IClassFactory
IClassFactory : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE CreateInstance(
IUnknown *pUnkOuter,
REFIID riid,
void **ppvObject) = 0;
virtual HRESULT STDMETHODCALLTYPE LockServer(
BOOL fLock) = 0;
};
IClassFactory的作用是建立COM元件。我們已經知道COM元件實際上就是一個類,那我們平常是怎麼例項化一個類物件的?是用‘new’命令!很簡單吧,COM元件也一樣如此。但是誰來new它呢?不可能是客戶程式,因為客戶程式不可能知道元件的類名字,如果客戶知道元件的類名字那元件的可重用性就要打個大大的折扣了,事實上客戶程式只不過知道一個代表著元件的128位的數字串而已,
IClassFactory最重要的一個函式就是CreateInstance,顧名思議就是建立元件例項,一般情況下我們不會直接呼叫它,API函式都為我們封裝好它了,只有某些特殊情況下才會由我們自己來呼叫它,這也是VC編寫COM元件的好處,使我們有了更多的控制機會,而VB給我們這樣的機會則是太少太少了。
IDispatch
IDispatch : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
UINT *pctinfo) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
UINT iTInfo,
LCID lcid,
ITypeInfo **ppTInfo) = 0;
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId) = 0;
virtual HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr) = 0;