1. HRESULT
HRESULT是一個可以分成三個域的32位值,
注意:S_FALSE被定義爲1而S_OK被定義爲0,這一點同C/C++變成原則正好相反。
HRESULT值中16到30這15個比特位包含的時設備代碼,設備代碼標識的時可以返回HRESULT中返回代碼的操作系統部分。當前定義的:
HRESULT值的使用
- 成功的代碼有多個,失敗的代碼也有多個
一個函數在各種情況下返回的狀態太代碼通常包含多個成功代碼及多個失敗代碼。這就是爲什麼要使用SUCCEEDED及FAILED宏的原因。一般不直接將HRESULT值同某個成功代碼(如S_OK)| 失敗代碼(如S_FAILE)進行比較以決定某個函數是否成功,應使用SECCEEDED及FAILED宏判斷
- 失敗代碼可能會發生變化
其他人可能會定義新的HRESULT錯誤代碼,客戶程序也可能會遇到相應的錯誤。由於客戶使用的組件可能會發生變化,因此組件返回的錯誤代碼也可能會發生變化。
2. GUID
爲什麼要使用GUID來標識接口而不是用一個長整數呢?問題的實質並不是在於我們可以標識多少個接口,而在於怎樣保證每一個接口標識符都是唯一的。
GUID的聲明和定義
可以使用ObjBase.h中的DEFINE_GUID宏來定義
#ifndefINITGUID
#defineDEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID FAR name
#else
#defineDEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#endif // INITGUID
在ObjBase.h中所定義的DEFINE_GUID將產生於下列類似的輸出:
EXTERN_C const GUID FAR IID_IX
但是,如果在OBjBase.h之後包含INITGUID.H,那麼DEFINE_GUID所產生的代碼就如下:
//{32bb8320-b41b-11cf-a6bb-0080c7b2d682}
Extern “C” const IID IID_IX =
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6,0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
GUID的比較
在ObjBase.H中定義了一個==操作符,也可以使用IsEqualGUID、IsEqualIID以及IsEqualCLSID。
3. windows註冊表
註冊表的組織
註冊表是一個有許多元素構成的層次結構,每一個元素均被稱作是一個關鍵字。每一個關鍵字可以包含一系列子關鍵字。一系列命名的值及/或一個未命名的值。子關鍵字也可以包含他的子關鍵字及值,但值卻不能有子關鍵字或值。每一個值都有其相應的類型。註冊表結構:
CLSID關鍵字結構
COM只使用了註冊表的一個分支:HEKY_CLASSES_ROOT。在此關鍵字下,可以找到有CLSID關鍵字。在clsid關鍵字之下列有系統所有安裝的組件的CLSID,註冊表CLSID是一個具有如下格式的串:{32bb8320-b41b-11cf-a6bb-0080c7b2d682},對於關鍵字現在關心的時他的一個子關鍵字InprocServer32.此關鍵字的缺省值是組件所在的DLL文件名稱
關於註冊表的其他細節
在HKEY_CLASSES_ROOT地開頭,列出的將是各種應用程序所註冊的文件擴展名。在擴展名之後,可以看到許多其他的名字。此類名字的大多數被稱爲ProgID,表示是程序員定義的標識符。
- AppID-----此關鍵字下地子關鍵字的作用是將某個APPID(應用程序ID)映射成某個遠程服務器名稱。分佈式COM將用到此關鍵字
- 組件類別----註冊表的這一分支可以將CATID(組件類別ID)映射成某個特定的組件類別。
- Interface----用於將IID映射成與某個接口相關的信息。這些信息主要公寓在跨進程便捷使用接口的情況
- License-----License保持的時授權使用COM組件的一些許可信息
- TypeLib-----類型庫關鍵字所保持的時關於接口成員函數所用參數的信息。
ProgID
ProgID指的時程序員給某個CLSID指定的一個程序員易記的名稱。
- ProgID命名約定
ProgID具有如下的格式:
<Program>.<Component>.<Version>
比如:Visio.Drawing.4
- ProgID註冊表格式
- 從ProgID到CLSID的轉換
CLSID clsid;
CLSIDFromProgID(L"Primer.xxx.1",&clsid);
自注冊
DLL要輸出一下兩個函數:
#defineSTDAPI EXTERN_C HRESULTSTDAPICALLTYPE
STDAPI DllRegisterServer();
STDAPI DllUnregisterServer();
用戶可以使用程序RegSve32.exe來註冊某個組件。它實際上通過調用上述那些函數來完成組件的註冊的。
- DllRegisterServer的實現
通過直接調用註冊表函數來完成的。API中有許多想註冊表中加入新的關鍵字及刪除某個關鍵字的函數。
RegOpenKeyEx
RegCreateKeyEx
RegSetValueEx
RegEnumKeyEx
RegDeleteKey
RegCloseKey
組件類別
組件類實際上就是一個接口集合,該集合將被分配給一個GUID,此GUID此時叫做CATID。對於某個組件而言,若它實現了某個組件類別的所有接口,那麼他就可以將其註冊成該組件類別的一個成員。客戶就可以通過從註冊表中選擇只屬於某個特定組件類別的組件而準備找到他所需要的組件
4. Com庫
- COM庫的初始化
在使用COM庫的其他函數之前,進程必須先調用CoInitialize才初始化COM庫函數。當進程不在需要使用COM函數時,必須調用CoUnInitialize
- 內存管理
CoTaskMemAlloc()
CoTaskMemFree();
- 將字符串轉換成GUID
在註冊表中包含的CLSID的字符串表示,因此需要一些函數來完成從CLSID到字符串的轉換