C# - Как Преобразовать Объект В IntPtr И Обратно?

Я хочу передать объект из управляемого кода в функцию WinApi как IntPtr. Он передаст этот объект обратно в мою функцию обратного вызова в управляемом коде как IntPtr. Это не структура, это экземпляр класса.

как преобразовать object to IntPtr и обратно ?

2 ответов


поэтому, если я хочу передать список моей функции обратного вызова через 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 Дэвид Хеффернан

Edit: как отмечено в комментариях, вам нужно освободить ручку после использования. Также я использовал кастинг. Было бы разумно использовать статические методы GCHandle.ToIntPtr(handle1) и GCHandle.FromIntPtr(parameter) как здесь. Я этого не проверял.


в то время как принятый ответ правильный, я хотел добавить немного к нему.

Я полюбил создавать расширения для этого, поэтому он читает: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);
}