2013-10-10 73 views
11

TL; DRregsvr32生成的所有註冊表項必須存在於SxS reg-free-COM清單中,反之亦然?清單中的註冊免費COM需要哪些標籤?


我想要免費註冊COM去第三方組件。

Readingupon的主題,我發現有提到的幾個元素,可以放入清單:

From the docs,我們可以添加以下標籤清單來描述一個COM組件:

  • assemblyIdentity - 這真的只是描述了「抽象assembly」據我可以告訴
  • comClass - 介紹COM類(IID在terface)。它會出現,這總是需要的。
  • typelib - 什麼時候?
  • comInterfaceExternalProxyStub - 什麼時候?
  • ​​- 什麼時候?

From the other docs for HKEY_LOCAL_MACHINE\SOFTWARE\Classes我們可以看到有幾個類別的COM註冊表項:

使用regsvr42提取東西,我想regfree的dll產生僅包含comClass條目,沒有類型庫或ProxyStub條目清單。 (並且我交叉檢查了寫入的密鑰,所述的DLL,pdm.dll,MS的進程調試管理器僅寫入這些密鑰,即在註冊表中沒有明顯的類型庫或代理存根信息。)

如果註冊表只包含與comClass有關的信息,那麼這是否意味着此信息在SxS清單中是足夠的,或者可能需要清單中的其他信息?


順便說一句,我注意到註冊表中包含VersionIndependentProgId,並且具有附加在末尾的一個版本號的ProgId。該清單僅具有ProgId條目,該文檔狀態:

的ProgID:與 COM組件相關聯版依賴性編程標識符。 ProgID的格式是 <vendor>.<component>.<version>

但該文檔還規定

comClass元素可以有<progid>...</progid>元素 孩子,這列出的版本有關的ProgID。

and they say progid屬性應該是版本無關的。

那麼,這裏放什麼?當客戶端沒有請求特定版本時,它甚至是重要的嗎?

+0

PDM不會有類型庫,它沒有IDispatch接口,您必須使用CoCreateInstance()。而且它像一個免費線程進程組件一樣嘎嘎,所以不需要代理/存根。這裏究竟出了什麼問題? –

+0

@Hans,謝謝。沒有任何事情會出現這樣的錯誤,但我不確定是否有任何潛在的缺陷。 (COM總是讓我覺得我失去了一些東西。)如果你能幫助我解開上面的兩個或三個實際有用的問題,我會很感激。否則,我很高興,你似乎認爲一切都是我命令:-) –

回答

11

assemblyIdentity元素始終是必需的,是清單管道的一部分。您必須始終提供comClass元素,它將替代HKLM\Software\Classes\CLSID註冊表項並用於使客戶端的CoCreateInstance()調用起作用。該文件元素命名COM服務器可執行文件。

其餘的鍵是可選的,他們需要使編組工作。當客戶端調用需要在不同的線程上進行時,會發生封送。那麼總是發生在服務器和客戶端處於不同的進程中時,對於進程外服務器或當服務器在另一臺計算機上運行時。當comClass元素中指定的ThreadingModel需要它時,它可能會發生。換句話說,當COM對象在一個線程上創建,但在另一個線程上調用時,服務器不是線程安全的。

RPC實現封送處理,但它有一個工作要做,它需要幫助。它需要知道函數的參數是什麼,以及返回類型。這樣它就可以正確地將它們的值序列化成一個數據包,這個數據包可以通過網絡傳輸,或者傳遞給另一個線程中的代碼。這是代理的工作。存根在接收端運行並反序列化參數以構建堆棧幀並進行調用。函數返回值以及任何通過引用傳遞的參數值然後返回給調用者。否則進行調用的代碼根本沒有意識到它沒有直接調用該函數。

有四種基本情況:

  • 的COM服務器不支持被稱爲這樣的一切,必須始終從創建它在相同的線程中使用。停在那裏,不需要向清單添加任何東西。

  • COM服務器實現了IMarshal interface。當它無法找到另一種編組呼叫的方式時,由COM自動查詢。這是非常罕見的,除了COM服務器聚合自由線程編組的情況。換句話說,它本身完全是線程安全的,不需要任何幫助,並且始終在進程中運行。 PDM很可能會這樣工作。停在那裏,不需要向清單添加任何東西。

  • COM服務器作者通過用IDL語言編寫服務器的接口描述來啓動他的項目。然後由MIDL編譯。它可用的一個選項是從IDL聲明中自動生成代碼,這些代碼可用於構建實現代理和存根的獨立DLL。 IDL足夠豐富,可以描述函數參數類型和用法的詳細信息,以允許通過此自動生成的代碼完成封送處理。有時IDL屬性不夠用,COM作者會寫一個自定義編組器。 COM在運行時加載該DLL以自動創建代理和存根對象。

  • 針對COM自動化子集(IDispatch接口),Windows有一個內置編組器,它知道如何編組符合子集要求的調用。很常見。它使用類型庫來發現函數聲明。

後兩個項目符號需要使用HKLM\Software\Classes\Interface,它具有用於每個接口的IID的條目。這就是COM如何發現如何創建代理和界面的存根。如果找不到密鑰,則會回到IMarshal。您必須使用comInterfaceExternalProxyStub元素來替換註冊表項。使用comInterfaceProxyStub是一種特殊情況,即當COM服務器可執行文件包含代理和存根代碼而不是單獨的文件時。例如,在ATL項目中的一個選項,打開「允許合併代理/存根」嚮導選擇。

最後一個項目符號還需要使用typelib元素,因此內置編組器可以找到它需要的類型庫。

當COM客戶端通過IDispatch使用後期綁定時,progId是必需的,客戶端的運行時支持庫中的CreateObject()輔助函數是樣板。例如,用於任何腳本宿主。

有一些關於如何創建COM服務器的內幕知識當然有幫助,請務必聯繫供應商或作者尋求建議。可以通過觀察註冊服務器註冊時註冊哪些註冊表項來進行反向設計,SysInternals的ProcMon工具是查看該註冊表的最佳方式。基本的東西去尋找:

  • 如果你看到它寫HKLM\Software\Classes\Interface鍵,那麼你可以認爲你必須提供comInterface |外部| ProxyStub元素

  • 如果你看到它寫{00020420-0000 -0000-C000-000000000046}對於ProxyStubClsid32鍵,則可以假定它使用的是標準編組器,並且必須使用comInterfaceExternalProxyStub元素以及typelib元素。然後您應該看到它會寫入IID的TypeLib註冊表項以及HKLM \ Software \ Classes \ Typelib註冊表項中的條目。後者給出了類型庫的路徑。幾乎總是和COM服務器一樣,將類型庫作爲資源嵌入是非常普遍的。如果它是單獨的(一個.tlb文件),那麼你必須部署它。

  • 如果ProxyStubClsid32鍵值是另一個GUID,那麼您可以假設它使用自己的代理/存根DLL。然後您應該看到它爲代理編寫CLSID鍵,它的InProcServer32鍵爲您提供了DLL的路徑。如果該文件名與服務器的文件名相匹配,那麼您可以假定代理/存根代碼已合併,您必須改用comInterfaceProxyStub元素。如果不是那麼comInterfaceExternalProxyStub是必需的,您必須部署DLL

  • 如果您看到它在HKLM\Software\Classes中編寫ProgID,然後使用progid元素,完全如跟蹤中所示。

+0

令人驚歎。謝謝。 :-) pdm。dll是一個有趣的案例,因爲有第二個DLL,msdbg2.dll * *似乎*包括用於調試接口的ProxyStubs。 (例如,msdbg2.dll是Visual Studio需要的,以便能夠附加到進程)但是,我們使用pdm.dll(調試vbscript)的方式似乎並不需要msdbg2.dll中的ProxStub,因爲我們的代碼高興地工作沒有msdbg2.dll。 (雖然,如果註冊,msdbg2.dll將通過pdm.dll加載 - 不知道它究竟做了什麼。)嗯。這一切都是如此混亂。 –