I'm porting a small application I wrote for keybindings to .net core and I've run across an instance where the same code behaves differently. I'm calling the SendInput function in F# with this declaration

open System.Runtime.InteropServices [<StructLayout(LayoutKind.Sequential)>] type private MOUSEINPUT = struct val dx: int32 val dy:int32 val mouseData:uint32 val dwFlags: uint32 val time: uint32 val dwExtraInfo: int new(_dx, _dy, _mouseData, _dwFlags, _time, _dwExtraInfo) = {dx=_dx; dy=_dy; mouseData=_mouseData; dwFlags=_dwFlags; time=_time; dwExtraInfo=_dwExtraInfo} end [<StructLayout(LayoutKind.Sequential)>] type private KEYBDINPUT = struct val wVk: uint16 val wScan: uint16 val dwFlags: uint32 val time: uint32 val dwExtraInfo:int new(_wVk, _wScan, _dwFlags, _time, _dwExtraInfo) = {wVk =_wVk; wScan = _wScan; dwFlags = _dwFlags; time = _time; dwExtraInfo = _dwExtraInfo} end [<StructLayout(LayoutKind.Sequential)>] type private HARDWAREINPUT = struct val uMsg: uint32 val wParamL: uint16 val wParamH: uint16 new(_uMsg, _wParamL, _wParamH) = {uMsg = _uMsg; wParamL = _wParamL; wParamH = _wParamH} end [<StructLayout(LayoutKind.Explicit)>] type private LPINPUT = struct [<FieldOffset(0)>] val mutable ``type``:int // 1 is keyboard [<FieldOffset(4)>] val mutable mi : MOUSEINPUT [<FieldOffset(4)>] val mutable ki : KEYBDINPUT [<FieldOffset(4)>] val mutable hi : HARDWAREINPUT end module private NativeMethods = [<DllImport("user32.dll", SetLastError=true)>] extern uint32 SendInput(uint32 nInputs, LPINPUT* pInputs, int cbSize) let appSignature = 0xA8969 let private createPressInput (code: int) = let mutable input = LPINPUT() input.``type`` <- InputModes.INPUT_KEYBOARD input.ki <- KEYBDINPUT(uint16 code, uint16 0, Dwords.KEYEVENTF_KEYDOWN, uint32 0, appSignature) input let pressKey (code: int) = let input = createPressInput code NativeMethods.SendInput(uint32 1, &&input, Marshal.SizeOf(input)) |> ignore

The same code works in a .net framework application that I created in visual studio. Now, the output of Marshal.GetLastWin32ErrorCode() is 87 which apparently means ERROR_INVALID_PARAMETER -- not very helpful. I'm new to .net and F# so I'm not sure what could be different in this context. I admit, even getting this binding code was mostly trial and error as well.

I'd appreciate any info that could help me debug this.

UPDATE: I have a workaround that I'm not satisfied with. I can't explain why this works just yet -- I need to read more about how marshaling works. With this, the Marshal.GetLastWin32ErrorCode() is 5 , access denied. It still send the key so I'm not sure what that error is supposed to mean. That said, here it is. Splitting out the union from the struct that I was using into a dedicated union type, making that union type LayoutKind.Explicit , and making at least one of the fields FieldOffset(1) (but not the field I care about) gets key presses working. Other combinations of field offsets result in something that works but doesn't actually press keys, which I assume means that its marshaled in a way that results in no visible key presses.