【问题标题】:C# - How To Convert Object To IntPtr And Back?C# - 如何将对象转换为 IntPtr 并返回?
【发布时间】:2013-06-24 18:20:41
【问题描述】:

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

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

【问题讨论】:

  • 使用 GCHandle 固定它

标签: c# winapi callback marshalling intptr


【解决方案1】:

所以如果我想通过 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

编辑: 如 cmets 所述,您需要在使用后松开手柄。我也使用铸造。使用静态方法GCHandle.ToIntPtr(handle1)GCHandle.FromIntPtr(parameter) 可能是明智之举,例如here。我还没有验证。

【讨论】:

  • 不再需要时,句柄必须是freed!此代码泄漏
  • @dario_ramos 有道理。我添加了一条注释。
【解决方案2】:

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

我越来越喜欢为此创建扩展,因此它显示为: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);
}

【讨论】:

  • 壮观。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
相关资源
最近更新 更多