C# - 如何将对象转换为IntPtr并返回?

问题描述 投票:35回答:2

我想将托管代码中的对象作为IntPtr传递给WinApi函数。它会将此对象作为IntPtr传递回托管代码中的回调函数。它不是一个结构,它是一个类的实例。

如何将object转换为IntPtr并返回?

c# winapi callback marshalling intptr
2个回答
52
投票

因此,如果我想通过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");

感谢David Heffernan

编辑:如评论中所述,您需要在使用后释放句柄。我也用过铸造。使用像GCHandle.ToIntPtr(handle1)这样的静态方法GCHandle.FromIntPtr(parameter)here可能是明智的。我还没有证实。


5
投票

虽然接受的答案是正确的,但我想补充一点。

我喜欢为此创建扩展,所以它写道: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);
}
© www.soinside.com 2019 - 2024. All rights reserved.