Question

I have a windowless application whose only purpose is to install a 32 bit hook DLL file and wait until the parent program (a 64-bit program) exits. The 64-bit program is written in C#, and the windowless application is written in C++. I originally had this GetMessage loop which held the program open:

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

I was closing the C++ application using the Process.Kill method in C#, but I found out that that isn't allowing the C++ application to close cleanly. Also, if the C# application crashed, the C++ application would stay open forever. I made the C++ application check to see if the C# application is still running, using this loop:

while(true)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;

    Sleep(1000);
}

For some reason the Sleep causes problems. The hooks installed by the DLL file are WH_CBT and WH_KEYBOARD. Whenever I press a key while the C++ application is running with this loop, the keys just get eaten up. Removing the Sleep makes it work fine, but, as expected, it uses 100% CPU, which I don't want. I tried removing the message loop altogether and instead using WaitForSingleObject with an infinite timeout on a thread which would end when isMainProgramRunning returned false. This basically locks up the whole computer.

I don't really understand why GetMessage, which, as far as I saw, never returned, but suspended the main thread indefinitely, didn't cause these problems yet WaitForSingleObject causes every application to freeze when I click on it. How can I get the C++ application to stay open until the C# application closes?

Edit:

Since it's been pointed out to me that sleeping in a message pump is bad, let me ask this: Is there a way to specify a timeout on the message waiting, so the program isn't waiting indefinitely for a message, but rather, will wait about 250 ms, timeout, let me run the isMainProgramRunning method, then wait some more?

Edit2:

I tried using MsgWaitForMultipleObjects, although in a somewhat different way than Leo suggested. This is the loop I used:

while(MsgWaitForMultipleObjects (0, NULL, true, 250, QS_ALLPOSTMESSAGE) != WAIT_FAILED)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;
}

Again I had the same problem with the Sleep. I also tried suspending the main thread and having the other thread resume it. Same problem. What is it that GetMessage does that allows it to wait without causing these problems? Maybe this should be the subject of another post, but why is it that when the C++ application installing the hooks sleeps or is suspended, all processing in the hooks seems to suspend as well?

Edit3:

Here is the DLL method that the C++ application calls to install the hooks:

extern "C" __declspec(dllexport) void install()
{
    cbtHook = SetWindowsHookEx(WH_CBT, hookWindowEvents, hinst, NULL);

    if(cbtHook == NULL)
        MessageBox(NULL, "Unable to install CBT hook", "Error!", MB_OK);

    keyHook = SetWindowsHookEx(WH_KEYBOARD, LowLevelKeyboardProc, hinst, NULL);

    if(keyHook == NULL)
        MessageBox(NULL, "Unable to install key hook", "Error!", MB_OK);
}
Was it helpful?

Solution

GetMessage never returns is because you don't have a window created!

To use a message-queue you have to have some GUI. You Can for instance create a hidden window.

OTHER TIPS

You have two separate problems:

  1. How to make the windowless C++ program exit automatically if the C# program exits (e.g. crashes).

    In the C++ program, open a handle to the C# program. Since the C# program runs the C++ program, have the C# program pass its own PID as an argument; the C++ program can then open a handle to that process using OpenProcess.

    Then use MsgWaitForMultipleObjects in your message loop. If the C# program exits the handle you have to it will be signalled and you will wake up. (You can also use WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0 to check if the process is signalled or not, e.g. to verify why you were woken up, although the MsgWaitForMultipleObjects result will tell you that as well.)

    You should close the process handle as you are exiting (although the OS will do it for you when you exit, it's good practice in case you re-use this code in a different context). Note that the handle outlives the process it represents, and that is why you can wait on it.

  2. How to make the C# program instruct the C++ program to exit.

    You may not need this if you get #1 working, but you could just have the C# program post a message to the C++ one if you want.

    Do NOT use PostQuitMessage and do NOT post or send WM_QUIT across threads or processes.

    Instead, post some other message that the two apps agree on (e.g. WM_APP+1) using PostThreadMessage.

You can create a named event and use:

MsgWaitForMultipleObjects

in your message loop.

The C# application only have to open and raise this event to tell your application to exit.

It's kind of minimal interprocess communication.

You should exit the process by posting a WM_QUIT message to it and handling it correctly, as specified in this article (Modality), by Raymond Chen. Don't sleep inside a loop without handling messages - it's wrong. Your app should either be handling a message or waiting for new messages.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top