2

I am trying to call EnumWindows from F# and got following exception:

System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'parameter #1': Generic types cannot be marshaled.

Code I used:

module Win32 =
    open System
    open System.Runtime.InteropServices
    type EnumWindowsProc = delegate of (IntPtr * IntPtr) -> bool
    [<DllImport("user32.dll")>]
    extern bool EnumWindows(EnumWindowsProc callback, IntPtr lParam)

    let EnumTopWindows() =
        let callback = new EnumWindowsProc(fun (hwnd, lparam) -> true)
        EnumWindows(callback, IntPtr.Zero)

module Test = 
    printfn "%A" (Win32.EnumTopWindows())
wangzq
  • 896
  • 8
  • 17
  • 1
    How is this a duplicate of the question referenced as "same"? If I am looking for "How to use EnumWindows with F# this is where I would end up. There is no way that I would end up on the other question.. – Jukka Puranen Jul 07 '16 at 09:55

1 Answers1

5

This is a bit subtle, but when you use parentheses in the delegate definition, you are explicitly telling the compiler to create a delegate taking tuple - and then the interop fails because it cannot handle tuples. Without parentheses, the delegate is created as ordinary .NET delegate with two parameters:

type EnumWindowsProc = delegate of IntPtr * IntPtr -> bool

Then you also have to change how you use it (because it is now treated as two-parameter function):

let EnumTopWindows() =
    let callback = new EnumWindowsProc(fun hwnd lparam -> true)
    EnumWindows(callback, IntPtr.Zero)
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553