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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17339928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:13:57  来源:igfitidea点击:

C# - How To Convert Object To IntPtr And Back?

c#winapicallbackmarshallingintptr

提问by Bitterblue

I want to pass an object from managed code to a WinApi function as IntPtr. It will pass this object back to my callback function in managed code as IntPtr. It's not a structure, it's an instance of a class.

我想将托管代码中的对象作为IntPtr. 它会将这个对象作为IntPtr. 它不是一个结构,它是一个类的实例。

How do I convert objectto IntPtrand back ?

我如何转换objectIntPtr和返回?

采纳答案by Bitterblue

So if I want to pass a list to my callback function through WinApi I use GCHandle

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

感谢大卫·赫弗南

Edit:As noted in the comments, you need to free the handle after use. Also I used casting. It might be wise to use the static methods GCHandle.ToIntPtr(handle1)and GCHandle.FromIntPtr(parameter)like here. I haven't verified that.

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

回答by Josh Gust

While the accepted answer is correct, I wanted to add a little bit to it.

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

I have grown fond of creating extensions for this so it reads: list1.ToIntPtr().

我越来越喜欢为此创建扩展,所以它写着: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);
    }
}

Also, depending on how much of this you're doing, it might be nice to contain your list in an IDisposable.

此外,根据您所做的工作量,将您的列表包含在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();
    }
}

And then you might consume it like this:

然后你可能会像这样消费它:

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