Есть задача - подвинуть мышь (точнее, её курсор).
После изучения документации на Win32 API SendInput:
https://docs.microsoft.com/en-us/window ... -sendinput
https://docs.microsoft.com/en-us/window ... user-input
https://docs.microsoft.com/en-us/window ... mouseinput
был написан такой код:
- Код: Выделить всё
Option Explicit
' constants & types for function SendInput (from winuser.h)
Const INPUT_MOUSE As Long = 0&
Const INPUT_KEYBOARD As Long = 1&
Const INPUT_HARDWARE As Long = 2&
Const MOUSEEVENTF_MOVE As Long = &H1&
Private Type MOUSEINPUT
TypeInput As Long
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
Timetime As Long
dwExtraInfo As Long
End Type
Private Declare Function SendInput Lib "User32" (ByVal cInputs As Long, ByRef pInputs As MOUSEINPUT, ByVal cbSize As Long) As Long
Sub MouseMove()
Dim nResult As Long, LenInputs As Long
Dim Inputs As MOUSEINPUT
LenInputs = Len(Inputs)
With Inputs
.TypeInput = INPUT_MOUSE
.dx = 100& ' пусть будет 100
.dy = 50& ' пусть будет 50
.mouseData = 0&
.dwFlags = MOUSEEVENTF_MOVE
End With
nResult = SendInput(1&, Inputs, LenInputs)
End Sub
Этот код прекрасно работает в 32-разрядном VBA.
Для 64-разрядного VBA код, естественно, нужно адаптировать, и тут начались странности.
Но обо всём по порядку.
1. Методом тыка было выяснено, что SendInput ждёт структуру длиной 40 байт, против 28 байт для 32-разрядного VBA.
(SendInput возвращает 1 только при длине 40, при других длинах в диапазоне 28 - 56 возвращает 0)
Значит, поменять тип Long на LongLong должны 3 поля структуры.
2. После изучения документации на Windows Data Types https://docs.microsoft.com/en-us/window ... data-types
создаётся впечатление, что эти 3 64-разрядных поля: LONG dx, LONG dy, ULONG_PTR dwExtraInfo, то есть структура (тип) MOUSEINPUT должен иметь вид:
- Код: Выделить всё
Private Type MOUSEINPUT
TypeInput As Long
dx As LongLong
dy As LongLong
mouseData As Long
dwFlags As Long
Timetime As Long
dwExtraInfo As LongLong
End Type
3. Методом тыка было выяснено, что код работает с такой структурой:
- Код: Выделить всё
Private Type MOUSEINPUT
TypeInput As LongLong
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
Timetime As LongLong
dwExtraInfo As LongLong
End Type
4. Также методом тыка было выяснено, что код с такой структурой не работает:
- Код: Выделить всё
Private Type MOUSEINPUT
TypeInput As LongLong
dx As Long
dy As Long
mouseData As Long
dwFlags As LongLong
Timetime As Long
dwExtraInfo As LongLong
End Type
первый байт по адресу dwFlags - 01h, и дальше 00h до конца структуры.
(для удобства приведу код для 64-разрядного VBA целиком)
- Код: Выделить всё
Option Explicit
' constants & types for function SendInput (from winuser.h)
Const INPUT_MOUSE As Long = 0&
Const INPUT_KEYBOARD As Long = 1&
Const INPUT_HARDWARE As Long = 2&
Const MOUSEEVENTF_MOVE As Long = &H1&
Private Type MOUSEINPUT
TypeInput As LongPtr
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
Timetime As LongPtr
dwExtraInfo As LongPtr
End Type
Private Declare PtrSafe Function SendInput Lib "User32" (ByVal cInputs As LongPtr, ByRef pInputs As MOUSEINPUT, ByVal cbSize As LongPtr) As LongPtr
Sub MouseMove()
Dim nResult As LongPtr, LenInputs As LongPtr
Dim Inputs As MOUSEINPUT
LenInputs = Len(Inputs)
With Inputs
.TypeInput = INPUT_MOUSE
.dx = 100& ' пусть будет 100
.dy = 50& ' пусть будет 50
.mouseData = 0&
.dwFlags = MOUSEEVENTF_MOVE
End With
nResult = SendInput(1&, Inputs, LenInputs)
End Sub
Если вы дочитали до этого места, буду рад, если поможете ответить на вопросы:
1. Как с научной точки зрения объяснить несоответствие документации по Win API 32 и практики?
2. Почему структуры в пунктах 3 и 4 вызывают разное поведение?
(Есть обоснованное предположение, что когда поле dwFlags имеет тип LongLong, VB выравнивает его на границу 8 байт.
Но, если это так, то какого... он так делает, и как это отменить?)