實作In-Process延伸模組的指引

進程內延伸模組會載入任何觸發它們的進程。 例如,Shell 命名空間延伸模組可以載入任何直接或間接存取 Shell 命名空間的進程。 Shell 命名空間是由許多 Shell 作業使用,例如顯示通用檔案對話方塊、透過其相關聯的應用程式開機檔案,或取得用來表示檔案的圖示。 由於進程內延伸模組可以載入任意進程,因此請務必小心,它們不會對主應用程式或其他進程內延伸模組造成負面影響。

特定附注的其中一個執行時間是Common Language Runtime (CLR) ,也稱為Managed 程式碼.NET FrameworkMicrosoft 建議不要將受控進程內延伸模組寫入 Windows 檔案總管或 Windows Internet Explorer,而且不會將其視為支援的案例。

本主題討論當您判斷 CLR 以外的任何執行時間是否適合由進程內擴充功能使用時要考慮的因素。 其他執行時間的範例包括 JAVA、Visual Basic、JavaScript/ECMAScript、Delphi 和 C/C++ 執行時間程式庫。 本主題也提供一些在進程內延伸模組中不支援 Managed 程式碼的原因。

版本衝突

版本衝突可能是透過不支援在單一進程內載入多個執行時間版本的執行時間所引發。 4.0 版之前的 CLR 版本屬於此類別。 如果某個版本的執行時間載入會排除載入該相同執行時間的其他版本,如果主應用程式或其他同進程擴充功能使用衝突的版本,這可能會產生衝突。 如果版本與另一個同進程延伸模組發生衝突,衝突可能會很困難,因為失敗需要正確的衝突延伸模組,而失敗模式取決於載入衝突延伸模組的順序。

請考慮使用 4.0 版之前的 CLR 版本所撰寫的程式內擴充功能。 使用 [ 開啟 ] 對話方塊之電腦上的每一個應用程式,可能會有對話方塊的 Managed 程式碼及其載入應用程式進程的語音應答 CLR 相依性。 第一次將 4.0 版 CLR 載入應用程式或擴充功能的應用程式或擴充功能,會限制該應用程式的處理常式後續可以使用哪一個 CLR 版本。 如果具有 [開啟 ] 對話方塊的受管理應用程式是以衝突的 CLR 版本為基礎建置,則擴充功能可能無法正確執行,而且可能會導致應用程式中失敗。 相反地,如果擴充功能是第一個載入進程,而衝突版本的 Managed 程式碼會嘗試在該 (之後啟動,或執行中的應用程式可能需要載入 CLR) ,作業就會失敗。 對使用者,應用程式的某些功能會隨機停止運作,或應用程式意外當機。

請注意,CLR 版本等於或更新版本 4.0 通常不會受到版本控制問題的影響,因為它們的設計目的是彼此共存,而且 CLR (的 4.0 版除外,但版本 1.0 除外,無法與其他版本共存) 。 不過,如本主題其餘部分所述,可能會發生版本衝突以外的問題。

效能問題

當執行時間載入進程時,可能會發生效能問題,而造成顯著的效能負面影響。 效能損失可以是記憶體使用量、CPU 使用量、經過的時間,或甚至是位址空間耗用量的形式。 CLR、JavaScript/ECMAScript 和 JAVA 已知為高影響執行時間。 由於同進程擴充功能可以載入許多進程,而且通常會在效能敏感的時刻 (,例如準備要顯示使用者) 的功能表時,高影響執行時間可能會對整體回應造成負面影響。

耗用大量資源的高影響執行時間可能會導致主機進程或其他進程內延伸模組失敗。 例如,對堆積耗用數百 MB 位址空間的高影響執行時間,可能會導致主應用程式無法載入大型資料集。 此外,由於進程內延伸模組可以載入多個進程,單一延伸模組中的高資源耗用量可以快速地乘以整個系統的高資源耗用量。

如果執行時間仍會繼續載入,否則即使使用該執行時間的擴充功能已卸載,仍會繼續取用資源,則該執行時間不適用於擴充功能。

.NET Framework的特定問題

下列各節將討論使用 Managed 程式碼進行延伸模組時發現的問題範例。 它們不是您可能會遇到的所有可能問題的完整清單。 這裡所討論的問題都是擴充功能中不支援 Managed 程式碼的原因,以及當您評估其他執行時間使用時所要考慮的點。

重新進入

當 CLR 封鎖單一線程 Apartment (STA) 執行緒時,例如,由於 Monitor.Enter、WaitHandle.WaitOne 或競爭 的鎖定 語句,CLR 在其標準設定中輸入巢狀訊息迴圈。 許多擴充方法都禁止處理訊息,而且這種無法預期和非預期的重新進入可能會導致難以重現和診斷的異常行為。

多執行緒 Apartment

CLR 會為元件物件模型建立 執行時間可呼叫包裝函 式, (COM) 物件。 這些相同的執行時間可呼叫包裝函式稍後會由 CLR 的完成項終結,這是多執行緒 Apartment (MTA) 的一部分。 將 Proxy 從 STA 移至 MTA 需要封送處理,但無法封送處理延伸模組所使用的所有介面。

不具決定性的物件存留期

CLR 的物件存留期保證比原生程式碼還弱。 許多延伸模組對物件和介面都有參考計數需求,而且 CLR 所採用的垃圾收集模型無法滿足這些需求。

  • 如果 CLR 物件取得 COM 物件的參考,執行時間可呼叫包裝函式所持有的 COM 物件參考不會釋放,直到執行時間可呼叫包裝函式被垃圾收集為止。 非決定性發行行為可能會與某些介面合約衝突。 例如, IPersistPropertyBag::Load 方法要求當 Load 方法傳回時,物件不會保留屬性包的參考。
  • 如果 CLR 物件參考傳回原生程式碼,執行時間可呼叫包裝函式會在進行執行時間可呼叫包裝函式的最終呼叫 Release 時,將其參考給 CLR 物件,但基礎 CLR 物件在垃圾收集之前不會完成。 非決定性最終處理可能會與某些介面合約衝突。 例如,當其參考計數下降為零時,需要縮圖處理常式立即釋放所有資源。

Managed 程式碼和其他執行時間可接受的用法

可以使用 Managed 程式碼和其他執行時間來實作跨進程延伸模組。 跨進程殼層延伸模組的範例包括:

  • 預覽處理常式
  • 命令列型動作,例如在殼層\動詞\命令子機碼下註冊的動作。
  • 針對允許跨進程啟用的 Shell 擴充點,在本機伺服器中實作的 COM 物件。

某些延伸模組可以實作為同進程或跨進程延伸模組。 如果這些延伸模組不符合同進程擴充功能的需求,您可以實作這些延伸模組作為跨進程延伸模組。 下列清單顯示可實作為同進程或跨進程延伸模組的延伸模組範例:

  • 與在殼層\動詞\命令子機碼下註冊的DelegateExecute 專案相關聯的 IExecuteCommand
  • 與在殼層\動詞\DropTarget子機碼下註冊的 CLSID 相關聯的IDropTarget
  • 與 Shell動詞子機碼下\ 註冊的CommandStateHandler專案相關聯的IExplorerCommandState