web-dev-qa-db-ja.com

C#-オブジェクトをIntPtrに変換して戻す方法

マネージコードからWinApi関数にIntPtrとしてオブジェクトを渡したいです。このオブジェクトは、マネージコードでIntPtrとしてコールバック関数に返されます。それは構造ではなく、クラスのインスタンスです。

objectIntPtrに変換して戻す方法

41
Bitterblue

したがって、WinApiを介してコールバック関数にリストを渡したい場合は、 GCHandle を使用します

_// object to IntPtr (before calling WinApi):
List<string> list1 = new List<string>();
GCHandle handle1 = GCHandle.Alloc(list1);
IntPtr parameter = (IntPtr) handle1;
// call WinAPi and pass the parameter here
// then free the handle when not needed:
handle1.Free();

// back to object (in callback function):
GCHandle handle2 = (GCHandle) parameter;
List<string> list2 = (handle2.Target as List<string>);
list2.Add("hello world");
_

Thxから David Heffernan

Edit:コメントに記載されているように、使用後にハンドルを解放する必要があります。また、私は鋳造を使用しました。 here のような静的メソッドGCHandle.ToIntPtr(handle1)およびGCHandle.FromIntPtr(parameter)を使用するのが賢明かもしれません。私はそれを確認していません。

55
Bitterblue

受け入れられた答えは正しいですが、少し追加したかったのです。

list1.ToIntPtr()という読み取り専用の拡張機能を作成することを好みました。

public static class ObjectHandleExtensions
{
    public static IntPtr ToIntPtr(this object target)
    {
        return GCHandle.Alloc(target).ToIntPtr();
    }

    public static GCHandle ToGcHandle(this object target)
    {
        return GCHandle.Alloc(target);
    }

    public static IntPtr ToIntPtr(this GCHandle target)
    {
        return GCHandle.ToIntPtr(target);
    }
}

また、これをどの程度行っているかにもよりますが、IDisposableにリストを含めるのは良いことかもしれません。

public class GCHandleProvider : IDisposable
{
    public GCHandleProvider(object target)
    {
        Handle = target.ToGcHandle();
    }

    public IntPtr Pointer => Handle.ToIntPtr();

    public GCHandle Handle { get; }

    private void ReleaseUnmanagedResources()
    {
        if (Handle.IsAllocated) Handle.Free();
    }

    public void Dispose()
    {
        ReleaseUnmanagedResources();
        GC.SuppressFinalize(this);
    }

    ~GCHandleProvider()
    {
        ReleaseUnmanagedResources();
    }
}

そして、あなたはこのようにそれを消費するかもしれません:

using (var handleProvider = new GCHandleProvider(myList))
{
    var b = EnumChildWindows(hwndParent, CallBack, handleProvider.Pointer);
}
7
Josh Gust