国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
[筆記]COM組件初識

COM是一種組件開發(fā)技術(shù),實際是一種在二進(jìn)制層上兼容的軟件開發(fā)方法的規(guī)范,COM技術(shù)是與具體的編程語言無關(guān)的技術(shù),只要是支持COM開發(fā)的開發(fā)工具都可以用來進(jìn)行COM應(yīng)用的開發(fā),而它們在二進(jìn)制上兼容的要求由各個開發(fā)工具來實現(xiàn),絕大部分是由編譯器實現(xiàn)的。

一、組件對象模型:

1.組件

COM是開發(fā)軟件組件的一種方法,組件實際上是一些小的二進(jìn)制可執(zhí)行程序,它們可以給應(yīng)用程序、操作系統(tǒng)以及其它組件提供服務(wù)。開發(fā)自定義的COM組件就如同開發(fā)動態(tài)的、面向?qū)ο蟮?/span>API。多個COM對象可以連接起來形成應(yīng)用程序或組件系統(tǒng)。且組件可以在運(yùn)行時刻,在不被重新鏈接或編譯應(yīng)用程序的情況下被卸下或替換掉。Microsoft的許多技術(shù),如ActiveXDirectXOLE等都是基于COM建立起來的。

COM框架下,可以開發(fā)出各種各樣的功能專一的組件,然后將它們按照需要組合起來,構(gòu)成復(fù)雜的應(yīng)用系統(tǒng)。

COM所含的概念并不只是在microsoft windows 操作系統(tǒng)下有小,COM并非一個大的API,它實際上像結(jié)構(gòu)化編程及面向?qū)ο缶幊谭椒菢邮且环N編程方法。在任何一種操作系統(tǒng)中,開發(fā)人員均可以遵循“COM方法”。

將單個應(yīng)用程序分隔成單獨(dú)多個獨(dú)立的部分,即組件,這樣的好處是可以用新的組件取代已有的組件,且利用已有的組件,用戶還可以快速的建立全新的應(yīng)用。

傳統(tǒng)的做法是將應(yīng)用程序分割成文件、模塊或類,然后將它們編譯并鏈接成一個單模應(yīng)用程序。它與組件建立應(yīng)用程序的過程(稱為組件構(gòu)架)有很大不同。一個組件同一個微型應(yīng)用程序類似,都是已經(jīng)編譯鏈接好并可以使用的二進(jìn)制代碼,應(yīng)用程序就是由多個這樣的組件打包而得到的。單模應(yīng)用程序只有一個二進(jìn)制代碼模塊。自定義組件可以在運(yùn)行時刻同其他的足跡連接起來構(gòu)成某個應(yīng)用程序。

COM即組件對象模型,是關(guān)于如何建立組件以及如何通過組件建立應(yīng)用程序的一個規(guī)范,說明了如何可動態(tài)交替更新組件。

所有的組件必須滿足兩個條件:組件必須動態(tài)鏈接;必須隱藏或封裝其內(nèi)部實現(xiàn)細(xì)節(jié)。動態(tài)鏈接是組件的一個至關(guān)重要的要求,消息隱藏是動態(tài)鏈接的一個必要條件。

2.接口

對于COM來講,接口是一個包含一個函數(shù)指針數(shù)組的內(nèi)存結(jié)構(gòu)。每一個數(shù)組元素包含一個由組件所實現(xiàn)的函數(shù)地址。對于COM而言,接口就是此內(nèi)存結(jié)構(gòu),其他東西均是COM不關(guān)心的實現(xiàn)細(xì)節(jié)。

C++中,可以用抽象類來實現(xiàn)COM接口,由于一個COM組件可以實現(xiàn)支持任意數(shù)目的接口,因此對于這樣的組件,可以用抽象基類的多重繼承來實現(xiàn)。用類來實現(xiàn)組件將比其他方法更為容易。

對于客戶而言,一個組件就是一個接口集,客戶只能通過接口才能和COM組件打交道,該接口就是IUnknown。IUnknown接口定義包含在win32 SDK中的UNKNOWN.H頭文件中:

interface IUnknown

{

virtual HRESULT-__stdcall QueryInterface(const IID& iid,void **ppv)=0;

virtual ULONG__stdcall AddRef()=0;

virtual ULONG__release()=0;

};

所有COM組件都要繼承IUnknown,可以用IUnknown的接口指針來查詢該組件的其他接口,并且每個接口的vtbl中的前3個函數(shù)都是QueryInterface,AddRefRelease。這就使得所有的COM接口都可以被當(dāng)作成IUnknown接口來處理。由于所有的接口都支持QueryInterface,故組件的任一個接口都可以被客戶用來獲取它所支持的其他接口。

在用QueryInterface將組件抽象成由多個相互獨(dú)立的接口構(gòu)成的集合后,還需要管理組件的生命期。這一點是通過對接口的引用計數(shù)實現(xiàn)的??蛻舨⒉荒苤苯涌刂平M件的生命期。當(dāng)使用完一個借口而要用組件的另一個接口時,是不能將該組件釋放的。對組件的釋放可以由組件在客戶使用完所有組件之后自己完成。IUnknown的另兩個成員函數(shù)AddRefRelease的作用就是給客戶提供一種讓它指示何時處理完一個接口的手段。

AddRefRelease實現(xiàn)的是一種名為引用計數(shù)的內(nèi)存管理技術(shù)。當(dāng)客戶從組件獲得一個接口時,此引用數(shù)值將增加1;當(dāng)使用完某個接口時,組件的引用計數(shù)值將減1,當(dāng)引用計數(shù)值為0時,組件可以將自己從內(nèi)存中刪除。AddRefRelease可以增加和減少這一計數(shù)值。

3.創(chuàng)建組件

將組件分成多個接口只是將單模應(yīng)用分隔成多個部分的第一步,組件需要被仿佛動態(tài)鏈接庫(DLL)中。DLL是一個組件服務(wù)程序,或者說是發(fā)行組件的一種方式。組件可看作在DLL中實現(xiàn)的接口集。在客戶獲取某個組件接口指針之前,它必須先將相應(yīng)的DLL裝載到其進(jìn)程空間中,并創(chuàng)建此組件。

由于客戶組件需要的所有函數(shù)都可以通過某個接口指針而訪問到,因此可以在DLL中引出CreateInstance函數(shù)就可以使用戶調(diào)用它。之后,可以裝載DLL并調(diào)用其中的函數(shù),此功能可由COM庫函數(shù)CoCreateInstance來實現(xiàn)。CoCreateInstance創(chuàng)建組件的過程是:傳給它一個CLSID,然后它創(chuàng)建相應(yīng)的組件,并返回指向所請求的接口的指針。但CoCreateInstance沒有給客戶提供一種能控制組件創(chuàng)建過程的方法,缺乏一定的靈活性。常用類廠來創(chuàng)建組件。類廠就是一個帶有能夠創(chuàng)建其他組件的接口的組件。客戶先創(chuàng)建類廠本身,然后再用一個接口IClassFactory來創(chuàng)建所需的組件,然后還要用DllRegisterSeverwindows中注冊該組件。

4.復(fù)用

COM組件可以被復(fù)用,它支持“接口繼承”,這種繼承指的是一個類繼承其基類的類型或接口。抽象基類是一種最純粹的接口繼承,并且正好也被用來實現(xiàn)COM接口。在COM中,我們可以包容和聚合來對組件進(jìn)行改造。

包容是在接口級完成的,外部組件包含指向內(nèi)部接口的指針,此時外部組件只是內(nèi)部組件的一個客戶而已,它將使用內(nèi)部組件的接口來實現(xiàn)它自己的接口,外部組件也可以通過將調(diào)用轉(zhuǎn)發(fā)給內(nèi)部組件的方法來重新實現(xiàn)內(nèi)部組件所支持的某個接口。且外部組件還可以在內(nèi)部組件代碼的前后加上一些代碼以對接口進(jìn)行改造。

聚合時包容的一種變化形式。當(dāng)外部組件聚合了某個內(nèi)部組件的一個接口時,它并沒有像包容那樣重新實現(xiàn)此接口并顯式地將調(diào)用請求轉(zhuǎn)發(fā)給內(nèi)部組件。外部組件直接把內(nèi)部組件的接口指針返回給客戶。使用這種方法,外部組件無需重新實現(xiàn)并轉(zhuǎn)發(fā)接口中的所有函數(shù)。

包容和聚合為實現(xiàn)組件的復(fù)用提供了一種極具健壯性的機(jī)制,在組建架構(gòu)下,客戶與組件的實現(xiàn)完全隔離。

二、COM編程

1.使用COM接口

COM下,對對象的直接訪問是不允許的,與對象的通信時通過定義接口而進(jìn)行的。對訪問對象進(jìn)行限制使COM成為一個與環(huán)境和語言無關(guān)的模型。在COM的約定中沒有限制用戶一定要用C++,而其他編程語言C、DELPHI、VB也都可以編寫COM應(yīng)用程序。

接口是包含了一組函數(shù)的數(shù)據(jù)結(jié)構(gòu),通過這組數(shù)據(jù)結(jié)構(gòu),客戶代碼可以調(diào)用組件對象的功能,客戶程序使用一個接口數(shù)據(jù)結(jié)構(gòu)的指針來調(diào)用接口成員函數(shù)。接口指針實際上又指向另一個指針,第二個指針指向一組函數(shù),稱為接口函數(shù)表。接口函數(shù)表中每一項為4個字節(jié)的函數(shù)指針,每個函數(shù)指針與對象的具體實現(xiàn)聯(lián)系在一起。

標(biāo)準(zhǔn)規(guī)定:COM中所有接口都是以“I”開頭的,I即代表interface。每個對象都有IUnknown接口。

2.標(biāo)識COM接口和對象

COM是面對對象的組件模型。COM提供給客戶的是以對象形式封裝起來的實體。COM組件的位置對客戶來說是透明的,因為客戶并不直接取訪問COM組件,客戶程序通過一個全局標(biāo)志符進(jìn)行對象的創(chuàng)建和初始化工作。如何在沒有中心機(jī)構(gòu)管理的情況下保證唯一性是解決標(biāo)志符的要點。

COM指定接口和對象用128位數(shù)字來標(biāo)識。這個128位數(shù)字叫做全局唯一標(biāo)識符GUID。GUID用以標(biāo)志兩種類型的項目:用于標(biāo)識接口的GUID叫做接口標(biāo)識符interface identifier IID;用于標(biāo)識某種類型的對象的GUID稱為類標(biāo)識符ClassID CLSID。隨機(jī)性有兩方面的特性保證:空間和時間。

可以使用GUIDGEN.EXT,獲得一個屬于自己的獨(dú)一無二的GUID,這是一個圖形化的UUIDGEN,可以把GUID拷貝到剪貼板,然后再把它們粘貼到用戶的源代碼中。



3.處理GUID

由于GUID的長度比較長,處理GUID比處理32位句柄要困難一些,下面是GUID的結(jié)構(gòu)

 

typedef struct _GUID

{

 unsigned long Data1;

 unsigned short Data2;

 unsigned short Data3;

 unsigned char Data4[8];

}GUID;

Windows 注冊表中,GUID的兩邊各加上一個花括號{}

Win32 SDK提供了以下幾個用于處理GUID的函數(shù):

CLSIDFromString:把字符串轉(zhuǎn)化為CLSID;CoCreateGuid:產(chǎn)生新的GUIDIIDFromString:把字符串轉(zhuǎn)化為IID;IsEqualCLSID:比較2CLSID;IsEqualGUID:比較兩個GUIDIsEqualIID:比較2IID;StringFromCLSID:CLSID轉(zhuǎn)化為字符串;StringFromCLSID:格式化GUID,并存入所提供的緩沖區(qū);StringFromIID:IID轉(zhuǎn)化為字符串。

4.使用IUnknown接口:

COM定義的每一個接口都必須從IUnknown繼承過來,原因在于IUnknown接口提供的2個特性:生命期控制和接口查詢??蛻舫绦蛑荒芡ㄟ^接口與COM對象進(jìn)行通信,雖然客戶程序可以不管對象內(nèi)部的實現(xiàn)細(xì)節(jié),但它要控制對象的存在與否。如果客戶還要繼續(xù)對對象進(jìn)行操作,就必須保證對象能一直存在于內(nèi)存中;如果客戶對對象的操作已經(jīng)完成,以后再也不需要對象了,則它必須及時地把對象釋放掉,以提高資源的利用率。IUnknown引入了“引用記數(shù)”方法可以有效地控制對象的生存周期。

如果一個COM對象實現(xiàn)了多個接口,在初始時刻,客戶程序不太可能得到該對象所有的接口指針,它只會擁有一個接口指針。如果客戶程序需要其他的指針,那么它如何通過接口指針呢?IUknown使用了“接口查詢”方法完成接口之間的跳轉(zhuǎn)。

IUnknown定義(IDL):

Interface IUnknown

{

HRESULT QueryInterface([in]REFIID iid,[out] void **ppv);

ULONG ADDRef(void);

ULONG Release(void);

}

IUnknown包含了3種成員函數(shù):QueryInterface,AddRefRelease函數(shù)。QueryInterface用于查詢COM對象的其他接口指針,函數(shù)AddRefRelease用于對引用計數(shù)進(jìn)行操作。

關(guān)于接口的幾點說明:

引用計數(shù)

COM對象的生存周期是由該對象所保存的內(nèi)部引用計數(shù)值嚴(yán)格控制的。該計數(shù)值代表客戶所創(chuàng)建的指向接口的指針的數(shù)目。

關(guān)于引用計數(shù)存在如下一些通用規(guī)則:在創(chuàng)建對象時,它的構(gòu)造函數(shù)把引用計數(shù)設(shè)置為0;在指向接口的指針被提供給對象的客戶時,創(chuàng)建該指針的函數(shù)將引用計數(shù)增加1AddRef函數(shù)實現(xiàn));當(dāng)不再使用指針時,內(nèi)部引用計數(shù)值通過調(diào)用Release函數(shù)減少,這就使得每一個對象都可以知道有多少外部客戶程序與自己連接在一起。當(dāng)內(nèi)部計數(shù)器的值為0時,沒有別的程序使用該對象,這時它通常會銷毀自己。

如果對象不是在堆上創(chuàng)建的,以上步驟可以進(jìn)行優(yōu)化。對靜態(tài)創(chuàng)建的對象而言,引用計數(shù)的操作一般都是空操作。但是客戶程序在使用該組件對象時仍然必須遵守引用計數(shù)的規(guī)則。

查詢另一個接口

通過調(diào)用QueryInterface,可以獲得指向?qū)ο笏С值娜我饨涌诘闹羔槨EcAddRefRelease一樣,QueryInterface也是IUnknown接口的一部分,所以可以通過任一接口指針調(diào)用QueryInterface。

QueryInterface有兩個參數(shù),該函數(shù)返回結(jié)果代碼的句柄,例如:

IFTeChart *pTeChart

HRESULT hr;

hr=pIUnknown->QueryInterface(IID_IFTeChart,&*pTeChart);

if(FAILED(hr)){

//返回錯誤代碼

}else{

//使用該接口

pTeChart->Release();

}

根據(jù)QueryInterface的實現(xiàn),對象的行為必須遵守下列規(guī)則:

在成功調(diào)用了QueryInterface之后,在該函數(shù)把新的接口指針返回給調(diào)用程序之前,接口的引用計數(shù)值必須增加1;對于對象的某個實例,某個給定的接口總是返回相同的指針值,如果用戶查詢某對象的接口并得到一定的指針值,那么之后同一對象的接口上對該對象進(jìn)行的任何QueryInterface調(diào)用都將返回相同的值;對象不允許擴(kuò)充新的接口,如果某次QueryInterface調(diào)用成功,以后它總是返回正確的值。反之,如果某次調(diào)用它出錯,則以后對它的調(diào)用將總是出錯;接口層次必須是有序的,如果QueryInterface調(diào)用返回指向新接口的指針,則可以通過調(diào)用QueryInterface返回到前一個接口。

處理返回值

與大多數(shù)的COM接口和函數(shù)一樣,QueryInterface返回的是HRESULT值。這是一個結(jié)構(gòu)化的32位值,與通常的返回代碼相比,這個值所包含的內(nèi)容要豐富的多。函數(shù)可能會有不同的方式來表示判斷一個函數(shù)是否成功,用戶必須使用SUCCEEDEDFAILED宏來檢測是否成功。

hr=pIUnknown->QueryInterface(IID_IFTeChart,&*pTeChart);

if(FAILED(hr)){

}

Hr=pIUnknown->GetData(&Data);

if(SUCCEEDED (hr)){}

5.創(chuàng)建COM對象

客戶程序通過調(diào)用CoCreateInstance來創(chuàng)建COM對象的一個實例,并向想要創(chuàng)建的對象傳送一個CLSID,比如:

IGraphBuilder *pGraph=NULL;

HRESULT hr=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,(void**)&pGraph);

if(FAILED(hr))

{

//ERROR

}

上述程序中利用CoCreateInstance創(chuàng)建了一個IGraphBuidler對象,如果創(chuàng)建成功將返回指向IGraphBuilder對象的指針。

一般情況下,創(chuàng)建COM對象需要經(jīng)歷幾個步驟。所有的COM對象都是由下面3種服務(wù)程序之一創(chuàng)建的:進(jìn)程內(nèi)服務(wù)程序,它在DLL中實現(xiàn),并運(yùn)行于客戶程序的地址空間中;本地服務(wù)程序,它們是EXE文件,運(yùn)行在客戶程序的同一臺計算機(jī)上,并且它們在自己的地址空間運(yùn)行;遠(yuǎn)程服務(wù)程序,它們也是EXE文件,運(yùn)行在網(wǎng)絡(luò)上的某臺計算機(jī)上。

使用類對象

每一個COM對象都與特定的對象相關(guān)聯(lián),這種特定的對象稱為類對象class object。類對象也稱為類工廠,它們負(fù)責(zé)創(chuàng)建COM對象的實例,每個類對象負(fù)責(zé)創(chuàng)建一個CLSID。如果用戶正在創(chuàng)建幾個CLSID服務(wù)程序,則必須為每個CLSID準(zhǔn)備一個類對象。

所有的COM對象都是通過該COM對象的CLSID關(guān)聯(lián)的類對象實現(xiàn)的,這就使得客戶程序可以用一種標(biāo)準(zhǔn)方法來創(chuàng)建COM對象,客戶程序可以只處理單個接口就行了。

IClassFactory接口需要類對象來實現(xiàn);IClassFactory接口在標(biāo)準(zhǔn)的IUnKnown接口的基礎(chǔ)是增加2個函數(shù);CreateInstance放回一個接口指針,指向CLSID所代表的COM對象的新實例;LockServer要求類對象駐留在內(nèi)存中,不要銷毀自己。

代碼如下:

STDMETODIMP CClassFactory::CreateInstance(LPUNKNOWN punk,PEFIID rlld,LPVOID *ppv)

{

*ppv=NULL;

if(punk!=NULL)

return ResultFromScode(CLASS_E_NOAGGREGATION);

CCTest *pTest=new CTest;

if(pTest==NULL)

return ResultFromScode(E_OUTOFMEMORY);

return pTest->QueryInterface(rlid,ppv);

}

在該段程序中,特定的類工廠CreateInstance函數(shù)創(chuàng)建CTest對象,在把接口指針放回調(diào)用程序之前,該程序?qū)ο髨?zhí)行第一次的QueryInterface。在每次使用windows 2000CoCreateInstance函數(shù)時,該函數(shù)都會為CLSID所指向的類對象在內(nèi)部創(chuàng)建一個實例。用戶可以執(zhí)行相同的步驟:首先調(diào)用CoGetClassObjectAPI函數(shù)來獲取指向類對象的指針,在用戶獲得指向?qū)ο笊舷嚓P(guān)接口的指針后,就可以通過調(diào)用CreateInstance函數(shù)得到一個或多個COM對象實例。

HRESULT MyCoCreateInstance(REFCLSID retsid,LPUNKNOWN pUnkOuter,DWORD dwClsContent,REFIID riid,LPVOID ppv)

{

ICLassFactory *pcl=NULL;

HRESULT hr=CoGetClassObject(rcsid,dwClsContent,NULL,IID_IClassFactory,(void**)&pcf);

if(FALIED(hr))

return hr;

hr=pcf->CreateInstance(pUnkOuter,riid,ppvObj);

pcf->Release();

return hr;

}

如果用戶要創(chuàng)建COM對象的多個實例,那么與每個實例調(diào)用一次CoCreateInstance比較,使用類對象來創(chuàng)建多個實例效率要高得多。

在注冊表中查找類對象

包含COM組件的類對象的模塊可以在系統(tǒng)注冊表中找到,如果該CLSID是進(jìn)程內(nèi)服務(wù)程序,則該服務(wù)程序的DLL的路徑存放在InProcServer32關(guān)鍵字中,例如

[HKEY_CLASSES_ROOT\CLSID\{32GUID}\InprocServer32]

缺省值為”D:\\Program Files\Common Files\\Microsoft shared\\DAO\\DAO350.DLL”.

客戶程序通過注冊表加載該動態(tài)鏈接庫,如果用戶把動態(tài)鏈接庫放到系統(tǒng)的目錄下將會加快加載該對象的速度。

.進(jìn)程內(nèi)服務(wù)程序的需求

除了類對象所需的函數(shù)以外,進(jìn)程內(nèi)服務(wù)程序必須實現(xiàn)3個函數(shù):

DLLMain:它是模塊的入口點,該函數(shù)所完成的唯一工作就是保存實例句柄以備程序使用;DLLGetClassObject,必須從模塊中導(dǎo)出該函數(shù),在創(chuàng)建新的COM類對象時,windows系統(tǒng)將調(diào)用該函數(shù)。

DLLCanUnloadNow,windows系統(tǒng)調(diào)用這個函數(shù)來測試DLL是否可以被加載。在創(chuàng)建過程中,模塊所創(chuàng)建的每一個對象都會使用全局引用計數(shù)器值增加1,而銷毀時則減1。

 

三、創(chuàng)建COM程序

目前編寫的COM程序可以通過MFC或者ATL來進(jìn)行,MFC是創(chuàng)建COM程序的一種簡單、一致的方法,但是ATL提供了一種框架來實現(xiàn)創(chuàng)建COM客戶機(jī)和服務(wù)器所必須的樣板文件代碼。使用這兩種方法創(chuàng)建COM程序各自有各各自的優(yōu)缺點。

1.使用MFC創(chuàng)建COM程序

使用MFC使得開發(fā)windows應(yīng)用程序比使用SDKAPI容易得多。MicrosoftMFC的基礎(chǔ)上,增加了對即存框架的COM支持。由于MFC的開發(fā)者在增加越來越多的函數(shù)時必須保持框架的完整,同時,visual C++編譯器那時還不支持模板,因此,它們不得不借助非模板的其他手段來將COM功能摻入它們的類中。Microsoft 通過加入一些虛函數(shù)到CCmdTarget類中和一些宏中,解決了此問題,使得MFC中實現(xiàn)了COM接口有了可能。

MFC內(nèi)部的COM支持從CCmdTarget開始,CCmdTarget類實現(xiàn)了IUnknown接口,還包括了一個用于引用計數(shù)的成員變量(m_dwRef)和用于實現(xiàn)IUnknown6個函數(shù):InternalAddRef、InternalReleaseInternalQueryInterface、ExternalAddRefExternalReleaseExternalQueryInterface。QueryInterface的兩個版本,AddRefRelease支持COM聚合。InternalAddRefInternalReleaseInternalQueryInterface完成引用計數(shù)和QueryInterface操作,而ExternalAddRefExternalReleaseExternalQueryInterface代理控制聚合的對象。

MFC使用嵌套的類負(fù)荷策略實現(xiàn)COM接口。在MFC中,想實現(xiàn)COM接口的淚是從CCmdTarget類中派生的。每個由CCmdTarget派生出的類實現(xiàn)的接口得到它自己的嵌套類。MFC使用宏BEGIN_INTERFACE_PARTEND_INTERFACE_PART來產(chǎn)生嵌套類。

MFC還實現(xiàn)了表驅(qū)動的QueryInterface。MFC接口映射的工作機(jī)理同它的消息映射基本相同:MFC的消息映射把一個windows消息和一個C++類中的函數(shù)相聯(lián)系;MFC的接口映射把一個接口的GUID和一個表示此接口的特定的vptr的地址相聯(lián)系。每個基于CCmdTarget類實現(xiàn)COM接口通過更多的宏:DECLARE_INTERFACE_MAP、BEGIN_INTERFACE_MAP、INTERFACE_PARTEND_INTERFACE_MAP來增加一個接口映射。

除了實現(xiàn)了IUnKnown接口,MFC還包括IClassFactory的一個標(biāo)準(zhǔn)實現(xiàn)。MFC通過若干宏提供此支持。MFC2個宏來提供類對象:DECLARE_OLECREATE_EXIMPLEMENT_OLECREATE_EX。在一個基于CCmdTarget的類中使用這些宏增加一個COleObjectFactory類型的靜態(tài)成員到該類中。如果你看一下AFXDISP.HCOleObjectFactory的定義,將會看到用在COleObjectFactory中的MFC的嵌套類宏為實現(xiàn)IClassFactory2定義了一個嵌套類。IClassFactory::CreateInstanceMFC版本使用MFC的動態(tài)創(chuàng)建機(jī)制(DECLARE_DYNCREATEIMPLEMENT_DYNCREATE宏打開此功能)來實例化COM類。

最后MFC中實現(xiàn)一個分發(fā)接口,可以通過ClassWizard來實現(xiàn)該功能。ClassWizard中有一個按鈕用于添加屬性,另一個用于添加方法。在MFC中,IDispatch支持來自CCmdTarget類。IDispatchMFC實際實現(xiàn)在一個叫做COleDispatchImpl的類中,COleDispatchImpl派生自IDispatch,實現(xiàn)了所有4IDispatch函數(shù):GetTypeInfoCountGetTypeInfo、GetIDsNamesInvoke。由CCmdTarget派生的類通過調(diào)用EnableAutomationIDispatch vptr加入到它們的接口映射中,當(dāng)客戶在基于MFCCOM組建上調(diào)用IDispatchQueryInterface時,CCmdTarget交出鏈接在COleDispatchImpl上的vptr。

每次使用ClassWizard將一個自動屬性或者方法加入到一個類中時,同時也在該類的分發(fā)映射表中加入了一項,一個分發(fā)映射表是一個將DISPIDs(用來調(diào)用分發(fā)成員的符號)和它們攻人讀的名字以及和實際完成這個工作的某些C++代碼聯(lián)系起來的簡單表格。COleDispatchImpl的調(diào)用以及GetIDsOfNames函數(shù)通過在類的分發(fā)映射表中查找分發(fā)成員并分發(fā)DISPID相對應(yīng)的函數(shù)來工作。MFC能為某些基于COM的高級技術(shù)如OLE文檔、OLE拖放和自動操作提供非常好的支持。

2.使用ATL編寫COM程序

ATLActiveX template library的縮寫,是一套C++模板庫。使用ATL能夠快速地開發(fā)出高效、簡潔的代碼,同時對COM組件的開發(fā)提供最大限度的代碼自動生成以及可視化支持。為了方便的使用,microsoftATL集成到visual C++開發(fā)環(huán)境中。

ATL的目標(biāo)是使開發(fā)者不必重寫IUnknown,IDispatch,IClassFactory和其他的分支將常規(guī)的DLLEXE變成基于COMDLLEXE。從這個角度講,ATL是一個比MFC精簡得多的框架,它設(shè)計和生成時就考慮了COM的支持,它使用基于模板的方法,通過繼承ATL提供的模板,開發(fā)者可以加入各種COM功能片斷。

ATL的原始COM支持是從對IUnknown的支持開始的。ATLIUnknown的實現(xiàn)分成兩個部分:CComObjectRootEx是一個機(jī)遇模板的類,將線性模型作為其唯一參數(shù)。ATL2個處理引用計數(shù)的淚,用于處理不同的線性模型:CComSingleThreadModelCComMultiThreadModel。這些類每個都有一個遞增和一個遞減的函數(shù)。其區(qū)別在于CComSingleThreadModel用標(biāo)準(zhǔn)C++操作符(++--)實現(xiàn)遞增和遞減;而CComMultiThreadModel使用線程安全的InterlockedIncrementInterlockedDecrement函數(shù)來實現(xiàn)這兩個功能。根據(jù)用來實例化CComObjectRootEx的模板參數(shù),它能正確的運(yùn)行給定的組件類型。像MFCATL使用基于表的查找機(jī)制實現(xiàn)QueryInterface。CComObjectRootBase通過一個接口映射處理類的QueryInterface函數(shù)。BEGIN_COM_MAPEND_COM_MAP宏定義了一個借口映射的開始和結(jié)束。與MFC不同的是,ATL提供了17種途徑來組成一個接口映射,例如使用從ATL的基于模板的接口實現(xiàn)類如IOleObjectImpl來的vptrs。這包含了那些從tear-off的類或者由聚合提供的類來的vptrs。

ATL里,C++類通過繼承CComObjectRootEx,指定它們想要的組件模型(記住MFCIUnknown支持是內(nèi)建在CCmdTarget中的)變成COM類。

ATL的類對象(以及IClassFactory)支持也來自模板,而MFC的類對象支持通過COleObjectFactory和一些宏而有效。ATL的類對象支持來自CComCoClass/CComClassFactory類家族和CComCreator類家族。CComCoClass包含了類的GUID,定義了COM類的錯誤處理設(shè)施。CComCreator類提供了CreateInstance的實現(xiàn),供CComClassFactory使用。對于MFC,可以通過若干宏,使所有這種支持有效。ATL包括DECLARE_CLASS_FACTORY,DECLARE_CLASS_FACTORY2,DECLARE_CLASS_FACTORY_AUTO_THREAD以及DECLARE_CLASS_FACTORY_SINGLETON等宏用來使各種具體的類工廠支持有效。

最后ATLIDispatch的支持還來自模板類其名字是IDispatchImpl。與MFCIDispatch來說,ATLIDispatch的支持更加容易和標(biāo)準(zhǔn)。MFC試用了一種hand-rolledIDispatch來實現(xiàn),而ATL使用更加標(biāo)準(zhǔn)的方法來加載一個接口的類型信息并代表標(biāo)準(zhǔn)的類型庫編譯器。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
IE內(nèi)核瀏覽器開發(fā)筆記
VC知識庫文章 - COM 組件設(shè)計與應(yīng)用(七)——編譯、注冊、調(diào)用
COM聚合
COM入門第一部分
MFC對COM接口編寫的支持分析
COM編程技術(shù)基礎(chǔ)之二
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服