7

Whilst messing around with multithreading, callbacks, win32 api functions, and other troublesome troubles, I received an idea event. (hehehe)

What if, instead of defining a global (or static when designing a class) callback function, I instead assigned DefWindowProc for lpfnWndProc when registering the window class, and then ran the whole event loop on a separate thread?

This way I don't have to hack around the this problem when implementing the callback in a class and the main thread's execution continues, freeing you from that god-forsaken while loop, allowing you to do whatever, even open another window (yay!)

The "normal" way:

LRESULT CALLBACK WndProc(...)
{
    ... // process event information
    return DefWindowProc(...);
}

int CALLBACK WinMain(...)
{
    ... // initialize whatever needs initializing :)
    WNDCLASSEX wc;
    ...
    wc.lpfnWndProc = WndProc;
    ... // register the class, create the window, etc...

   MSG msg;
   while(GetMessage(&msg, 0, 0, 0) != 0)
   {
        ... // TranslateMessage(&msg) if you want/need it
        DispatchMessage(&msg); // dispatches the message to WndProc
   }

   return static_cast<int>(msg.wParam);
}

My newfound awesome way:

DWORD WINAPI MyAwesomeEventLoop(void* data) // must be static in a class
{
    ... // do whatever you need with the data
    MSG msg;
    while(GetMessage(&msg, 0, 0, 0) != 0)
    {
        ... // TranslateMessage(&msg) if you want/need it
        ... // process event information
            // call PostQuitMessage(0) to leave the loop
    }

    return static_cast<DWORD>(msg.wParam);
 }

int CALLBACK WndProc(...)
{
    ...
    WNDCLASSEX wc;
    ...
    wc.lpfnWndProc = DefWindowProc;
    ...
    HANDLE threadHandle = 0;
    // use "this" as the 4th parameter when implementing in a class
    threadHandle = CreateThread(0, 0, MyAwesomeEventLoop, 0, 0, 0);

    ... // you are now free to do whatever you want! :)

    // waits untill the thread finishes
    // hopefully because PostQuitMessage(0) was called
    WaitForSingleObject(threadHandle, INFINITE);
    DWORD returnValue = 0;
    GetExitCodeThread(threadHandle, &returnValue);
    CloseHandle(threadHandle);
    ...

    return static_cast<int>(returnValue);
 }

What do you guys think?

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
acpluspluscoder
  • 446
  • 1
  • 4
  • 10

2 Answers2

14

GetMessage docs on MSDN:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx

Read the first sentence: "Retrieves a message from the calling thread's message queue."

The message queue for a window is tied to the thread it was created on. Since you created your window on the main thread, your event loop running on a new thread will just not receive any messages for that window. If you want to run the event loop on another thread, you will need to create the thread first, then create your window on that thread.

Andrew
  • 186
  • 1
  • 3
2

That doesn't really buy you anything, except now you have window class-specific event handling code in a generic event loop, which is plain ugly. If you need background work, use worker threads. Keep the GUI and the event reactor inside the main thread, and use callbacks as documented.

And if you have a class whose instances handle windows, you shouldn't make them global even in single-threaded code (or you will suffer painful refactoring in the future).

Pharap
  • 3,826
  • 5
  • 37
  • 51
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • 1
    They are global just for example. Why is a generic event loop ugly? – acpluspluscoder Dec 03 '11 at 10:24
  • @acpluspluscoder: Generic event loop with non-generic code stuffed inside is ugly. And if they're not global, then you're using `(Get/Set)WindowLongPtr` anyway, so I don't see what you mean by "I don't have to hack around the `this` problem". – Cat Plus Plus Dec 03 '11 at 10:28