Я открываю окно с CreateProcess, и у меня много проблем с пониманием SetWinEventHook.
В вызывающей функции у меня есть:
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT );
BOOL result = CreateProcess(0, arguments,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo)
if (hook) {
UnhookWinEvent(hook);
}
Процесс создания завершается без помех, но функция WinEventProc, связанная с SetWinEventHook, не вызывается. Чтобы получить вызов WinEventProc, я попробовал что-то вроде этого:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0);
после вызова createProcess, но я не знаю, как завершить цикл while, чтобы он шел непрерывно.
Я много читал, но я не понимаю, как использовать SetWinEventHook, чтобы поймать процесс, запущенный CreateProcess. Любая помощь приветствуется!
Возможно, вам нужен полный и работающий цикл обработки событий — попробуйте:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Если ваше приложение не является приложением с графическим интерфейсом — или, более конкретно, если вам не нужен цикл обработки событий для чего-то еще, кроме хуков, — вы можете либо добавить другой поток и использовать вышеупомянутый цикл обработки событий там (и, я полагаю, все перехватывания и отсоединения) или используйте PeekMessage
в сочетании с GetMessage
создать неблокирующий цикл обработки событий и регулярно вызывать его.
Во-вторых, вы не должны снимать хук сразу после звонка CreateProcess
, Обычно создание окна происходит после полной загрузки и инициализации программы, и этот процесс может занять некоторое время. CreateProcess
работает асинхронно, что означает, что он не ждет, пока все это произойдет, прежде чем выйти.
В-третьих, чтобы иметь возможность получать любые сообщения о перехватах, ваш цикл сообщений должен выполняться между SetWinEventHook
а также UnhookWinEvent
— в любом другом случае вы ничего не получите.
Наконец, чтобы избежать передачи сообщений от других процессов вашему процессу, вам, вероятно, следует запустить приложение, используя CREATE_SUSPENDED
флаг, начните свой хук с соответствующего идентификатора процесса, а затем возобновите выполнение процесса с помощью ResumeThread
с рукояткой основной резьбы полученной формы CreateProcess
,
В целом это должно выглядеть следующим образом:
BOOL result = CreateProcess(0, arguments,
NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
NULL, &StartupInfo, &ProcessInfo);
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, WinEventProc, ProcessInfo.dwProcessId, 0, WINEVENT_OUTOFCONTEXT );
ResumeThread(ProcessInfo.hThread);
// If you don't have an event loop function in your application already, then you could insert a temporary one here.
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Если ваше приложение не управляется событиями — просто обычное последовательное приложение, то вам следует регулярно вызывать вышеуказанный цикл обработки событий до тех пор, пока WinEventProc
выполняется — вы, вероятно, должны добавить некоторые защитные переменные, чтобы увидеть, было ли оно уже выполнено. Другой хорошей идеей может быть включение некоторого тайм-аута (2-3 минуты?) На случай, если события не публикуются (сбой приложения, приложение по какой-либо причине не создает объектов). Для простоты я также пропустил любую проверку ошибок.
И ваша процедура подключения должна сделать что-то вроде этого:
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
// This will handle the re-entrance problem nicely.
UnhookWinEvent(hWinEventHook);
// Do wathever you need to do with a window here.
[...]
}
РЕДАКТИРОВАТЬ:
Что касается пропуска через цикл сообщений — да, именно это и должен делать этот цикл сообщений.
Какой цикл обработки сообщений вам больше подходит, зависит от конструкции вашей программы — если у вас уже работает четный цикл (GUI-фреймворки, такие как Qt, MFC … обычно уже реализуют его для вас), то вам не нужно добавлять его в любом случае , Если вы хотите, чтобы ваше приложение дождалось доставки WinEvent, вам следует сделать что-то вроде этого:
//Global variable for stop-condition:
bool docontinue = false;
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
// This will handle the re-entrance problem nicely.
UnhookWinEvent(hWinEventHook);
// Do wathever you need to do with a window here.
[...]
docontinue = false;
}
И функция перехвата должна делать:
// In hooking function use:
docontinue = true;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (!docontinue)
break;
}
Это наиболее наивный подход, у него есть несколько недостатков, но если вам просто нужно сделать одну простую операцию, то, вероятно, вам этого будет достаточно.
Других решений пока нет …