2009-02-08 18 views
33

Beni MSDN'ye yönlendirmeden, bunların her birinin amacının ve bunların ne zaman kullanılacağını net ve açık bir şekilde açıklayabilir. (IntPtr, SafeHandle ve HandleRef)IntPtr, SafeHandle ve HandleRef - Açıklaması

+1

MSDN ile ilgili sorun nedir? –

+8

Hiçbir şey. Sadece bunları doğru şekilde kullandığımı garanti etmek için her birinin kısa bir özetini arıyorum. MSDN ve diğer insanların açıklamalarını okursam, yaptığım şeyin doğru olup olmadığını daha iyi hissediyorum. – user62572

cevap

46

IntPtr yalnızca bir işaretçi (örneğin, 32-bit sistemler, 64 bit sistemlerde 64 bit boyutunda 32 bit boyutu) tutabilen basit bir tamsayı tabanlı bir yapıdır.

SafeHandle, Win32 nesne tanıtıcılarını tutmayı amaçlayan bir sınıftır; nesne, nesne GC'ed olduğunda tanıtıcının kapalı olduğundan emin olan bir sonlandırıcıya sahiptir. SafeHandle, soyut bir sınıftır çünkü farklı Win32 tanıtıcıları kapatılmaları gereken farklı yollara sahiptir. SafeHandle'un kullanılmasından önce, IntPtr, Win32 tutamaçlarını tutmak için kullanıldı, ancak bunların düzgün bir şekilde kapatılmasının ve GC'ed olmasının engellenmesi programcının sorumluluğundaydı. Bir P/Invoke çağrısının ortasında olduğunuzda yönetilmeyen bir tanıtıcının GC'ed olmadığından emin olmanın bir yoludur.

HandleRef. HandleRef gibi bir şey olmadan, yönetilen kodunuz P/Invoke çağrısından sonra tutamaçla bir şey yapmazsa, GC P/Invoke çağrısı sırasında çalıştırılmışsa, tanıtıcının hala kullanımda olduğunu ve GC'nin . SafeHandle'un kapsüllenmiş tutamacın yönetiminin bir parçası olarak HandleRef'u kullanabileceğini (ancak emin değilim ve bakmadım) hayal edin. Sorun, "a" olarak bulunduğu bir durumda, bu tutamak yakın olmasıdır

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

Bu varsayarsak

+13

Küçük düzeltme. PInvoke sırasında * yönetilen * nesnesi GC'ed istemediğinizde HandleRef'i kullanın. e.g sınıfı HWnd {public IntPtr Handle; HWnd a = yeni HWnd(); B.SendMessage (a.Handle, ...); <- Bir PInvoke 'da GC'ed olabilir. B.SendMessage (yeni HandleRef (a, a.Handle)) <- şimdi PInvoke –

+3

'da GC'ed olamaz. Başka bir ek: 'SafeHandle' referans sayımını içerir geri dönüşüm saldırılarını engeller. –

+0

Güvenli kullanımın güvenlik görevlisi olduğunu doğrulayan var mı?Ya da en azından benzer bir mekanizma var mı? – Assimilater

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

"a" programında, bu eşdeğerdir, sadece bir referanstır. Bu, SendMessage çağrısından önce veya sırasında gerçekleşirse, tutamaç geçersiz olur.

HandleRef, program bitmeden önce "a" nın çöp toplanmasını önler.

1

O HandleRef en KeepAlive davranışını dahil yok SafeHandle benziyor: 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) 
<...> 
*/ 

Ama emin değilim, sadece kurucusuna sahte değer sağlanarak başarılmıştır edilebilir canlı tutma davranışı benziyor hangi basitçe nesneyi kesinleştirilemez olarak işaretler, bu durumda kaynak sızıntısını önlemek için SafeHandle's Dispose() öğesini manüel olarak çağırmanız gerekir, doğru muyum? birisi kaynak kodu açıklayabilir,

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

nedir?