Я портирую небольшое приложение, которое я написал для привязки клавиш, на net ядро, и я столкнулся с экземпляром, где тот же код ведет себя по-разному. Я вызываю SendInput функцию в F # с этим объявлением
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
Тот же код работает в приложении. net Framework, которое я создал в Visual Studio. Теперь вывод Marshal.GetLastWin32ErrorCode()
равен 87
, что, очевидно, означает ERROR_INVALID_PARAMETER
- не очень полезно. Я новичок в. net и F #, поэтому я не уверен, что может быть иначе в этом контексте. Я признаю, что даже получение этого связующего кода было в основном методом проб и ошибок.
Буду признателен за любую информацию, которая может помочь мне отладить это.
ОБНОВЛЕНИЕ : I есть обходной путь, который меня не устраивает. Я пока не могу объяснить, почему это работает - мне нужно больше узнать о том, как работает маршалинг. При этом Marshal.GetLastWin32ErrorCode()
равен 5
, доступ запрещен. Он все еще посылает ключ, поэтому я не уверен, что эта ошибка должна означать. Тем не менее, вот оно. Разделение объединения из структуры, которую я использовал, в выделенный тип объединения, создание этого типа объединения LayoutKind.Explicit
и создание хотя бы одного из полей FieldOffset(1)
(но не поля, которое мне небезразлично) приводит к срабатыванию нажатий клавиш. Другие комбинации смещений полей приводят к тому, что что-то работает, но фактически не нажимает клавиши, что, как я предполагаю, означает, что его маршалинг происходит так, что не происходит видимых нажатий клавиш.
[<StructLayout(LayoutKind.Explicit)>]
type private InputUnion = struct
[<FieldOffset(0)>]
val mutable ki : KEYBDINPUT
[<FieldOffset(1)>]
val mutable mi : MOUSEINPUT
[<FieldOffset(1)>]
val mutable hi : HARDWAREINPUT
end
[<StructLayout(LayoutKind.Sequential)>]
type private LPINPUT = struct
val ``type``:int // 1 is keyboard
val u: InputUnion
new(_type, _u) = {``type`` = _type; u = _u}
end