Winapi, чужое приложение — проблемы с меню и окна отрисовываются только при наведении мыши?
Добрый день,
Моя операционная система Windows 8.1, есть приложение, которое написано на Java\SWT, доступа к исходным кодам нет.
Мне необходимо сделать некоторую автоматизацию, я делаю это через вызовы winapi.
Запускается программа отдельно, не через CreateProcess из программы, которая делает автоматизацию (не знаю, влияет ли это на что-нибудь).
Программа должна быть в фоновом режиме, то есть фокус стоит на другом окне, никак не связанном с ней.
Вопрос 1:
Главное меню, там где File, Help я ищу через вызов GetMenu - находит прекрасно, каждый раз.
Потом я вызываю GetSubMenu и GetMenuItemID соотвественно, чтобы найти пункт меню.
Проблема как раз в этом. GetMenuItemID выдает FFFFFFF - то есть она не находит пункт меню до тех пор, пока не кликнешь на пункт меню например File в самой программе, чтобы открылся список подменю.
Как только нажмешь, список подменю откроектся - находит нормально, пока программа некоторое время не постоит в простое - тогда снова подменю пропадает и выдает FFFFFFF.
Я перепробовал много различных команд посылать программе, но без успеха.
Каким образом можно реинициализировать меню, чтобы каждый раз не кликать для его инициализации?
Вопрос 2:
Приложение находится в фоновом режиме, фокус стоит на другом окне.
При нажатии на пункты меню через SendMessage, должен открыватся диалог с классом "#32770 (Dialog box)"
Проблема в том, что иногда происходит так, что диалоговые окна не открываются, пока... не наведешь мышью на область окна.
Я тестирую из консоли, консоль поверх окна программы, мышка находится на консоли. И ровно в момент того, как мышь наводится на заднее окно (именно просто наводится, без клика и активации), все диалоговые окна начинают рисоваться...
Если сделать SetForegroundWindow - то вроде бы все рисуется нормально, но тогда окно становится активным, а нужно чтобы оно было в фоновом режиме.
Вопрос 3:
Как определить, что диалоговое окно "#32770 (Dialog box)" открылось? Я долго искать в интернете, но почти все методы - это просто каждые N миллисекунд искать окно, а потом делать Sleep.
Вопрос 4:
Почему на разных компьютерах, все c Windows 8.1, программа работает по-разному?
На некоторых компьютерах SetForegroundWindow делает окно активным, то есть окно выскакивает на передний план.
На других SetForegroundWindow не делается активным, иконка программы в taskbar начинает мигать, но окно не выскакивает на передний план.
Иногда находит пункт подменю через GetMenuItemID, а иногда категорически отказывается, даже если активировать подменю через клик.
Ответ на 4 вопрос:
Когда деревья были маленькими, а Windows только появилась, то была функция SetActiveWindow, которая делала выбранное окно активным — выбрасывало на первый план. Но программисты любили делать свои окна постоянно активными и вызывали эту функцию слишком часто, от этого иногда система уходила в карусель активных окон. Для предотвращения этого в API Windows появилась функция SetForegroundWindow, которая работает почти также, но в случае частых вызовов окна перестают переключаться, а только начинают мигать в панели задач. Это не особенность компьютеров или программ — это внутренняя кухня. Если система решит, что вы слишком часто переключаетесь - она начнёт просто мигать кнопками. Ответ на 3 вопрос:
Ожидание появление окна — в цикле, по таймеру. Ничего в этом страшного нет. При желании это можно организовать в отдельном потоке.
Помимо этого есть сложные методы внедрения кода в программу, связанные с хуками приложения или перехватом вызовов функций, но не думаю что ваша задача требует такого сложного вмешательства. Ответ на 2 вопрос:
Видимо у программы так реализован цикл событий, что ваш SendMessage не обработается, пока не придут настоящие события - MOUSE_MOVE, например. Или для диалога нужно текущее активное окно. Или ещё много других подобных причин. Может перед SendMessage должно прийти другое событие.
В большинстве случаев для имитации действий нужно чтобы окно было активным. Если окно не активное, то имитация в равной степени может работать или не работать. Ответ на 1 вопрос:
Скорее всего меню динамические и создаются по щелчкам мыши и открытию меню. Поэтому вам ничего не остаётся как последовательно имитировать нажатие на меню File, пробег по пунктам меню, и выбор нужного пункта меню — чтобы отработали внутренние механизмы создания подменю.
Спасибо, ваши ответы очень помогли решить мою задачу. Я переделал чуть архитектуру и теперь делаю через SendInput в активное окно - все работает как часы и меню не пропадают.