PostMessage() для эмуляции ввода в С++?

Я пытаюсь сделать простую программу для ботов для игры. Я хочу, чтобы это работало, даже когда игра не в фокусе или свернута. Из-за этого я не могу использовать SendInput(), так как он имитирует глобальные события. Я понял, что для того, чтобы это работало, я должен использовать функцию PostMessage(). Я сделал тестовую программу, имитирующую ввод в Блокноте:

#include <Windows.h>
HWND handle = FindWindow(NULL,CStringW("Untitled - Notepad"));
HWND edit = FindWindowEx(handle, NULL, CStringW("Edit"), NULL);
PostMessage(edit, WM_CHAR, 'a', 0 );

Этот пример успешно имитирует щелчок «a» в блокноте, даже если блокнот не в фокусе или свернут. Точно так же я заставил работать события мыши.

Однако, когда я пытаюсь сделать то же самое для своей игры, я не могу опубликовать команды щелчка. После расследования я обнаружил, что исходный дескриптор получен, но при вызове FindWindowEx() разрешение отказано, и дескриптор не возвращается.

Есть ли способ получить доступ «редактировать» к другому процессу, если он блокирует эту функцию?


person Reed B    schedule 07.11.2012    source источник
comment
Что вы получите, если вызовете GetLastError после вызова FindWindowEx?   -  person anthonyvd    schedule 08.11.2012
comment
Кроме того, если в окне вашей игры нет подокна с именем «Редактировать», оно вернет значение null. вы должны использовать PostMessage для дескриптора, полученного при вызове FindWindow, чтобы найти дескриптор окна вашей игры.   -  person anthonyvd    schedule 08.11.2012
comment
Пожалуйста, отредактируйте свой вопрос. Похоже, вы пытаетесь получить дескриптор окна, которого нет в вашем приложении.   -  person Sebastian Cabot    schedule 10.11.2012


Ответы (2)


Конечно, Windows никогда не позволит вам сделать это, что, если вы попытаетесь украсть пароль пользователя?? вам не разрешено получать входные данные, пока у вас нет фокуса!!

Но вы можете сделать некоторые трюки здесь: вы должны написать функцию-ловушку для мыши или клавиатуры, и эта функция должна быть реализована в DLL (а не в вашем EXE), используйте SetWindowsHookEx, чтобы установить его, а затем использовать механизм IPC в вашей библиотеке DLL для отправки сообщений мыши и/или клавиатуры в ваш основной EXE-файл.

Но помимо этого: пока обычно работает линия

HWND handle = FindWindow(NULL,CStringW("Untitled - Notepad"));

Враги не имеют никакого смысла, окна должны иметь версии большинства функций, которые получают хотя бы один строковый аргумент: один для ANSI, имя которого оканчивается на A, и одно для широких (UTF-16) символов, которые заканчиваются на W. У MSVC есть дополнительный уровень поверх этого дизайна, называемый TCHAR, и с помощью определения сопоставьте все такие функции либо с ANSI, либо с широким, поэтому, если вы используете эту версию API, нецелесообразно напрямую использовать CStringW для создания широких строк. И поскольку Windows API работает с char* и wchar_t*, почему вы конвертируете свой строковый литерал в CString, а затем передаете его функции? вы должны использовать один из них:

// This also work with CStringA
HWND handleA = FindWindowA(NULL, "Untitled - Notepad");
// This also work with CStringW
HWND handleW = FindWindowW(NULL, L"Untitled - Notepad");
// This also work with CString
HWND handleT = FindWindow(NULL, _T("Untitled - Notepad") );
person BigBoss    schedule 08.11.2012
comment
Конечно, Windows никогда не позволит вам сделать это, что, если вы попытаетесь украсть пароль пользователя?? вам не разрешено получать входные данные, пока у вас нет фокуса!! Это не часть вопроса, но да, GetAsyncKeyState() позволяет программе отслеживать клавиатуру, даже если она не находится в фокусе. Фрагмент кода, который я предоставил, позволяет вводить данные в Блокнот, когда Блокнот и/или программа не в фокусе. У вас есть пример того, как подключить Блокнот так, как вы предложили, для имитации ввода? - person Reed B; 08.11.2012
comment
@ReedB Вы невнимательно прочитали мой пример, обратите внимание, что L, L в начале литерала делает его широким строковым литералом, а также, поскольку вы не используете версию TCHAR, вы должны использовать _T (), и это определенно работает! - person BigBoss; 08.11.2012
comment
А, понятно, спасибо. Я никогда раньше не вводил DLL. Есть ли у вас какие-либо советы, если я решу попробовать это? - person Reed B; 08.11.2012
comment
См. документацию SetWindowsHookEx, и вы получите ее, там также есть дюжина образцов - person BigBoss; 08.11.2012
comment
Спасибо. Нет ли способа просто получить разрешение на редактирование? Как я уже сказал, я заставил это работать в блокноте, но это не сработает в моей игре. Что-то связанное с токенами? msdn.microsoft.com/en-us/library/aa379295 (VS.85).aspx - person Reed B; 08.11.2012
comment
что ты хочешь делать? если вы хотите опубликовать сообщение в окне, это просто, используйте PostMessage метод, который я описываю, заключается в получении ввода из фона. - person BigBoss; 08.11.2012
comment
ой. Я заинтересован в использовании PostMessage. Дескриптор, который вы предоставляете postmessage, должен иметь возможности редактирования, как в моем примере. Когда я пытаюсь запросить возможности редактирования с помощью FindWindowEx(handle, NULL, CStringW(Edit), NULL);, при попытке сделать это в игре возвращается NULL (это отлично работает для блокнота). Это источник ошибки и причина поста. - person Reed B; 08.11.2012
comment
Вы не получаете дескриптор с возможностями edit, вы ищете окно, класс которого называется EDIT. в вашей программе такого класса нет. Прочтите документацию по FindWindow и FindWindowEx в MSDN - person BigBoss; 08.11.2012
comment
Спасибо за помощь! Есть ли способ по-прежнему использовать PostMessage() для того, что я пытаюсь сделать, о чем вы можете подумать? - person Reed B; 08.11.2012
comment
Внутри исходного объекта дескриптора для моей игры нет дополнительных окон; однако отправка сообщения объекту дескриптора фактически не нажимает кнопку в игре. Как вы думаете, это связано с тем, что игра использует DirectX и, следовательно, использует directInput? - person Reed B; 08.11.2012
comment
кнопка на самом деле является окном с классом BUTTON - person BigBoss; 08.11.2012
comment
Кнопки, которые есть в этой игре, не являются стандартными кнопками .Net Windows. Они находятся в пользовательском интерфейсе, который не позволяет получить доступ к кнопкам через findwindowex. - person Reed B; 08.11.2012
comment
Хорошо, у этого пользовательского интерфейса есть аксессуар для этой кнопки ?? вы должны обработать опубликованное сообщение в родительском окне и вызвать функцию для имитации некоторого действия на кнопке, поэтому PostMessage будет использоваться для отправки сообщения в ваше главное окно!! Если эта кнопка не является стандартной кнопкой Windows, как вы хотите отправить ей сообщение и ожидать, что она что-то сделает? Или как вы хотите отправить сообщение чему-то, что не имеет HWND?? - person BigBoss; 08.11.2012
comment
Я хочу имитировать щелчок мышью по определенным координатам в дополнение к нажатиям клавиш. Я мог бы вызвать событие мыши в координатах кнопки, и это будет так, как если бы пользователь щелкнул ее. - person Reed B; 08.11.2012

Вы уверены, что игра, в которую вы пытаетесь отправить текст, владеет элементом управления Windows Edit, который можно перечислить из дочерних элементов клиента? Очень может быть, что элемент управления Edit, на который вы ссылаетесь, является сущностью графического контейнера клиента. В этом случае вам, возможно, придется отправить сообщения WM_KEYDOWN и WM_KEYUP самому окну клиента для достижения желаемой функциональности.

Надеюсь, это поможет.

person Community    schedule 27.06.2013
comment
Спасибо за ответ! Есть два разных способа, которыми программа может обрабатывать пользовательский ввод. Один принимает данные от операционной системы. Это успешно смоделировано на моем примере. Другой метод — постоянно проверять состояние данной клавиши или кнопки. Это, насколько мне известно, не может быть легко воспроизведено. Единственный способ создать программу для ботов, которая имитирует этот тип ввода, — это внедрить dll, которая выполняет код, который обычно запускается при изменении состояния кнопки. - person Reed B; 28.06.2013
comment
Мне показалось, что вы пытаетесь отправить символы в программу из-за пределов памяти процесса, поэтому я ответил соответственно. Конечно, запуск из памяти процесса делает вещи более доступными, но функциональность, которую вы описали в своем вопросе, была выполнима вне самого процесса. В любом случае, спасибо за ответ. - person ; 28.06.2013