2009-02-08 2 views
33

Sans me diriger vers MSDN, quelqu'un peut-il donner une explication concise et claire du but de chacun d'entre eux et du moment où les utiliser. (IntPtr, SafeHandle et HandleRef)IntPtr, SafeHandle et HandleRef - Expliqué

+1

Quel est le problème avec MSDN? –

+8

Rien. Je cherche juste un bref résumé de chacun pour m'assurer que je les utilise correctement. Si je lis MSDN et les descriptions des autres, je comprends mieux si ce que je fais est correct. – user62572

Répondre

46

IntPtr est simplement une structure basée sur un nombre entier qui peut contenir un pointeur (par exemple, la taille de 32 bits sur les systèmes 32 bits, la taille de 64 bits sur les systèmes 64 bits).

SafeHandle est une classe qui est destinée à contenir les poignées d'objet Win32 - elle a un finaliseur qui s'assure que le handle est fermé lorsque l'objet est GC'ed. SafeHandle est une classe abstraite, car différentes poignées Win32 ont différentes manières dont elles doivent être fermées. Avant l'introduction de SafeHandle, IntPtr était utilisé pour contenir les handles Win32, mais s'assurer que ceux-ci étaient correctement fermés et empêchés d'être GC'ed était la responsabilité du programmeur.

HandleRef est un moyen de s'assurer qu'un handle non géré n'est pas GC'ed lorsque vous êtes au milieu d'un appel P/Invoke. Sans quelque chose comme HandleRef, si votre code managé ne fait rien avec le handle après l'appel P/Invoke, si le GC était exécuté pendant l'appel P/Invoke, il ne réaliserait pas que le handle était encore utilisé et pourrait le GC . J'imagine (mais je ne suis pas sûr et n'ai pas regardé) que SafeHandle pourrait utiliser HandleRef dans le cadre de sa gestion de la poignée encapsulée.

+13

Correction mineure. Utilisez HandleRef lorsque vous ne voulez pas d'objet GC * * géré pendant PInvoke. par exemple classe HWnd {public IntPtr Handle; } HWnd a = new HWnd(); B.SendMessage (a.Handle, ...); <- a pourrait être GC'ed dans PInvoke B.SendMessage (nouveau HandleRef (a, a.Handle)) <- maintenant un ne peut pas être GC'ed dans PInvoke –

+3

Un autre ajout: 'SafeHandle' inclut le compte de référence à empêcher les attaques de recyclage des poignées. –

+0

Quelqu'un peut-il confirmer l'utilisation de safehandle handleref?Ou au moins a un mécanisme similaire? – Assimilater

16
HWnd a = new HWnd(); 
B.SendMessage(a.Handle, ...); 

En supposant que c'est la seule référence à « un » dans le programme, ce qui équivaut à:

HWnd a = new HWnd(); 
IntPtr h = a.Handle; 
// a is no longer needed and thus can be GC'ed 
B.SendMessage(h, ...); 

Le problème est que lorsque « a » est disposé, il fermera la poignée. Si cela se produit avant ou pendant l'appel à SendMessage, le handle ne sera pas valide. HandleRef évite que "a" ne soit collecté avant que le programme ne soit terminé avec h.

1

Il ressemble à SafeHandle n'intègre le comportement KeepAlive de HandleRef: Project Roslyn SafeHandle.cs http://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/safehandle.cs,743afbddafaea263

/* 
    Problems addressed by the SafeHandle class: 
    1) Critical finalization - ensure we never leak OS resources in SQL. Done 
    without running truly arbitrary & unbounded amounts of managed code. 
    2) Reduced graph promotion - during finalization, keep object graph small 
    3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread ---- (HandleRef) 
<...> 
*/ 

Mais je ne suis pas sûr, il semble que le comportement keepalive ne peut être acheived en offrant une valeur fausse au constructeur qui simplement marque l'objet comme n'étant pas finalisable, vous devez donc appeler manuellement Dispose() de SafeHandle pour éviter les fuites de ressources dans ce cas, ai-je raison? Quelqu'un peut-il expliquer code source, ce qui est le

private extern void InternalDispose(); 
private extern void InternalFinalize(); 

?

Questions connexes