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

时间:2013-06-27 09:48:27

标签: c# winapi callback marshalling intptr

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

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

2 个答案:

答案 0 :(得分: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");

Thx to David Heffernan

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

答案 1 :(得分:5)

虽然接受的答案是正确的,但我想在此添加一些内容。

我已经很喜欢为此创建扩展名,因此其内容为:$(function(){ $('#stack_name').on('change keyup paste', function(){ $(#'stack_label').text($(this).val()); }); $('#bucket').change(function(){ $(#'bucket_label').text($(this).val()); }); $('#key_pair').change(function(){ $(#'key_pair_label').text($(this).val()); }); });

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();
    }
}