I have been reading some material online such as:
So the pattern to use in P/Invoke is such as:
// inherits from SafeHandleZeroOrMinusOneIsInvalid, so IsInvalid is already implemented.
internal sealed class MySafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// A default constructor is required for P/Invoke to instantiate the class
public MySafeHandle()
: base(ownsHandle: true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(handle);
}
}
internal static class NativeMethods
{
// Returns the SafeHandle instead of IntPtr
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
internal extern static MySafeHandle CreateFile(String fileName, int dwDesiredAccess, System.IO.FileShare dwShareMode, IntPtr securityAttrs_MustBeZero, System.IO.FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr TemplateFile_MustBeZero);
// Take a SafeHandle in parameter instead of IntPtr
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(MySafeHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
[DllImport("kernel32", SetLastError = true)]
internal extern static bool CloseHandle(IntPtr handle);
}
Well not quite... If I understand properly the correct pattern would be more like this instead:
internal static class NativeMethods
{
[...] CreateFile / CloseHandle unchnaged [...]
// Take a SafeHandle in parameter instead of IntPtr
[DllImport("kernel32", SetLastError = true)]
private extern static int ReadFile(MySafeHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
internal static int ReadFileSafe(MySafeHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero) {
if(handle.IsInvalid) throw new Exception("Invalid handle");
return ReadFile(handle, bytes, numBytesToRead, numBytesRead, overlapped_MustBeZero);
}
}
Did I understand the scope of SafeHandle properly ? In that case, is there any mechanism to avoid this boilerplate code ?
So indeed
SafeHandlesimply expose the state of the internal handle. Therefore, one can keep API simple using:But implement the checking of state as:
This is also documented in one of the example of the documentation online: