Je veux passer un objet du code managé à une fonction WinApi en tant que IntPtr
. Il transmettra cet objet à ma fonction de rappel dans le code managé comme IntPtr
. Ce n'est pas une structure, c'est une instance d'une classe.
Comment puis-je convertir object
en IntPtr
et vice versa?
Donc, si je veux passer une liste à ma fonction de rappel via WinApi, j'utilise 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");
Merci à David Heffernan
Edit: Comme indiqué dans les commentaires, vous devez libérer la poignée après utilisation. J'ai aussi utilisé le casting. Il pourrait être judicieux d'utiliser les méthodes statiques GCHandle.ToIntPtr(handle1)
et GCHandle.FromIntPtr(parameter)
comme ici . Je ne l'ai pas vérifié.
Bien que la réponse acceptée soit correcte, je voulais y ajouter un peu.
J'ai adoré créer des extensions pour cela, il indique: 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);
}
}
De plus, en fonction de ce que vous faites, il peut être intéressant de contenir votre liste dans 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();
}
}
Et puis vous pourriez le consommer comme ceci:
using (var handleProvider = new GCHandleProvider(myList))
{
var b = EnumChildWindows(hwndParent, CallBack, handleProvider.Pointer);
}