[<DllImport("kernel32")>]
extern bool CloseHandle(System.Void* handle);
//System.Void also throws same error
//extern bool CloseHandle(System.Void handle);
gives the error:
'System.Void' can only be used as 'typeof' in F#
but
extern bool CloseHandle(typeof<System.Void> handle);
does not compile. Same error,
"System.Void can only be used as typeof..."
F# void*
does compile
extern bool CloseHandle(void* handle);
but using it in C# throws a design-time convert error
public void CloseBeforeGarbageCollection(IntPtr someAllocIntPtr)
{
//test unmanaged block
var result = CloseHandle(someAllocIntPtr.ToPointer());
return result;
}
'cannot convert from 'void*' to 'System.IntPtr'
though passing the managed IntPtr will compile
//test managed IntPtr
var result = CloseHandle(someAllocIntPtr); //throws error at runtime
but when someAllocIntPtr
is the result of Marshal.AllocHGlobal
, it throws a runtime exception External component has thrown an exception.
.
As I understand it, this happens because someAllocIntPtr
(as the result of Marshal.AllocHGlobal) is technically a managed pointer TO an unmanaged pointer, not the same as a normal IntPtr. This is noted by Peter Ritchie in a reply to his answer here: System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception
The only way to avoid this runtime Exception is to wrap the handle in a SecureHandle()
subclass, but I think that's against the ref-ref\out-out
rule on MSDN: CA1021: Avoid out parameters.
IE, System.Void* realPointer = someAllocIntPtr.ToPointer()
is the ACTUAL pointer (a reference to an unmanaged pointer), or in other words, SecureHandle safeHandle = new SecureHandle(someAllocIntPtr)
is actually "a reference of - another reference of - an actual pointer", and should not be passed with out
or ref
keywords, according to the MSDN article.