糾錯《COM技術內幕》之ProgID
最近在看《COM技術內幕》,看到第六章時發現該章節在解釋ProgID時有點錯誤,特此記錄一下,也給正在學習COM的小夥伴們一個提示。
而且我發現該問題存在於一些很多大型軟件的COM組件中。(開發者估計都是看了該書吧)
在該書的6.3.5章節講解了ProgID的在註冊表中的格式,示例如下
註冊表文件格式為
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\AA.BB\CLSID] @="{00000000-F2ED-4CD4-9204-A1C28871DD2E}" [HKEY_CLASSES_ROOT\AA.BB\CurVer] @="AA.BB.1" [HKEY_CLASSES_ROOT\AA.BB.1\CLSID] @="{00000000-F2ED-4CD4-9204-A1C28871DD2E}"
(上面我故意將CLSID的第一節寫為零了,僅僅只是為了讀者容易區分後面的其他CLSID)
書中也講到了,這麽做的目的是為了客戶在使用COM組件時可以通過“AA.BB”這個與版本無關的ProgID來映射到最新版本的組件
在上例中也就是“AA.BB.1”這個版本。引用書中的一段原話“與版本號無關的ProgID關鍵字Helicopter.TailRotor包含兩個關鍵字CLSID及CurVer。”
也就是上面註冊表文件中所描述的格式。為了驗證書中所說的,我們把"AA.BB.1”的CLSID改一下
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\AA.BB\CLSID] @="{00000000-F2ED-4CD4-9204-A1C28871DD2E}" [HKEY_CLASSES_ROOT\AA.BB\CurVer] @="AA.BB.1" [HKEY_CLASSES_ROOT\AA.BB.1\CLSID] @="{11111111-F2ED-4CD4-9204-A1C28871DD2E}"
那麽是不是真的可以通過“AA.BB”映射到“AA.BB.1”呢?編寫如下測試代碼
#include "stdafx.h" #include<iostream> #include <Windows.h> int _tmain(int argc, _TCHAR* argv[]) { CLSID clsid; CLSIDFromProgID(L"AA.BB", &clsid); LPOLESTR str; StringFromCLSID(clsid, &str); std::wcout << str << std::endl; CoTaskMemFree(str); system("pause"); return 0; }
運行結果如圖
很可惜,取到的CLSID還是“AA.BB”的,並非“AA.BB.1”的CLSID。
看到這裏你也許會發現,在我們的系統中,有著這個問題的COM組件有很多,比如迅雷的
騰訊的
它們都無法從“與版本號無關的ProgID”映射到“具體版本的ProgID”。
一般來說升級COM組件的最佳方式還是升級內部接口的方式,如IX2、IX3等,並不會選擇去添加一個新的COM組件的方式。
所以這個問題也不算是個問題。
回到正題,那麽如何做才是正確的呢?其實很簡單,只要把“AA.BB"的CLSID鍵刪除即可
Windows Registry Editor Version 5.00 [-HKEY_CLASSES_ROOT\AA.BB\CLSID] [HKEY_CLASSES_ROOT\AA.BB\CurVer] @="AA.BB.1" [HKEY_CLASSES_ROOT\AA.BB.1\CLSID] @="{11111111-F2ED-4CD4-9204-A1C28871DD2E}"
這樣,CLSIDFromProgID才會真正的工作正常,再次運行測試程序得到”AA.BB.1“的CLSID
CLSIDFromProgID會查找用戶指定的ProgID,如果其下有子鍵”CLSID“的話,則認為該ProgID是一個具體版本的。
否則該ProgID只是起到映射的作用,它實際會跳到”CurVer“鍵所指向的ProgID。
《COM技術內幕》中所講到的與版本無關的ProgID都添加了CLSID鍵,這樣會導致該ProgID不是一個能映射的ProgID。
轉載地址:http://blog.csdn.net/aqtata/article/details/36915823
糾錯《COM技術內幕》之ProgID