C# - ¿Cómo Convertir Un Objeto A IntPtr Y Viceversa?


Quiero pasar un objeto desde el código administrado a una función WinAPI como IntPtr. Pasará este objeto de vuelta a mi función de devolución de llamada en código administrado como IntPtr. No es una estructura, es una instancia de una clase.

¿Cómo convertir object a IntPtr y viceversa ?

Author: Bitterblue, 2013-06-27

2 answers

Entonces, si quiero pasar una lista a mi función de devolución de llamada a través de WinAPI, uso 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 a David Heffernan

Edit: Como se indica en los comentarios, debe liberar el controlador después de usarlo. También usé casting. Podría ser sabio usar los métodos estáticos GCHandle.ToIntPtr(handle1) y GCHandle.FromIntPtr(parameter) como aquí. No he verificado eso.

 45
Author: Bitterblue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-08 17:20:57

Si bien la respuesta aceptada es correcta, quería agregar un poco a ella.

He crecido aficionado a la creación de extensiones para esto por lo que se lee: 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);
    }
}

También, dependiendo de cuánto de esto estés haciendo, podría ser bueno contener tu lista en un 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();
    }
}

Y entonces podrías consumirlo así:

using (var handleProvider = new GCHandleProvider(myList))
{
    var b = EnumChildWindows(hwndParent, CallBack, handleProvider.Pointer);
}
 2
Author: Josh Gust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-31 17:43:24