Программно нажать кнопку в другом приложении (C, Windows)

Я пытаюсь использовать следующий код, чтобы нажать кнопку в другом приложении:

HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{   
   ButtonHandle = FindWindowEx(wnd, 0, "SaveButton", "&Save");
   SendMessage(wnd, WM_COMMAND, MAKEWORD(GetDlgCtrlID(ButtonHandle), BN_CLICKED ), (LPARAM)ButtonHandle);

}

Это не работает. Я пытался передать разные дескрипторы в MAKEWORD и изменить WPARM и LPARAM, но ничего.

Любые идеи о том, как нажать кнопку в окне другого приложения?

Код приветствуется. Спасибо.

РЕДАКТИРОВАТЬ: Причина, по которой, похоже, не работают разрешения. Я отправил сообщение PostMessage(), и результатом была ошибка GetLastError() = 5 (или доступ запрещен). Есть идеи?

EDIT2 Я не хочу показаться грубым, но, пожалуйста, пожалуйста, я уже обыскал все API, включая получение и настройку регионов для кнопки, а затем отправку кнопки вниз и кнопку вверх, получение идентификатора элемента управления , получение идентификатора класса и многое другое. Причина, по которой я задал вопрос здесь, в первую очередь заключается в том, что я уже исчерпал свой поиск в Интернете. Если вы знаете ответ ПОСТАВЬТЕ КОД, не предлагайте API и все, покажите мне, как этот API решает проблему. Это не трудно. Спасибо.

РЕДАКТИРОВАТЬ 3: ответ на вопрос был выбран автоматически, когда награда закончилась. Вопрос по-прежнему остается без ответа.


person wonderer    schedule 03.08.2009    source источник
comment
Для какой версии винды это?   -  person billmcc    schedule 16.09.2009
comment
Возможно, это не имеет значения, но я предлагаю вам запустить программу от имени администратора или запустить Visual Studio в режиме администратора и попробовать, работает ли это. Также это то, что я видел в документации PostMessage: Microsoft Windows Vista и более поздние версии. Когда сообщение блокируется UIPI, последней ошибке, полученной с помощью GetLastError, присваивается значение 5 (отказано в доступе).   -  person FatDaemon    schedule 16.09.2009
comment
Это в Висте или 7? В XP работает? (Загрузите образ для запуска в Virtual PC от Microsoft и протестируйте.) Пробовали ли вы использовать sendkeys?   -  person svinto    schedule 17.09.2009
comment
Гух. Вот почему все графические приложения также должны иметь CLI. Такие вещи, как DBUS, еще лучше.   -  person Xiong Chiamiov    schedule 18.09.2009
comment
Учитывая, что у кнопки нестандартный класс кнопок, возможно, она не отправляет WM_COMMAND своему родителю. Он может даже не поддерживать Active Accessibility. Таким образом, предложения использовать SendInput для отправки событий мыши могут быть вашим лучшим выбором.   -  person Adrian McCarthy    schedule 22.09.2009
comment
Я пробовал с SendInput. Это ничего не делает. Даже при установке диалогового окна в качестве окна переднего плана   -  person wonderer    schedule 24.09.2009


Ответы (12)


  1. Вы уверены, что имя класса «SaveButton» допустимо? У вас есть ручка кнопки?
  2. Попробуйте отправлять сообщения в окно ButtonHandle (непосредственно на кнопку).

Обновление: я считаю, что это должно работать,

SendMessage(ButtonHandle, BM_CLICK, 0, 0);
person Nick Dandoulakis    schedule 03.08.2009
comment
1) да. Я уверен. Я использовал Spy++, чтобы получить эту информацию. 2) Я попытался отправить сообщение на дескриптор кнопки, но ничего не произошло. - person wonderer; 04.08.2009
comment
Конечно, знаю. Я получаю дескриптор окна, кнопку и даже класс кнопки - person wonderer; 04.08.2009
comment
В большинстве случаев отправленный вами sendmessage() работает, однако в одном случае он мне нужен больше всего, похоже, он не работает. Я получаю дескриптор кнопки и даже класс кнопки. Я пробовал разные подходы, но ничего... - person wonderer; 13.08.2009
comment
Странный. Хоть раз удалось? Вы должны получать дескриптор каждый раз, когда отправляете сообщение, а не (сохраняете) его повторное использование. Ручка кнопки может не всегда быть одинаковой. Бывает и так, что это кастомное кнопочное управление, но все же... Не могу сейчас что-то другое придумать. - person Nick Dandoulakis; 13.08.2009
comment
Обратите внимание, что в более поздних версиях Windows (Vista+) вам не разрешено отправлять сообщения в окна, работающие с более высокими привилегиями. - person Mike Weller; 17.09.2009
comment
@Майкл Веллер, спасибо за информацию. Возможно, это объясняет проблему вандерера, если он использует Vista. - person Nick Dandoulakis; 17.09.2009
comment
Я использовал это мой код. Работает. Это действительно не работает, когда код без повышенных прав пытается отправить приложение с повышенными правами. - person bohdan_trotsenko; 21.09.2009
comment
@modosansreves, ваш комментарий интересен, но я не знаком с термином код без повышенных прав. Не могли бы вы уточнить это? - person Nick Dandoulakis; 21.09.2009
comment
@wonderer, если вы не примете ответ, SO автоматически примет ответ, когда истечет срок действия награды. - person Nick Dandoulakis; 24.09.2009

SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);

Вы должны отправить нажатие кнопки дважды. Не уверен, почему (может быть, первый щелчок только активирует окно кнопки), но я использую этот код в течение длительного времени, и он всегда работал для меня.

person mwore    schedule 17.09.2009

возможно, это может помочь: http://www.cplusplus.com/forum/beginner/8806/

person fnurglewitz    schedule 03.08.2009

См. следующее решение, также вы можете использовать

SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0);

Or

SendMessage(ButtonHandle, BM_CLICK, 0, 0);

HWND buttonHandle = 0;

BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
 char label[100];
 int size = GetWindowTextA(handle,label,sizeof(label));
 if(strcmp(label,"&Save") == 0)
 {
  buttonHandle = handle;
  return false;
 }
 return true;
}
void main()
{
 HWND windowHandle = FindWindowA(NULL,"Do you want to Save?");
 if(windowHandle != 0)
 {
  BOOL ret = EnumChildWindows(windowHandle,GetButtonHandle,0);

  if(buttonHandle != 0)
  {
   LRESULT res = SendMessage(buttonHandle,BM_CLICK,0,0);
   //SendMessage(buttonHandle,WM_LBUTTONDOWN,0,0); 
   //SendMessage(buttonHandle,WM_LBUTTONUP,0,0);
  }

 }



}

Примечание. Убедитесь, что текст окна, текст кнопки (проверьте, есть ли пробел в конце заголовка окна)

person Ahmed Said    schedule 17.09.2009

Ошибки Access Denied в SendMessage или PostMessage не имеют смысла, если только процесс, отправляющий сообщение, не выполняется с более низким уровнем целостности, чем целевой процесс.

Этого не должно происходить, если только процесс, которому принадлежит целевое окно, не запускается от имени администратора или не является службой. И службам чертовски сложно создавать окна на интерактивном рабочем столе с Windows 6 и выше.

Вы можете почитать об уровнях целостности здесь, если они применимы даже удаленно. к этой ситуации. Internet Explorer — едва ли не единственное другое приложение, которое «выбирает» модель безопасности целостности, намеренно снижая уровень своей целостности, чтобы более эффективно изолировать себя.

person Chris Becke    schedule 17.09.2009
comment
странный. Оба процесса запущены от имени администратора. Однако процесс, который я пытаюсь щелкнуть, является интерфейсом (GUI) для службы. Теперь графический интерфейс - это не служба, это простое приложение с графическим интерфейсом win32, которое все, что он делает, - это вызывает диспетчер служб и обновляет службу... Интересно, заставляет ли это графический интерфейс отбрасывать сообщение... - person wonderer; 17.09.2009

Если вы можете поднять окно, содержащее кнопку, вы можете отправить необработанное событие мыши в положение в пределах границ кнопки.

Существует две функции для имитации события мыши: SendInput. и mouse_event. Я рекомендую использовать функцию mouse_event. Чтобы открыть окно, вы можете использовать ShowWindow. Я не знаю, как получить дескриптор кнопки, но если у вас есть hWnd, ее абсолютное положение легко найти с помощью GetWindowRect. Попробуйте использовать их, если у вас возникнут проблемы, я буду рад помочь.

Или определите собственный WM в вашем окне приложения для обработки запроса на сохранение. WM_CUSTOM или WM_USER (не помню какой) отмечает начало пользовательских оконных сообщений.

person Cem Kalyoncu    schedule 16.09.2009
comment
1) пример? 2) Я не могу определить какие-либо пользовательские обработчики сообщений в приложении. - person wonderer; 16.09.2009
comment
Поскольку образец слишком длинный, я обновил ответ, пожалуйста, проверьте его. - person Cem Kalyoncu; 16.09.2009
comment
Хорошо, снова. Я не могу установить собственный обработчик сообщений в своем приложении или в окне приложения, и, поскольку я специально попросил образец кода, я был бы признателен, если бы вы могли предоставить образец. Причина, по которой я спросил, заключается в том, что я уже прошел через все ответы, которые смог найти самостоятельно, включая обычную попытку X и Y. Что ж, если вы думаете, что X и Y работают, пожалуйста, покажите мне код. в противном случае я очень благодарен вам за усилия, но это не то, что я ищу. - person wonderer; 16.09.2009
comment
Мне очень жаль отправлять комментарий до дополнительных определений, мне нужно было выполнить какую-то другую задачу, и я смог отредактировать его только сейчас. Проверьте дополнительный абзац, я включил функции, которые вам понадобятся. нет образца, который я могу предоставить, но я уверен, что вы поймете это, используя эти функции - person Cem Kalyoncu; 16.09.2009
comment
Я также почти уверен в mouse_event, потому что это то, что используют драйверы устройств. Если вы прочитаете статью MSDN, вы увидите, что производители планшетов рекомендуют использовать ее в своих драйверах. - person Cem Kalyoncu; 16.09.2009
comment
Еще раз спасибо. Проблема с SendInput() и mouse_event() заключается в том, что указатель мыши ДОЛЖЕН находиться поверх того места, которое вы хотите щелкнуть. То, что я пытаюсь сделать, это нажать кнопку программно, как указано в вопросе. для этого мне нужно использовать SendMessage или PostMessage. Я уже прошел через все это сам. - person wonderer; 16.09.2009
comment
в mouse_event вы устанавливаете координаты, где происходит событие, или перемещаете мышь в нужное вам положение. - person Cem Kalyoncu; 16.09.2009
comment
наблюдать: mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, btnpos.left+(btnpos.right-btnpos.left), btnpos.top(btnpos.bottom-btnpos.top), 0, NULL); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, btnpos.left+(btnpos.right-btnpos.left), btnpos.top(btnpos.bottom-btnpos.top), 0, NULL); - person Cem Kalyoncu; 16.09.2009
comment
Спасибо. Тем не менее, если я не помещу указатель мыши поверх кнопки, он не нажмет на нее. - person wonderer; 17.09.2009
comment
Попробуйте SetCursorPos изменить положение мыши. и не забудьте активировать целевое окно. - person Cem Kalyoncu; 17.09.2009

Когда мне приходится делать подобные вещи, я использую SendKeys. Это VB-иш, и C# предоставляет приятный интерфейс для использования, но для C/C++ вам придется это сделать ‹здесь>. Что хорошо, так это то, что вы можете писать сценарии и запускать их вместо жесткого кодирования в своем коде.

person jdehaan    schedule 17.09.2009

Теперь Microsoft продвигает Active Accessibility (MSAA) для автоматизации пользовательского интерфейса (он был переименован в раз за годы) см.

Извините, у меня нет простого кода, чтобы вы начали. Поскольку «SendMessage()», похоже, не работает для вас, я не знаю другого варианта, кроме «Автоматизация пользовательского интерфейса».

Я предполагаю, что вы проверили с помощью Spy ++ (установленного с MsDev), что ваше сообщение отправляется на правильную кнопку и т. Д., И что кнопка является стандартной кнопкой Windows. Мой первый момент сказал бы использовать «SendMessage ()» или «PostMessage ()», но учитывая количество ответов о «SendMessage ()» и тот факт, что он не работает для вас. Я ожидаю, что кто-то продолжит…

person Ian Ringrose    schedule 21.09.2009

//Отправляем цифру 4 в уже открытый calc.exe

HWND windowHandle;

windowHandle = FindWindowA(NULL,"Calculator");

if(windowHandle != 0)
   ret = EnumChildWindows(windowHandle,GetButtonHandle,0);

BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));

if(strcmp(label,"4") == 0)
{
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);

PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);

return false;
}
return true;
}
person Tim Pearson    schedule 01.08.2020

Вы можете использовать sendkeys (как сказал tr3) для отправки щелчков мыши, что отличается от использования SendMessage. Это также менее прямолинейно и более хакерски, но полезно для автоматизации (в VBS).

Кроме того, просто предположение, но проблема может заключаться в том, что ваша обработка сообщений где-то нарушена из-за того, что вы не вызываете член базового класса. Пример:

void CMyClass::OnMessageY(CWnd *cwnd)
{
    CBaseClass::OnMessageY(cwnd);
    //... my code
}
person Klathzazt    schedule 15.09.2009

если вы уверены, что ButtonHandle является допустимым дескриптором, вы можете использовать пару сообщений WM_LBUTTONDOWN и WM_LBUTTONUP вместо BN_CLICKED

HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{   
    SendMessage(ButtonHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
    SendMessage(ButtonHandle, WM_LBUTTONUP, MK_LBUTTON, 0);
}
person Arash    schedule 16.09.2009
comment
это уже пробовал. это не работает. Я думаю, эта кнопка не хочет, чтобы ее нажимали. Что я получаю, так это отказ в доступе к ошибке, если я использую postmessage() или C000022 или что-то в этом роде, когда я использую SendMessage. Я посмотрел эту ошибку, и в основном это также отказ в доступе. - person wonderer; 17.09.2009
comment
можете ли вы нажать кнопку непрограммно;) - может быть программа перехватывает событие мыши, чтобы предотвратить нажатие другой программы на ее кнопку - person Arash; 17.09.2009
comment
Я уверен, что могу. там нет проблем. Я начинаю подозревать, что по какой-то причине приложение игнорирует сообщения - person wonderer; 17.09.2009

Подход, отличный от C: используйте Java и класс java.awt.Robot для перемещения мыши и выполнения реальных щелчков (я думаю, в мире Windows для этого тоже есть что-то). Проблема: вы должны знать, где находится ваша кнопка :D

person ZeissS    schedule 17.09.2009