實作 In-Process 延伸模組的指引
進程內擴充功能會載入至觸發它們的任何進程。 例如,Shell 命名空間擴充功能可以載入任何直接或間接存取Shell命名空間的進程。 Shell 命名空間是由許多 Shell 作業使用,例如顯示通用檔案對話框、透過其相關聯的應用程式啟動檔,或取得用來表示檔案的圖示。 因為同進程延伸模組可以載入任意進程,所以必須小心不要對主應用程式或其他同進程擴充功能造成負面影響。
值得注意的一個運行時是 Common Language Runtime(CLR),也稱為 Managed 程式碼 以及 .NET Framework。 Microsoft建議不要將 Managed In-process 擴充功能寫入 Windows Explorer 或 Windows Internet Explorer,而且不會將其視為支援的案例。
本主題討論當您判斷 CLR 以外的任何運行時間是否適合供同進程擴充功能使用時要考慮的因素。 其他運行時間的範例包括 Java、Visual Basic、JavaScript/ECMAScript、Delphi 和 C/C++ 運行時間連結庫。 本主題也提供一些原因說明為什麼受控代碼在進程內擴充功能中無法被支援。
版本衝突
版本衝突可能由於執行階段不支援在單一進程中載入多個執行階段版本而發生。 4.0 版之前的 CLR 版本屬於此類別。 如果載入某個版本的執行階段會阻止載入同一執行階段的其他版本,那麼在主應用程式或其他同進程的擴充功能使用相衝突的版本時,就可能會發生衝突。 如果版本與另一個正在執行中的擴充功能發生衝突,該衝突可能會難以重現,因為需要正確的衝突擴充功能,且失敗模式取決於載入衝突擴充功能的順序。
請考慮使用 4.0 版之前的 CLR 版本所撰寫的進程內延伸模組。 每個在電腦上使用 [開啟 ] 對話框 文件的應用程式,都可能會將對話框的受管理程式代碼及其相關的 CLR 相依性載入至應用程式的程序中。 在應用程式的進程中,第一個載入 4.0 之前版本 CLR 的應用程式或擴充功能會限制該進程後續可以使用的 CLR 版本。 如果具有 Open 對話框的受控應用程式建置在衝突的 CLR 版本上,則擴充功能可能無法正確執行,而且可能會導致應用程式中失敗。 相反地,如果延伸模組是第一個載入進程,且衝突版本的 Managed 程式代碼會嘗試在該之後啟動(可能是受控應用程式或執行中的應用程式會視需要載入 CLR),則作業會失敗。 對用戶來說,應用程式的某些功能似乎會隨機停止運作,或應用程式神秘地當機。
請注意,CLR 版本等於或高於 4.0 的版本通常不會受到版本相容性問題的影響,因為它們的設計目的是彼此共存,且可與大多數 4.0 之前的 CLR 版本共存(但 1.0 版本例外,因為它不能與其他版本共存)。 不過,如本主題的其餘部分所述,可能會發生版本衝突以外的問題。
效能問題
執行環境可能會發生效能問題,當其載入到進程中時,可能會導致顯著的效能懲罰。 效能降低可以是記憶體使用量、CPU 使用量、耗用時間,甚至是位址空間耗用量的形式。 CLR、JavaScript/ECMAScript 和 Java 已知為高影響運行時間。 由於同進程擴充功能可以載入許多進程,而且通常在效能敏感時刻進行(例如在準備顯示給使用者的功能表時),高負載運行環境可能會對整體回應性造成負面影響。
耗用大量資源的高影響運行時間可能會導致主機進程或其他進程內擴充功能失敗。 例如,高影響運行時間,其堆積耗用數百 MB 的地址空間,可能會導致主應用程式無法載入大型數據集。 此外,由於進程內擴充功能可以載入多個進程,單一延伸模組中的高資源耗用量可以快速地乘以整個系統的高資源耗用量。
如果執行環境在使用該環境的擴充功能被卸除後仍繼續載入或繼續消耗資源,那麼該執行環境不適合用於擴充功能。
.NET Framework 特有的問題
下列各節將討論使用Managed程式碼進行延伸模組時所發現問題的範例。 它們不是您可能遇到的所有可能問題的完整清單。 此處討論的問題是兩個原因:其一是擴充功能中不支援 Managed 程式碼,其二是在評估使用其他執行環境時需要考量的要點。
重新進入
例如,當 CLR 因 Monitor.Enter、WaitHandle.WaitOne 或爭用的 鎖定 語句而封鎖單執行緒單元 (STA) 執行緒時,CLR 在其標準配置中會進入巢狀訊息迴圈以等待。 許多擴充方法都被禁止處理訊息,這種無法預測和意外的重入可能會導致難以重現和診斷的異常行為。
多線程公寓
CLR 會為元件物件模型 (COM) 物件建立 執行階段可呼叫包裝器。 這些相同的可運行時調用的包裝器稍後會由CLR的終結器摧毀,這是多執行緒單元(MTA)的一部分。 將 Proxy 從 STA 移至 MTA 需要封送處理,但擴充元件所使用的所有介面都無法封送處理。
不具決定性的物件存留期
CLR 的物件存留期保證度比本機代碼弱。 許多延伸模組都有物件和介面的參考計數需求,而CLR採用的垃圾收集模型無法滿足這些需求。
- 如果一個 CLR 物件取得一個 COM 物件的參考,那麼由運行時可呼叫包裝器所持有的 COM 物件參考在運行時可呼叫包裝器被垃圾回收之前不會被釋放。 非決定性發行行為可能會與某些介面合約衝突。 例如,IPersistPropertyBag::Load 方法要求,在 Load 方法傳回時,該物件不能保留任何屬性包的參考。
- 如果將 CLR 物件參考傳回給原生代码,運行時可呼叫包裝器在最後一次呼叫 Release 時,會放棄對 CLR 物件的引用,但基礎 CLR 物件要等到垃圾收集時才會被最終處理。 非決定性最終化可能會與某些介面合約衝突。 例如,縮圖處理程式必須在參考計數降至零時立即釋放所有資源。
受管理程式碼及其他執行環境的可接受用法
使用受管理代碼和其他執行環境來實作外部進程擴展是可接受的。 例如,跨進程 Shell 擴展包括以下範例:
- 預覽處理程式
- 命令行式動作,例如在 Shell 下註冊的動作,\動詞\命令的 子鍵。
- 在本機伺服器中實作的 COM 物件,適用於允許跨進程啟用的殼層擴充點。
某些延伸模組可以實作為同進程或跨進程延伸模組。 如果這些擴充功能不符合同進程擴充功能的需求,您可以將這些擴充功能實作為獨立進程擴充功能。 下列表顯示可實作為同進程或跨進程的延伸模組範例:
- IExecuteCommand 與註冊在外殼下的DelegateExecute 項目相關聯並位於\動詞\命令 子機碼。
- IDropTarget 與在 殼層下註冊的 CLSID 相關聯,\動詞命令\DropTarget 子機碼。
- IExplorerCommandState 與 CommandStateHandler 項目相關聯,殼層\動詞 子機碼下註冊。