微軟的COM中GUID和UUID、CLSID、IID
當(dāng)初微軟設(shè)計(jì)com規(guī)范的時候,有兩種選擇來保證用戶的設(shè)計(jì)的com組件可以全球唯一:
第一種是采用和Internet地址一樣的管理方式,成立一個管理機(jī)構(gòu),用戶如果想開發(fā)一個COM組件的時候需要向該機(jī)構(gòu)提出申請,并交一定的費(fèi)用。
第二種是發(fā)明一種算法,每次都能產(chǎn)生一個全球唯一的COM組件標(biāo)識符。
第一種方法,用戶使用起來太不方便,微軟采用第二種方法,并發(fā)明了一種算法,這種算法用GUID(Globally Unique Identifiers)來標(biāo)識COM組件,GUID是一個128位長的數(shù)字,一般用16進(jìn)制表示。算法的核心思想是結(jié)合機(jī)器的網(wǎng)卡、當(dāng)?shù)貢r間、一個隨即數(shù)來生成GUID。從理論上講,如果一臺機(jī)器每秒產(chǎn)生10000000個GUID,則可以保證(概率意義上)3240年不重復(fù)。
GUID的例子: 54BF6567--1007--11D1--B0AA--444553540000
HKEY_CLASSES_ROOT\CLSID\{002B9E07-2E10-438F-AF1E-40E6A96F1EE4}
在微軟的COM中GUID和UUID、CLSID、IID是一回事,只不過各自代表的意義不同:
UUID : 代表COM
CLSID : 代表COM組件中的類
IID :代表COM組件中的接口
在程序中,實(shí)際對象數(shù)據(jù)對應(yīng)的處理程序路徑string往往不盡相同,比如有的放C盤有的D盤,微軟想出了一個解決方案,那就是不使用直接的路徑表示方法,而使用一個叫 CLSID的方式間接描述這些對象數(shù)據(jù)的處理程序路徑。
CLSID 其實(shí)就是一個號碼,CLSID 的結(jié)構(gòu)定義如下:
typedef struct _GUID {
DWORD Data1; // 隨機(jī)數(shù)
WORD Data2; // 和時間相關(guān)
WORD Data3; // 和時間相關(guān)
BYTE Data4[8]; // 和網(wǎng)卡MAC相關(guān)
} GUID;
typedef GUID CLSID; // 組件ID
typedef GUID IID; // 接口ID
#define REFCLSID const CLSID &
// 常見的聲明和賦值方法
CLSID CLSID_Excel = {0x00024500,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
struct __declspec(uuid("00024500-0000-0000-C000-000000000046")) CLSID_Excel;
class DECLSPEC_UUID("00024500-0000-0000-C000-000000000046") CLSID_Excel;
// 注冊表中的表示方法
{00024500-0000-0000-C000-000000000046}
如果使用開發(fā)環(huán)境編寫組件程序,則IDE會自動幫你產(chǎn)生 CLSID;
可以用函數(shù) CoCreateGuid() 產(chǎn)生 CLSID;
使用"vc目錄\Common\Tools\GuidGen.exe"工具產(chǎn)生GUID
每一個COM組件都需要指定一個 CLSID,并且不能重名。它之所以使用16個字節(jié),就是要從概率上保證重復(fù)是“不可能”的。但是,微軟為了使用方便,也支持另一個字符串名稱方式,叫 ProgID。。由于 CLSID 和 ProgID 其實(shí)是一個概念的兩個不同的表示形式,所以我們在程序中可以隨便使用任何一種。
下面是 CLSID 和 ProgID 之間的轉(zhuǎn)換方法和相關(guān)的函數(shù):
函數(shù) |
功能說明 |
CLSIDFromProgID()、CLSIDFromProgIDEx() |
由 ProgID 得到 CLSID。沒什么好說的,你自己都可以寫,查注冊表貝 |
ProgIDFromCLSID() |
由 CLSID 得到 ProgID,調(diào)用者使用完成后要釋放 ProgID 的內(nèi)存(注5) |
CoCreateGuid() |
隨機(jī)生成一個 GUID |
IsEqualGUID()、IsEqualCLSID()、IsEqualIID() |
比較2個ID是否相等 |
StringFromCLSID()、StringFromGUID2()、StringFromIID() |
由 CLSID,IID 得到注冊表中CLSID樣式的字符串,注意釋放內(nèi)存 |
客戶端軟件和組件之間的調(diào)用如下:
容器 協(xié)商部分 |
組件 應(yīng)答部分 |
|
1 |
根據(jù)CLSID啟動組件 。 CoCreateInstance() |
生成對象,執(zhí)行構(gòu)造函數(shù),執(zhí)行初始化動作。 |
2 |
你有IUnknown接口嗎? |
有,給你! |
3 |
恩,太好了,那么你有IPersistStorage接口嗎?(注9) IUnknown::QueryInterface(IID_IPersistStorage...) |
沒有! |
4 |
真差勁,連這個都沒有。那你有IPersistStreamInit接口嗎?(注10) IUnknown::QueryInterface(IID_IPersistStreamInit...) |
哈,這個有,給! |
5 |
好,好,這還差不多。你現(xiàn)在給我初始化吧。 IPersistStreamInit::InitNew() |
OK,初始化完成了。 |
6 |
完成了?好!現(xiàn)在你讀數(shù)據(jù)去吧。 IPersistStreamInit::Load() |
讀完啦。我根據(jù)數(shù)據(jù),已經(jīng)在窗口中顯示出來了。 |
7 |
好,現(xiàn)在咱們各自處理用戶的鼠標(biāo)、鍵盤消息吧...... |
...... |
8 |
哎呀!用戶要保存退出程序了。你的數(shù)據(jù)被用戶修改了嗎? IPersistStreamInit::IsDirty() |
改了,用戶已經(jīng)修改啦。 |
9 |
那好,那么用戶修改后,你的數(shù)據(jù)需要多大的存儲空間呀? IPersistStreamInit::GetSizeMax() |
恩,我算算呀......好了,總共需要500KB。 |
10 |
暈,你這么個小玩意居然占用這么大空間?!......好了,你可以存了。 IPersistStreamInit::Save() |
謝謝,我已經(jīng)存好了。 |
11 |
恩。拜拜了您那。(注11) IPersistStreamInit::Release();IUnknown::Release() |
執(zhí)行析構(gòu)函數(shù),刪除對象。 |
12 |
我自己也該退出了...... PostQuitMessage() |
本文僅代表作者觀點(diǎn),版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請?jiān)谖闹凶⒚鱽碓醇白髡呙帧?/p>
免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請及時與我們聯(lián)系進(jìn)行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com





