epicTurkey epicTurkey - 1 year ago 68
Vb.net Question

Is there a C# & VB compatible System.Void* in F#? (To close a pointer to nonmanaged Alloc?)

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#


extern bool CloseHandle(typeof<System.Void> handle);

does not compile. Same error,

"System.Void can only be used as typeof..."

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 throws a runtime exception
External component has thrown an exception.
unless its wrapped in a
subclass, but it doesn't seem to reliably close the handles.

As I understand it, this happends because
is a
resulting from a call to
, so
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

This means that
System.Void* realPointer = someAllocIntPtr.ToPointer()
is the ACTUAL pointer, which would break the
rule on MSDN: http://msdn.microsoft.com/en-us/library/ms182131.aspx

Finally, meaning that a
SecureHandle safeHandle = new SecureHandle(someAllocIntPtr)
is actually a reference of a reference of a pointer, and should not be passed with

Answer Source

I have done a little test in the following way:

In an f# assembly (dll library) I have the following module:

module MyWin32
open System
open System.Runtime.InteropServices

extern bool CloseHandle(IntPtr handle);

extern IntPtr CreateToolhelp32Snapshot(IntPtr flag, IntPtr procId);

In an F# Console Program that has a reference to the above lib I have:

open System
open System.Runtime.InteropServices
open MyWin32

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)

And in a C# Console program that references the above lib I have:

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));


Both the F# and C# test compiles and runs as expeceted. I hope this will help you.

About void*:

Changing f# assembly MyWin32 shown above to the following with substution of IntPtr to void* still works for the F# and C# client without any other modfications (The C# metadata code of MyWin32 substitutes void* with IntPtr):

module MyWin32
open System
open System.Runtime.InteropServices

extern bool CloseHandle(void* handle);

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 one should only use IntPtr.ToPointer() in an unsafe {} section in C#, as pointers only make sense in unsafe mode in C#.