سؤال

I'm opening a window with CreateProcess, and I'm having a lot of trouble understanding SetWinEventHook.

In the calling function, I have:

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);
}

The create Process goes off without a hitch, but the WinEventProc function linked to the SetWinEventHook is not called. In order to get the WinEventProc to get called, I've tried something like this:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0);

after the createProcess call, but I have no idea how to end the while loop so it goes continuously.

I've done a lot of reading but I don't understand how to use SetWinEventHook to catch a process started by CreateProcess. Any help is appreciated!

هل كانت مفيدة؟

المحلول

You probably need full and working event loop - try:

MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}

If your app is not a GUI application - or more specifically if you don't need event loop for anything else than hooks - you might either add another thread and use above event loop there (and all the hooking and unhooking as well I suppose), or use PeekMessage in conjunction with GetMessage to create non-blocking event loop and call it regularly.

Secondly, you shouldn't remove your hook directly after a call to CreateProcess. Creation of a window happens usually after a program is fully loaded and initialized, and this process can take a while. CreateProcess works asynchronously, which means that it doesn't wait for all this to happen before exiting.

Thirdly, to be able to receive any kind of hook messages your message loop needs to be executed between SetWinEventHook and UnhookWinEvent - in any other case you will not get anything.

Finally, to avoid messages from other processes being passed to your process, you should probably start you application using CREATE_SUSPENDED flag, start your hook with apropriate process-ID, and then resume process execution by using ResumeThread with main thread handle obtained form CreateProcess.

Overall It should look along the lines of:

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);
}

If you application is not event driven - just regular sequential app, then you should call above event loop regularly until your WinEventProc executes - you probably should add some safeguard variables to see if it was already executed. Another good idea might be including some timeout (2-3 minutes?) in case that no events are posted (app crashing, app creating no objects for some reason). For simplicity I also skipped any error checking.

And your hook procedure should do something like that:

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.
    [...]

}

EDIT:

As for skipping through the message loop - yes, that's what this message loop is supposed to do.

Which message loop is best for you depends on you program construction - if you already have an even loop running (GUI-frameworks like Qt, MFC... usually implement it for you already), then you don't need to add any anyway. If you want your app to wait until WinEvent is delivered then you should do something like that:

//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;
}

And the hooking function should do:

// In hooking function use:
docontinue = true;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
   TranslateMessage(&msg);
   DispatchMessage(&msg);
   if (!docontinue)
       break;
}

This is most naive approach, it has several drawbacks, but if you just need to do one simple operation then it will probably be enough for you.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top