Win32 API Sendinput в VBA

Обсуждения по программированию для ОС Windows безотносительно используемого языка программирования. Windows NT, Win32, Windows API, ядро и драйверы.
Михаил Орлов
Начинающий
Начинающий
 
Сообщения: 11
Зарегистрирован: 30.09.2021 (Чт) 20:57

Win32 API Sendinput в VBA

Сообщение Михаил Орлов » 13.04.2022 (Ср) 23:25

Приветствую уважаемых гуру и адептов VB.

Есть задача - подвинуть мышь (точнее, её курсор).

После изучения документации на 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 байт.
Но, если это так, то какого... он так делает, и как это отменить?)

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: Win32 API Sendinput в VBA

Сообщение bon818 » 14.04.2022 (Чт) 18:00

Структура должны быть размером в 24 bytes

Код: Выделить всё
Size = 24 bytes
TYPE MOUSEINPUT  ' выравнивание по DWORD
   dx          AS LONG    ' LONG
   dy          AS LONG    ' LONG
   mouseData   AS LONG   ' DWORD
   dwFlags     AS LONG   ' DWORD
   Timetime As LONG  'MOUSEINPUT_TIME_UNION
   dwExtraInfo AS LONG 'DWORD   ' ULONG_PTR
END TYPE

Михаил Орлов
Начинающий
Начинающий
 
Сообщения: 11
Зарегистрирован: 30.09.2021 (Чт) 20:57

Re: Win32 API Sendinput в VBA

Сообщение Михаил Орлов » 14.04.2022 (Чт) 22:09

bon818 писал(а):Структура должны быть размером в 24 bytes

Уверены? Речь о Win32 x64 API.

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: Win32 API Sendinput в VBA

Сообщение bon818 » 15.04.2022 (Пт) 4:20

Был не прав :roll:

В качестве оправдания:
Во время написания этого проста, просматривал - слушал политические новости с ютуба )

Раз десять(не мение) вносил исправления в пост, понимал, что пишу что-то не-то.
В результате, из за невнимания(ютуб, чтоб тебя) и нежелание вникать в тему как следует(и лени), оставил этот пост как есть.

И чтоб не кого не вводить в заблуждение (своим самоуверенным заблуждением), удаляю содержимое этого поста.
Извиняюсь, короче.
Последний раз редактировалось bon818 18.04.2022 (Пн) 13:58, всего редактировалось 2 раз(а).

Михаил Орлов
Начинающий
Начинающий
 
Сообщения: 11
Зарегистрирован: 30.09.2021 (Чт) 20:57

Re: Win32 API Sendinput в VBA

Сообщение Михаил Орлов » 15.04.2022 (Пт) 14:40

1. Даже для Win32 x32 API не 24 байта, а 28.
На вход SendInput передаётся не структура MOUSEINPUT, а структура INPUT, которая длинее на 4 байта (поле DWORD type).
Вы про него сначала забыли, потом исправились.

2. Типы LONG, ULONG_PTR ни разу не фиксировано 32-разрядные, а зависят от разрядности Win32 API (считай-от разрядности приложения).
Long для них не подходит.
Думаете, в Windows Data Types просто так наплодили алиасов для базовых целочисленных типов, что-ли?
https://docs.microsoft.com/en-us/window ... data-types

3. То, что Sendinput в Win32 x64 API ждёт структуру размером в 40 байт, можно считать установленным фактом.
Только при такой длине Sendinput возвращает 1 (нет ошибки).

4. По поводу вашего примера
bon818 писал(а):наверно, только для MOUSEINPUT, хватит и токового:

Разумеется, речь идёт только о MOUSEINPUT. Нет, не хватит. Нужно не только сделать структуру нужного размера (40 байт), но и разместить поля на своих местах (смещениях) внутри неё.
Собственно, как правильно - я и сам ташёл методом тыка, топик не о том "что нужно сделать", а о том, "почему сделанное так сильно расходится с официальной документацией".

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: Win32 API Sendinput в VBA

Сообщение bon818 » 15.04.2022 (Пт) 16:50

Михаил Орлов писал(а):1. Даже для Win32 x32 API не 24 байта, а 28.
Вы про него сначала забыли, потом исправились.

Структура MOUSEINPUT = 24 байта, а TypeInput это общий флаг (+ 4 байта), для MOUSEINPUT, KEYBDINPUT, HARDWAREINPUT

Михаил Орлов писал(а):3. То, что Sendinput в Win32 x64 API ждёт структуру размером в 40 байт, можно считать установленным фактом.

Sendinput ждет полную структуру INPUT такого вида:
Код: Выделить всё
Type INPUT
TypeInput AS DWORD
UNION
mi AS MOUSEINPUT
ki AS KEYBDINPUT
hi AS HARDWAREINPUT
UNION
End Type


Дальше спорить не собираюсь.

Михаил Орлов
Начинающий
Начинающий
 
Сообщения: 11
Зарегистрирован: 30.09.2021 (Чт) 20:57

Re: Win32 API Sendinput в VBA

Сообщение Михаил Орлов » 17.04.2022 (Вс) 19:15

2 bon818: хорошо, к вам больше никаких вопросов нет.

Коллеги, если кто-нибудь читает эту тему - ответьте, пожалуйста, на её верхнее сообщение.

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: Win32 API Sendinput в VBA

Сообщение bon818 » 18.04.2022 (Пн) 17:06

Михаил Орлов писал(а):2 bon818: хорошо, к вам больше никаких вопросов нет.

Был не прав.
Как не крути)), структура INPUT с UNION, это всего лишь (MOUSEINPUT + TypeInput) 28 байта, для х86.

Михаил Орлов писал(а): объяснить несоответствие документации по Win API 32 и практики?

Думаю, если подключить правильные заголовочные файлы(header file), с бесконечными typedef FIX for __WIN64 или #IF WIN64, то и на практике проблем(расхождений) не будет.

А простое решение может быть каким-то таким:
Код: Выделить всё
If SendInput(INPUT, LenInputs = 28) = 0 Then
    SendInput(INPUT, LenInputs = 40)
End If

Михаил Орлов
Начинающий
Начинающий
 
Сообщения: 11
Зарегистрирован: 30.09.2021 (Чт) 20:57

Re: Win32 API Sendinput в VBA

Сообщение Михаил Орлов » 19.04.2022 (Вт) 10:34

Проблема не в том, чтобы написать рабочий код VB под Win32 API x32 / Win32 API x64 / или даже универсальный.
И первое, и второе, и третье уже сделано и работает.

Проблема в том, что написанный рабочий код драмматически расходится с официальной документаией Microsoft по функции Sendinput и её структурам данных.
При этом, функция Sendinput существует, минимум, с 1994 г. (время Win NT), а её 64-разрядная версия - минимум, с 2003 г. (Win XP x64, Win 2003 x64).
То есть, будь это косяк в документации - за 19 лет он, по-любому, должен был быть обнаружен. То есть, скорее всего - это не косяк.
Но тогда объяснить это расхождение не получается. Вот в этом и вопрос.


Вернуться в Windows-программирование

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

    TopList  
cron