次のサンプルでは、Microsoft's documentationからです:安全な方法
public delegate bool CallBack(int handle, IntPtr param);
public class LibWrap
{
// passing managed object as LPARAM
// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
[DllImport("user32.dll")]
public static extern bool EnumWindows(CallBack cb, IntPtr param);
}
public class App
{
public static void Main()
{
Run();
}
[SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
public static void Run()
{
TextWriter tw = System.Console.Out;
GCHandle gch = GCHandle.Alloc(tw);
CallBack cewp = new CallBack(CaptureEnumWindowsProc);
// platform invoke will prevent delegate to be garbage collected
// before call ends
LibWrap.EnumWindows(cewp, GCHandle.ToIntPtr(gch));
gch.Free();
}
private static bool CaptureEnumWindowsProc(int handle, IntPtr param)
{
GCHandle gch = GCHandle.FromIntPtr(param);
TextWriter tw = (TextWriter)gch.Target;
tw.WriteLine(handle);
return true;
}
}
私を神秘2つのものがあります。
まず、GCHandle.Alloc
のドキュメントでは、オブジェクトがガベージコレクションされないようにすることについてのみ説明しています。それがすべてだった場合は、GCHandle.Alloc
は必要ありません。明らかに、サンプルではtw
は、EnumWindows
へのコール中に収集されません。機能スコープに参照があります。
がに移動していないことを確認する必要があります。しかし、GCHandle.Alloc
のドキュメントではそのことについて話しません。どうしたの?
第2に、代議員はどうですか?このサンプルに問題はないかもしれませんが、デリゲートがオブジェクト(クラスのクロージャまたは非スタティックメソッドを持つラムダ)にバインドされている場合はどうなりますか?その場合、デリゲートの世話をする必要があります。それは別のGCHandle.Alloc(myDelegate)
ですか、それとももっと検討する必要がありますか?
ああ、私は実際に参照を使用するものの管理されていない側ではないので、ピンで固定する必要はありません。管理されていない側が参照解除されている場合のみ、ピン設定が必要になります。最後の2つの文で説明したシナリオで、デリゲート(または関連オブジェクト)を固定する必要がない理由はまだ分かりません。 – John
p/invoke marshallerは、呼び出しが返るまでデリゲートが存続することを保証します。それで十分です。デリゲートオブジェクトは固定する必要はありません。マーシャラは、アドレスがアンマネージコードに渡されるアンマネージサンク(デリゲートを呼び出す)を作成します。非管理コードは直接デリゲートを呼び出すことができないため、デリゲートオブジェクトのアドレスはアンマネージコードに渡されません。したがって、サンクの必要性。 –
そして、サンクは私が推測するスタックに住んでいます。それは理にかなっている。私がまだ理解していない唯一のことは、私がそうする必要がある場合にオブジェクトを固定するために何をしなければならないかということです。アンマネージコードが参照解除されていて、元の呼び出しが戻った後でそうしています。 'fixed'ステートメントはスコープ用のものだけを固定しますので、何かを無期限に修正したいのであれば(あるいはプログラムで固定するまで)何を使用しますか? – John