Is there any compatible with C # and VB System.Void * in F #? (To close a pointer to an unmanaged Alloc?)
[<DllImport("kernel32")>] extern bool CloseHandle(System.Void* handle); //System.Void also throws same error //extern bool CloseHandle(System.Void handle); gives an error:
'System.Void' can only be used as 'typeof' in F #
but
extern bool CloseHandle(typeof<System.Void> handle); not compiled. Same mistake
"System.Void can only be used as typeof ..."
F # void* compiles
extern bool CloseHandle(void* handle); but using it in C # causes a development-time conversion error
public void CloseBeforeGarbageCollection(IntPtr someAllocIntPtr) { //test unmanaged block var result = CloseHandle(someAllocIntPtr.ToPointer()); return result; } 'cannot convert from' void * 'to' System.IntPtr '
although a managed intptr transfer will compile
//test managed IntPtr var result = CloseHandle(someAllocIntPtr); //throws error at runtime but when someAllocIntPtr is the result of Marshal.AllocHGlobal , it throws an exception at runtime External component has thrown an exception. . As I understand it, this is because someAllocIntPtr (as a result of Marshal.AllocHGlobal) is a technically managed pointer to an unmanaged pointer, not a normal IntPtr. Peter Ritchie noticed this in response to his answer here: System.Runtime.InteropServices.SEHException (0x80004005): An external component threw an exception
The only way to avoid this Exception Exception is to wrap the handle in a subclass of SecureHandle() , but I think it's against the ref-ref\out-out rule in MSDN: CA1021: Avoid parameters . IE, System.Void* realPointer = someAllocIntPtr.ToPointer() is an ACTUAL pointer (a reference to an unmanaged pointer), or, in other words, SecureHandle safeHandle = new SecureHandle(someAllocIntPtr) is actually a " other link - actual pointer" link and not must be transmitted with the keywords out or ref in accordance with the MSDN article.
I did a little test as follows:
In the f # assembly (dll library), I have the following module:
module MyWin32 open System open System.Runtime.InteropServices [<DllImport("kernel32")>] extern bool CloseHandle(IntPtr handle); [<DllImport("kernel32")>] extern IntPtr CreateToolhelp32Snapshot(IntPtr flag, IntPtr procId); In the F # console program, which has a link to the aforementioned lib, I:
open System open System.Runtime.InteropServices open MyWin32 [<EntryPoint>] let main argv = let handle = CreateToolhelp32Snapshot(IntPtr(4), IntPtr(System.Diagnostics.Process.GetCurrentProcess().Id)) printfn "%A" handle printfn "%b" (CloseHandle handle) // A HGlobal should always be released by FreeHGlobal let intPtr = Marshal.AllocHGlobal(1024) Marshal.FreeHGlobal(intPtr) And in the C # console program that references the lib above, I:
using System; namespace CSTest { class Program { static void Main(string[] args) { var handle = MyWin32.CreateToolhelp32Snapshot(new IntPtr(4), new IntPtr(System.Diagnostics.Process.GetCurrentProcess().Id)); Console.WriteLine(handle); Console.WriteLine(MyWin32.CloseHandle(handle)); Console.ReadLine(); } } } Both tests F # and C # are compiled and executed as completed. Hope this helps you.
About void *:
The F # MyWin32 assembly change shown above using IntPtr to void * substitution still works for F # and C # clients without any other modifications (the C # metadata code for MyWin32 replaces void * with IntPtr):
module MyWin32 open System open System.Runtime.InteropServices [<DllImport("kernel32")>] extern bool CloseHandle(void* handle); [<DllImport("kernel32")>] extern void* CreateToolhelp32Snapshot(IntPtr flag, IntPtr procId); So, the conclusion of the above small tests is that you can use void * in F # as a valid substitution for IntPtr.
I think that you need to use IntPtr.ToPointer () in the insecure section {} in C #, since pointers only make sense in insecure mode in C #.