Le rappel transmis à CreateTimerQueueTimer doit être une fonction non managée qui existera pour la durée de vie des rappels. Le délégué géré peut se déplacer dans la mémoire mais the underlying stub created by the marshalling will not do this so there is no need to pin the delegate. Il y a cependant un besoin d'empêcher le délégué d'être collecté car le pointeur du code non géré n'est pas suffisant pour le maintenir en vie. Le paramètre PVOID transmis à la fonction de rappel doit être fixé en mémoire, car la fonction non gérée attend Dans .Net, cet épinglage se produit (efficacement) automatiquement mais seulement pour la durée de vie de la fonction appelée, donc si vous utilisez une référence à un objet géré (par exemple en lui envoyant un IntPtr) l'objet sous-jacent doit être épinglé (encore une fois le GCHandle peut être utilisé de façon subtilement différente.) Pour voir si c'est le problème, essayez IntPtr.Zero comme paramètre pour tester si cela fonctionne
Si cela résout mince Si vous avez besoin d'allouer votre paramètre en octets bruts dans le tas non géré (et marshal en conséquence), utilisez un type blittable qui est sûr de mettre quelque chose de taille PVOID (comme un Int32) ou utilisez la technique GCHandle ci-dessus pour maintenir un pointeur stable vers une instance gérée, cela aura des conséquences significatives sur les performances si cela est fait à tort.
Vous n'êtes généralement pas obligé d'affecter les délégués passés aux fonctions de l'API, car InteropServices gère ces éléments. Vous * devez * vous assurer que votre application conserve une référence au délégué afin qu'il ne soit pas collecté. L'épinglage est normalement nécessaire uniquement lors du passage de blocs de mémoire du monde géré dans le monde non géré (qui s'attend à ce que les choses restent là où elles sont). – MusiGenesis
@MusiGenesis, c'est ce que je faisais allusion à "Dans .Net, il est presque certain qu'il arrive à tout ce que vous passez.", Je devrais probablement avoir appelé cela comme étant spécifique à PInvoke. De même, je n'ai vu aucune raison de mentionner la nécessité de garder une référence car P/Invoke fait cela pour vous si cela est nécessaire: http://msdn.microsoft.com/en-us/23acw07k.aspx – ShuggyCoUk
PInvoke ne maintient définitivement pas de délégué références pour vous. Le compilateur vous laissera heureusement appeler CreateTimerQueueTimer et passera 'new TimerCallback (...)' en tant que paramètre. Cela fonctionnera même avec succès pendant un certain temps, jusqu'à ce que le délégué que vous avez créé avec 'new' arrive à être ramassé. – MusiGenesis