You should use the SafeHandle derivative whenever possible, where managed code gets IntPtr from unmanaged code. Although the name, general use, and even documentation of the SafeHandle class implies that it should only be used to store Windows operating system descriptors, several internal .NET Framework classes such as Microsoft.Win32.SafeHandles.SafeLocalAllocHandle and those made from the public abstract System class .Runtime.InteropServices.SafeBuffer also use it to guarantee the release of other unmanaged resources, such as dynamically allocated structures and arrays. In general, I believe that it is good practice to create a derivative of this class whenever IntPtr returns to managed code from unmanaged code, even if it does not require cleaning.
The established goal of SafeHandle is to ensure that even if the world ends (for example, an AppDomain is unloaded or a StackOverflowException event is raised), the .NET platform must be absolutely sure that the finalizer for SafeHandle is called to close or free the unmanaged object referenced by the wrapped IntPtr. The SafeHandle class achieves this by inheriting from the CriticalFinalizerObject class. However, inheriting from this class, however, imposes an obligation on the heir not to completely depend on the state of the process when the finalizer is called, which is most likely not often used for entities other than Windows operating system descriptors. The .NET platform also provides some weak finalization orders, so itβs safe to interact with the SafeHandle object in the finalizer of any class that does not inherit from CriticalFinalizerObject, but the circumstances in which this is necessary should be small and far from each other.
Ideally, the SafeHandle class should also be used to more securely interact with an unmanaged object reference, by encapsulating the expected functionality in a derived class. A well-written class that inherits from SafeHandle should have a specific purpose and should provide methods sufficient so that any developer using it for this purpose never needs to interact directly with the IntPtr contained in it. Adding such methods also provides other developers with a clear idea that the result of an unmanaged method call should be used in a controlled context. A class that inherits from SafeHandle can be used to do this, even if the pointer that the unmanaged method returns does not need to be cleared by calling base (false) in the constructor for the class.
The following are two examples that use classes that are manufactured by SafeHandle to safely clear a reference to an unmanaged object and encapsulate the functionality associated with an unmanaged object. The first example is a more conventional scenario in which the user token returned LogonUser wrapped SafeTokenHandle instance class. This class will call CloseHandle on the token when the object is deleted or completed. It also includes the GetWindowsIdentity method, which returns a WindowsIdentity object for the user represented by the user token. The second example uses the built-in Windows CommandLineToArgvW function to parse the command line. This function returns a pointer to an array containing a contiguous block of memory that can be freed with a single call to LocalFree. The SafeLocalAllocWStrArray class (which inherits from the SafeLocalAllocArray class, which is also defined in this example) will call LocalFree in the array when the object is deleted or finalized. It also includes a function that copies the contents of an unmanaged array into a managed array.
static class Examples { static void Example1_SafeUserToken() { const string user = "SomeLocalUser"; const string domain = null; const string password = "ExamplePassword"; NativeMethods.SafeTokenHandle userToken; WindowsIdentity identity; NativeMethods.LogonUser(user, domain, password, NativeMethods.LogonType.LOGON32_LOGON_INTERACTIVE, NativeMethods.LogonProvider.LOGON32_PROVIDER_DEFAULT, out userToken); using (userToken) {
Mike ness
source share