#c #winapi #hook
Вопрос:
Я пытаюсь прослушивать события в окне стороннего приложения, в котором у меня нет источника.
Я не понимаю эту часть документации, в которой говорится:
Клиентский поток, вызывающий SetWinEventHook, должен иметь цикл сообщений для получения событий.
Как мне «определить» этот цикл сообщений?
В моем коде крючка он никогда не достигает switch
:
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
)
{
switch (event) {
case EVENT_SYSTEM_MINIMIZESTART:
...
break;
case EVENT_SYSTEM_MINIMIZEEND:
...
break;
}
}
HWINEVENTHOOK hWinEventHook;
int EventHook() {
hWinEventHook = SetWinEventHook(
EVENT_SYSTEM_MINIMIZESTART, // eventMin
EVENT_SYSTEM_MINIMIZEEND, // eventMax
NULL, // hmodWinEventProc
WinEventProc, // pfnWinEventProc
4834, // idProcess
0, // idThread
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); //dwFlags
MSG msg;
while (GetMessage(amp;msg, NULL, 0, 0))
{
TranslateMessage(amp;msg);
DispatchMessage(amp;msg);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::thread t1(EventHook);
...
}
Я изменил код, как было предложено в комментариях, но теперь моя программа выходит из строя;
Он выходит из строя, когда доходит до линии:
while (GetMessage(amp;msg, NULL, 0, 0))
Комментарии:
1. «Цикл сообщений» — это сокращение для вызова
GetMessage
иDispatchMessage
повторного своевременного вызова.while
Цикл в вашем примере на самом деле является циклом сообщений. В той мере, в какой существует проблема, она кроется в другом. Вы проверилиSetWinEventHook
, удался ли вызов? Является4834
ли действительным идентификатор какого-либо процесса? Вы свернули или восстановили какое-либо окно, принадлежащее этому процессу?2. @IgorTandetnik Вы имеете в виду, если
hWinEventHook
возвращает значение? Оно делает.3. У вас есть цикл сообщений, но он недостаточно хорош, когда вы используете std::async. Требование состоит в том, чтобы цикл сообщений выполнялся в том же потоке, который установил крючок. Легко исправить, вам просто вообще не нужно, чтобы он был асинхронным.
4. И вам, вероятно, также необходимо скомпилировать для Windows вместо консоли, чтобы основной поток был потоком пользовательского интерфейса, а код, вероятно, должен запускаться из основного потока или, по крайней мере, из потока STA. Я думаю, что крючки несколько трудно понять и понять правильно, и если они не будут выполнены должным образом, это может сильно повлиять на стабильность системы. Лучше всего избегать их, если у вас нет другого выбора и вы не готовы много читать…
Ответ №1:
Цикл сообщений должен быть в основном, в вашем случае после вызова SetWinEventHook. И поскольку у вас нет другого способа выхода из вашей программы, вы, вероятно, захотите создать диалоговое окно с кнопкой выхода, и в обработчике для этой кнопки BN_CLICKED используйте вызов MessageBox, чтобы подтвердить, что пользователь хочет выйти, и если да, то сделайте PostQuitMessage). Подтверждение заключается в том, что в противном случае было бы слишком легко выйти.
Комментарии:
1. Я изменил сообщение, добавил отладочную информацию, я не понимаю , что вы имеете в виду, нужно включить
main
, я сомневаюсь, как запустить его во вторичном потоке.
Ответ №2:
Цикл сообщений, который вы показали, в полном порядке (после его перемещения EventHook()
).
«Авария» на самом деле не является катастрофой. Это просто программа внезапно завершает работу, потому что поток все еще работает, когда std::thread
объект уничтожен, поскольку вы не вызывали join()
или detach()
не запускали его до того, как он вышел из области видимости при _tmain()
выходе.
По std::thread::~thread
:
Уничтожает объект потока.
Если
*this
имеет связанный поток (joinable() == true
),std::terminate()
вызывается.Примечания
Объект потока не имеет связанного потока (и его безопасно уничтожать) после
Итак, симпатичный звонок t1.join()
перед _tmain()
выходом:
int _tmain(int argc, _TCHAR* argv[])
{
std::thread t1(EventHook);
...
t1.join();
return 0;
}
Комментарии:
1. Как избежать уничтожения нити? Я попытался определить
t1
как глобальную переменную, и теперь я получил эту ошибку:call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
2. Мне нужно выполнить больше кода после вызова
EventHook()
, вот почему я спрашиваю, как запустить его во вторичном потоке.3. @LeandroBoinha ничто в вашем вопросе или предыдущих комментариях не говорит о том, что вы хотите запустить другой код во время выполнения крючка. Если вам нужна нить, просто вызовите
join()
ее перед выходом.4. Мне не нужен поток, я пытаюсь добиться того, чтобы функция EventHook() выполнялась в потоке и одновременно выполняла остальную часть моего кода в другом потоке. Если я вызову join, он застрянет в цикле сообщений EventHook()
5. @LeandroBoinha » Мне не нужна нить » — вы противоречите себе. » Если я вызову join, то он застрянет в цикле сообщений EventHook() » — нет, этого не произойдет.
join()
заблокирует поток, который его вызывает, то есть поток, в котором_tmain()
выполняется.EventHook()
, и его цикл сообщений будет продолжать работать разблокированным в своем собственном потоке.