共用方式為


安全控制代碼和關鍵結束

在 .NET Framework 2.0 版之前,所有的作業系統控制代碼都只能被封裝在 IntPtr Managed 包裝函式物件。 儘管這是與機器碼進行相互操作的方便作法,控制代碼卻可能因為未預期的執行緒中止或堆疊溢位 (Stack Overflow) 一類的非同步例外狀況 (Exception) 而遺漏。 這些非同步例外狀況是清除作業系統資源的阻礙,而且可能會在程式中的任何位置發生。 這些例外狀況最容易在使用執行 Managed 程式碼之主機的應用程式 (例如 Microsoft SQL Server) 中發生。

在某些狀況下,在平台叫用呼叫內執行方法時,都可以使用記憶體回收來回收可完成之物件。 如果某個完成項釋放傳遞至該平台叫用呼叫的控制代碼,便可能會造成控制代碼損毀。 當進行平台叫用呼叫 (例如讀取檔案) 期間而封鎖您的方法時,也可以回收控制代碼。

更為嚴重的是,由於 Windows 會積極回收控制代碼,控制代碼可以被回收並指向可能包含敏感資料的另一項資源。 這種情形被稱為回收攻擊,而且可能會損毀資料並成為安全性威脅。

從 .NET Framework 2.0 開始,SafeHandle 類別 (Class) 便簡化了許多這些物件存留期 (Lifetime) 的問題,而且還與平台叫用整合,使作業系統資源不至於遺漏。 SafeHandle 類別會在不受干擾的情況下指派和釋放控制代碼,以解決物件存留期的問題。 其中包含一個關鍵的完成項,以確定控制代碼的關閉,並保證會在 AppDomain 卸載時執行,即使平台叫用呼叫在損毀狀態下時依然如此。

由於 SafeHandle 是從 CriticalFinalizerObject 繼承的,對於所有非關鍵完成項的呼叫都會在任何關鍵完成項之前進行。 會在已不在相同記憶體回收行程中存在/運作的物件上,呼叫這些完成項。 例如,FileStream 物件可以執行一般完成項以清除現有的緩衝資料,而不需擔心控制代碼遺漏或是被回收的風險。 這種關鍵完成項與非關鍵完成項之間的弱式排列,並不適用於一般情況。 這種排列的主要用意是要允許現有程式庫使用 SafeHandle 藉此進行程式庫的移轉,而不需要透過更改其語意 (Semantics) 的方法。 此外,關鍵完成項和其所呼叫的任何項目,例如 SafeHandle.ReleaseHandle() 方法,都必須位於受到條件約束的執行區域中。 這樣便會對可在完成項之呼叫圖形內寫入的程式碼施加條件約束。

從 .NET Framework 2.0 版開始,平台叫用作業都會自動遞增由 SafeHandle 所封裝的控制代碼參考次數 (Reference Count),並會在完成時遞減這些參考次數。 如此即可確保控制代碼不會未預期地被回收或被關閉。

您可以在建構 SafeHandle 物件時指定基礎控制代碼的擁有權。 這樣便能控制 SafeHandle 物件是否會在物件已經處置後釋放控制代碼。 這種作法對於具有特殊存留期需求的控制代碼,或是使用其存留期由他人所控制的控制代碼都相當有用。

安全控制代碼類別

System.Runtime.InteropServices 命名空間中的 SafeHandle 類別是作業系統控制代碼的抽象包裝函式類別。 從這個類別衍生並不容易。 請改用 Microsoft.Win32.SafeHandles 命名空間中的衍生類別,這些類別可為下列各項提供安全的控制代碼:

  • 檔案和管道。

  • 記憶體檢視。

  • 加密結構。

  • 登錄機碼。

  • 等候控制代碼。

請參閱

參考

SafeHandle

CriticalHandle

CriticalFinalizerObject