How to use SafeHandle in a Resilient Library

SafeHandles や非同期例外については関係についてはこの日記でも以前から何度も取り上げていますが,「BCLTeam's WebLog」に新しいエントリが出ていたので紹介と.

How to use SafeHandle in a Resilient Library
http://blogs.msdn.com/bclteam/archive/2006/06/23/644343.aspx

P/Invoke や COM Interop などで下回りのコードを書く人は原則論として理解しておくべき内容なんですが,それ以前に「簡単に (アンマネージ) API・DLL を呼べます!」と煽っている連中がまず熟読すべきなんでしょうなぁ.呼ぶのは簡単でも動かすのは簡単じゃねーんだぞ,と.



Web で読める日本語資料としては,次の 2 つがおすすめです.

  1. 高可用性 .NET Framework の信頼性機能でコードを実行し続ける
  2. .NET Framework 開発者ガイド 信頼性に関するベスト プラクティス

特に後者については量が多いのでついつい読み流しかもしれませんが,実際網羅性はかなり高いです.

一部のコンテキストでは、SafeHandle は適切ではありません。ReleaseHandle メソッドは、GC ファイナライザ スレッドで実行できるため、特定のスレッドで解放する必要のあるハンドルを SafeHandle にラップする必要はありません。

例えばこれは,以前触れた Direct3D Device オブジェクトの解放を GC スレッドから行えない(id:NyaRuRu:20050526#p6) という問題そのもの.
とりあえず .NET Framework 開発者ガイド 信頼性に関するベスト プラクティス の「コード分析規則」を読みながら,「んっ?」と思った箇所を重点的に調べてみると良いかもしれません.

コード分析規則

SafeHandle を使用して、オペレーティング システム リソースをカプセル化します。HandleRef または IntPtr 型のフィールドは使用しないでください。

こういうのが沢山書いてあります.他にもこういうのは言われないと中々気付かないでしょう.

STA に依存する機能を識別する

COM シングルスレッド アパートメント (STA: Single-Threaded Apartment) を使用するコードを識別します。SQL Server プロセスでは、STA は無効になります。パフォーマンス カウンタやクリップボードなど、CoInitialize に依存する機能は SQL Server 内では無効にする必要があります。

あーでも一部の訳はミスリーディングかも.

Do Not Assume a Managed Thread Is a Win32 Thread – It Is a Fiber
Win32 スレッドはファイバであるため、マネージ スレッドが Win32 スレッドであることを想定しない
SQL Server runs in fiber mode; do not use thread local storage.
SQL Server はファイバ モードで実行します。スレッド ローカル ストレージは使用しないでください。

まあ「んっ?」と思ったら訳の問題だったという可能性もあるということで.