簡體   English   中英

為什么要注冊COM接口?

[英]Why registering COM interfaces?

我已經使用COM多年了,但我不斷學習新的(和奇怪的)東西。

最近我意識到COM接口不必在注冊表中注冊實現它們的組件。

在分析了工作站的注冊表后,我得出了這個結論,其中COM DLL (在.Net / C#中實現 )使用RegAsm創建的.reg文件注冊,因為用戶不是管理員。 RegAsm只為COM類而不是接口生成注冊表項。

如果這是真的,我的猜測是接口對於早期綁定很重要,並且只需要存在於TLB文件中 相反,注冊實現(類)是必不可少的,因為它們由需要引用的文件系統上的物理代碼支持。

1)我瘋了,丟失了什么,或者接口可以省略?

2)如果可以省略它們會帶來什么后果?

如果沒有注冊界面,有很多事情是你做不到的。 COM的許多功能 - 編組,代理,異步調用 - 都有標准的實現,可以防止你自己滾動這些東西。 例如, CoMarshalInterface是獲取任何COM對象接口並將該接口封送到流中的標准方法,以便可以在另一個線程,進程或機器中對其進行解組。 接口信息在這方面至關重要 - 沒有接口元數據,這樣的事情的標准COM實現將不起作用,因為基礎設施根本不了解您的接口以通用方式執行它需要做的事情適用於所有COM對象。

此外,雖然大多數自動化客戶端(如VBA,C#和C ++)可以直接引用類型庫文件以進行早期綁定,但仍存在一些限制。 例如,假設您正在使用一個類型庫,該類型庫包含一些實現不同類型庫接口的類,或者第一個類型庫中的接口可能接受參數或返回由interfaces / enums / etc定義的值。類型庫。 為了使自動化客戶端能夠使用包含交叉引用的這些接口,必須以某種方式發現交叉引用的類型庫。 注冊是實現這一目標的方式。

值得注意的是:根據我的經驗,當COM對象在機器范圍內注冊(在HKLM中注冊)時,幾乎所有工作都在每個用戶注冊時(在HKCU中)完全相同。 這通常使COM注冊在無法執行機器范圍注冊的情況下更加可口(例如,用戶不是管理員)。 然而,有一些重要的問題,最值得注意的是http://blogs.msdn.com/b/cjacks/archive/2008/06/06/per-user-com-registrations-and-elevated-processes-with-uac-上Windows的Vista的sp1.aspx

很模糊,不確定我能讀出大膽之間的所有單詞。 通常不止一種方法可以給這只貓上皮。 COM需要使用類工廠來創建對象,通用工作馬是CoCreateInstance()。 CreateObject()在腳本環境中很流行。 你給它一個數字,然后向后吐出一個接口指針。 使用COM運行時負責定位包含coclass的可執行文件,加載它並找到正確的類工廠實現。

查找可執行文件是棘手的部分,這通常由注冊表中的信息完成。 在組件注冊時進入那里。 不僅僅是,清單也可以是此信息的來源。 它需要嵌入客戶端應用程序,這是它不是通用解決方案的一個原因。 更現代的是Windows商店/電話/通用應用程序中的包清單。 必需的,只有非常特權的組件仍然可以使用注冊表讓自己被發現。 Microsoft組件。

一個完全不同的方面是定制類工廠。 例如,在DirectX中完成它的方式,根本不依賴於注冊表。 您可以調用CreateDevice()。 仍然稱這個COM有點拉伸,它是一種更通用的技術,稱為基於接口的編程

這一切都適用於對象,接口是不同的。 您調用IUnknown :: QueryInterface()來獲取接口指針。 不需要注冊,它是處理它的coclass。

不過,您會在HKLM \\ Software \\ Classes \\ Interface注冊表項中找到許多與Regedit.exe注冊的接口。 它們處理另一個COM細節,如果組件不在同一台機器或相同的進程或與客戶機代碼相同的線程中,則必須進行額外的工作以使調用在機器/進程/線程邊界上序列化。 在.NET Remoting中發生同樣的事情,它需要一個代理。 一個也實現相同接口但不直接執行該方法的對象,將參數傳遞給存根,以便它可以進行調用。

在.NET中很簡單,Reflection使它變得非常簡單。 在COM中並不簡單,需要一個知道如何將參數序列化為互操作數據包的額外組件。 並以相同的方式返回返回值。 代理/存根通常是從IDL自動構建的。 或者在.NET中很常見,因為它不使用IDL,你使用編組器從類型庫中挖掘出方法細節。 這種機制與.NET Reflection高度可比,類型庫與.NET元數據的作用完全相同。

Interface鍵中的ProxyStubClsId32注冊表項包含該組件的CLSID。 你會經常在那里找到{00000320-0000-0000-C000-000000000046},這是系統提供的使用類型庫的編組器。

Regasm不編寫接口密鑰,它將.NET [ComVisible]類的ThreadingModel密鑰設置為“Both”。 這樣就可以從STA和MTA線程調用這些方法,而無需編組。 這是非常樂觀的,很少測試,編寫線程安全的.NET代碼並不容易。

關於你的第一個問題,如果不應該在COM上下文中使用接口,或者如果接口派生自IDispatch並且你只使用后期綁定,則不需要注冊它。

但是,如果使用早期綁定,或者如果應該在COM上下文中使用該接口,則需要注冊它。

只是注冊一個接口不能啟用編組,所有參數類型和返回類型也必須是可編組的,即不是HANDLE或類似的。

關於你的第二個問題,我希望你在閱讀到目前為止的答案后能夠自己回答。 如果不,

如果您不注冊接口,則無法在COM上下文中直接使用它。 如果它來自某個已注冊的接口,則可以使用該接口,例如基於IDispatch的接口。

但是,很少有接口像IDispatch一樣通用,因此對於任何其他基本接口,您將無法使用派生接口的新方法。

在類型庫中,如果不注冊事件dispinterface ,那么開發工具(通常是IDE)將無法向您顯示可以觸發哪些事件,或者根本不顯示任何事件。 如果您的編程語言具有該選項,那么唯一的另一個選擇是手動實現dispinterface ,這需要首先需要與缺少的IDL相當的文檔。

一個常見的極端是讓所有對象只是實現IDispatch而不是其他接口,但這又會阻礙開發工具對方法列表,代碼完成和/或參數選擇(例如IntelliSense)所做的任何努力。 請注意,有時這是足夠的,例如在為IE的JScript實現window.external對象時,但在更常見的對象中完成時有點懶惰。

一般情況下,如果您需要很少的額外工作來注冊接口,假設您已經定位到COM,請執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM