.NET Framewrok 2.0 introduced us to SafeHandle. SafeHandle is an abstract wrapper for operating system handles (IntPtr). It helps the developer to make sure the handle is released when it is no longer in use (when the object is being GC).
Since I use PInvoke frequently, I found the following class very helpfull while working with Win32 handles.
namespace Samuelson.Win32
{
public sealed class SafeWin32Handle : SafeHandleZeroOrMinusOneIsInvalid
{
/// <summary>
/// Ctor.
/// </summary>
private SafeWin32Handle(): base(true){}
protected override bool ReleaseHandle()
{
try
{
return CloseHandle(handle);
}
finally {}
return false;
}
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hObject);
}
}
Let us go back to the begining. Take for example the OpenProcess and CloseHandle method :
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);
A simple usage will look like this:
public void Main(string[] args)
{
Process p = Process.GetProcesses()[0];
IntPtr pHandle = OpenProcess(p.Handle, PROCESS_VM_READ, p.Id);
try
{
// work with the pHandle
}
finally
{
CloseHandle(pHandle);
}
}
The problem here is that each call to OpenProcess should be handle very carefully by the developers. It can easily be used wrong and create memory leaks.
Using SafeWin32Handle solves this problem and makes the use of OpenProcess safe:
[DllImport("kernel32.dll")]
public static extern SafeWin32Handle OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
Notice now that the return value is SafeWin32Handle and not IntPtr. This is exactly what SafeHandle is all about.
The usage with SafeWin32Handle looks as follows:
public void Main(string[] args)
{
Process p = Process.GetProcesses()[0];
SafeWin32IntPtr pHandle = OpenProcess(p.Handle, PROCESS_VM_READ, p.Id);
// work with the pHandle
}
If you have a good eye, you would have noticed that it is impossible to create an instance of SafeWin32Handle because of two reasons:
- SafeWin32Handle has a private constructor.
- SafeWin32Handle is marked as sealed.
So my quiz for this time is:
How is it possible for OpenProcess to return an (not null) instance of SafeWin32Handle?
Happy Passover to everyone!