2009-02-08 9 views
33

Senza indicarmi MSDN, qualcuno potrebbe fornire una spiegazione concisa e chiara dello scopo di ciascuno di questi e quando utilizzarli. (IntPtr, SafeHandle e HandleRef)IntPtr, SafeHandle e HandleRef - Explained

+1

Cosa c'è che non va con MSDN? –

+8

Niente. Sto solo cercando un breve riassunto di ciascuno per assicurarmi che li stia usando correttamente. Se leggo MSDN e le descrizioni di altre persone, ho una sensazione migliore se quello che sto facendo è corretto. – user62572

risposta

46

IntPtr è solo una semplice struttura integer che può contenere un puntatore (ad esempio, a 32 bit su sistemi a 32 bit, a 64 bit su sistemi a 64 bit).

SafeHandle è una classe destinata a contenere gli handle di oggetti Win32 - ha un finalizzatore che si assicura che l'handle sia chiuso quando l'oggetto è GC. SafeHandle è una classe astratta perché le diverse maniglie Win32 hanno diversi modi per cui devono essere chiusi. Prima dell'introduzione di SafeHandle, IntPtr veniva utilizzato per contenere gli handle di Win32, ma assicurarsi che fossero stati chiusi correttamente e impedire l'esecuzione di GC era responsabilità del programmatore.

HandleRef è un modo per assicurarsi che un handle non gestito non venga eseguito da GC quando si è nel mezzo di una chiamata P/Invoke. Senza qualcosa come HandleRef, se il codice gestito non fa nulla con l'handle dopo la chiamata P/Invoke, se il GC è stato eseguito durante la chiamata P/Invoke, non si renderebbe conto che l'handle era ancora in uso e potrebbe farlo con GC . Immagino (ma non sono sicuro e non ho guardato) che SafeHandle potrebbe utilizzare HandleRef come parte della gestione dell'handle incapsulato.

+13

Correzione minima. Usa HandleRef quando non vuoi che un oggetto * gestito * GC venga inserito durante PInvoke. , ad esempio classe HWnd {handle IntPtr pubblico; } HWnd a = new HWnd(); B.SendMessage (a.Handle, ...); <- a potrebbe essere GC in PInvoke B.SendMessage (nuovo HandleRef (a, a.Handle)) <- ora non può essere GC in PInvoke –

+3

Un'altra aggiunta: 'SafeHandle' include il conteggio dei riferimenti a evitare di gestire attacchi di riciclaggio. –

+0

Qualcuno può confermare che maneggevolezza utilizza handleref?O almeno ha un meccanismo simile? – Assimilater

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

Assumendo questo è l'unico riferimento "a" nel programma, questo equivale a:

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

Il problema è che quando "a" è disposto, si chiuderà la maniglia. Se ciò accade prima o durante la chiamata a SendMessage, l'handle non sarà valido.

HandleRef impedisce a "a" di essere raccolto prima che il programma abbia terminato h.

1

Sembra SafeHandle non incorporare il comportamento KeepAlive del 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) 
<...> 
*/ 

Ma io non sono sicuro, sembra che il comportamento keepalive può essere acheived solo fornendo falso valore al costruttore che semplicemente contrassegna l'oggetto come non definibile, quindi devi chiamare SafeHandle's Dispose() per evitare perdite di risorse in quel caso, ho ragione? Qualcuno può spiegare il codice sorgente, qual è il

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

?