1

管理されていないリソースを取得して解放する必要があるサードパーティのライブラリと通信しています。SafeHandleいくつか読んだ後、リソース参照を管理するための最良かつ「正しい」方法は、またはCriticalHandleオブジェクトのいずれかであるという結論に達しました。

私の問題は、サード パーティのライブラリによって返されるハンドルがポインターではなく、符号なしの短い数値であるため発生します。MarshalAsAttribute返されたハンドルにを指定すると、 が得られますMarshalDirectiveException(CriticalHandles には MarshalAs 属性が設定されていてはならず、配列では使用できません)。

ここに私が検討したものがあります:

  • ハンドルを数値形式でマーシャリングし、メソッドCriticalHandleを介してラップします。Criticalhandle.SetHandleこれにより、参照の取得とカプセル化の間に例外が発生した場合、ハンドルがリークする可能性があります。
  • ハンドルを数値形式でマーシャリングして格納します。包含型を実装しCriticalFinalizerObjectます。これにより、参照の取得とカプセル化の間に例外が発生した場合、ハンドルがリークする可能性があります。
  • ハンドルをSafeHandleとしてマーシャリングしますIntPtr(最上位の 2 バイトを準ガベージで埋めます)。ネイティブDangerousGetHandleメソッドをSafeHandle. これにより、ハンドルの潜在的な漏れを防ぐことができますが、非常に面倒で、力ずくで間違ったソリューションを機能させているように見えます。

これらの「ハンドル」をどのように処理すればよいですか?

4

2 に答える 2

2

SafeHandleここで行うべき正しいことは、 (に類似し、から派生した独自のラッパーを実装することだと思います。次に、制約さCriticalFinalizerObjectれた実行領域でハンドルを作成する P/Invoke メソッドへの呼び出しをラップして、マネージド ハンドル ラッパーが適切に初期化されるようにします。

注: 以前は CER を使用する必要がなかったので、検証がなければ、このコードが出発点となることを願うばかりです。

[DllImport("blah.dll")]
private static extern ushort CreateMySpecialHandle();

public static SafeSpecial Handle Foo()
{
    SafeSpecialHandle safeHandle = new SafeSpecialHandle();
    System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
    }
    finally
    {
        ushort rawHandle = CreateMySpecialHandle();
        safeHandle.SetHandle(rawHandle);
    }

    if (safeHandle.IsInvalid)
    {
        // throw exception here, or other error handling
    }

    return safeHandle;
}
于 2012-07-04T16:09:03.323 に答える
1

@HansPassant が私の質問へのコメントで述べたように:

ネイティブ コードが 32 ビットの場合、SafeHandle を機能させることができます。C または C++ 関数呼び出しでは、短い引数は常に int に昇格されます。IntPtr はそれを混乱させません。– Hans Passant 7 月 4 日 15:10

したがって、C/C++ unsigned short を の派生物に直接マーシャリングすることが可能ですSafeHandle

于 2012-07-18T14:49:53.547 に答える