2012-08-15 20 views
13

Przeszukałem internet daleko, ale nie znalazłem dobrego wyjaśnienia.Czy mogę używać SafeHandle zamiast IntPtr?

Moje pytanie jest dość proste.

Mam DLL, który ma funkcję o nazwie Initialize, a jednym z parametrów jest wskaźnik, który otrzyma uchwyt, który będzie używany z kolejnymi połączeniami. Kolejnym parametrem jest ciąg znaków, który opiszę pod kątem kompletności. Podpis używam jest (w prostej formie):

[DllImport(MyDll)] 
static extern bool Initialize([In] string name, out IntPtr handle); 

podpis w samej DLL jest zapisana jako: Initialize(LPTSTR name, HANDLE handle) z komentarzem „Rękojeść: wskaźnik do lokalizacji, która otrzyma uchwyt”.

i późniejsze rozmowy są w formie

[DllImport(MyDll)] 
static extern bool DoSomething(IntPtr handle, uint randomParameter); 

Czytałem o SafeHandle i zastanawiałem się, czy mogę użyć go do substite dla mojego uchwytu IntPtr. A jeśli mogę, jak mam to zrobić? Rozszerzenie abstrakcyjnej klasy SafeHandle nie jest problemem, ale czy mogę bezpośrednio zastąpić moją IntPtr dla SafeHandle (i użyć domyślnego systemu Marshalling), czy też muszę zrobić coś ekstra?

+0

Jakie korzyści ma 'SafeHandle' dać wam, że tylko przechowywanie w' IntPtr' nie? –

+4

@ScottChamberlain - 'SafeHandle' jest' IDisposable' i zapewnia, że ​​zasoby przywoływane przez uchwyt są wypuszczane.'IntPtr' to po prostu wartość wielkości wskaźnika, którą można przekazać - nie ma żadnej semantyki związanej z usuwaniem. – LBushkin

+0

Zakładając, że możesz pobierać opłaty za pamięć, chyba że możesz zwolnić pamięć wskaźnika za pomocą 'Marshal.FreeBSTR',' Marshal.FreeCoTaskMem' lub 'Marshal.FreeHGlobal', nie sądzę, że możesz bezpiecznie -dokonuj pamięć z C#. Używając 'IntPtr', C# nie spróbuje automatycznie zwolnić pamięci. – Pooven

Odpowiedz

10

można znaleźć pełniejszą odpowiedź na temat różnicy między SafeHandle i IntPtr tutaj: IntPtr, SafeHandle and HandleRef - Explained

Jednak, aby podsumować, IntPtr powinny być stosowane tam, gdzie argument jest rzeczywiście wskaźnik maszynowego rozmiar - SafeHandle powinny być używane tam, gdzie argument jest w rzeczywistości uchwytem Win32. Te typy nie są na ogół zamienne; rozmiar IntPtr będzie się różnić w zależności od architektury (32 bity na x86 i 64 bity na x64 i amd64). UWAGA: Pod okładkami uważam, że SafeHandle używa również IntPtr).

Również w przeciwieństwie do IntPtr, SafeHandle faktycznie wykonuje usuwanie zasobów, gdy typ jest zbierany śmieci. Gwarantuje to, że zasoby systemowe nie wyciekają w czasie działania programu (mimo że powinieneś Dispose() z SafeHandle wystąpień wcześniej, gdy to możliwe). Zauważ, że SafeHandle jest rzeczywiście abstrakcyjna, ponieważ istnieje wiele różnych rodzajów uchwytów, które wymagają różnych podejść do prawidłowego usuwania i obsługi.

W konkretnym przypadku należy zapoznać się z dokumentacją biblioteki DLL, do której dzwonimy. Jeśli jest to DLL Win32, może już istnieć typ SafeHandle. Jeśli jest to trzecia strona DLL, możesz przetoczyć własną implementację SafeHandle - zakładając, że oprócz wersji Initialize() istnieje wersja Release() (lub odpowiednik).

kilka dodatkowych interesujących ciekawostek o IntPtr vs SafeHandle można znaleźć na stronie:

Use SafeHandle to encapsulate native resources

SafeHandle Class Reference

SafeHandles and Critical Finalization

+0

Z pewnością 'IntPtr' ma 64 bity, a nie 65? Zrobiłem edycję - proszę, odwróćcie i wyjaśnijcie więcej (jestem przygotowany na to, bym był moim "uczyć się czegoś nowego każdego dnia") – sblom

+0

Cóż, tworzenie własnych implantów SafeHandle, jak powiedziałem, to nic wielkiego, jest wiele przykładów Chciałbym wiedzieć, czy mogę używać SafeHandle i IntPtr zamiennie, a więc mogę to zrobić: 'static extern bool Initialize ([In] nazwa string, out SafeHandle)' zamiast bieżącego 'static extern bool Initialize ([In] nazwa string, out IntPtr) '? – Davio

+0

@sblom: Nie, to był po prostu literówka z mojej strony, dziękuję za złapanie tego – LBushkin