Intro
Today I found a neat way to access and work with the windows message loop via a class member function using a small hack/workaround. Unless you are working with a command line application you will probably have need to call RegisterClassEx() (a win api function) at some point early on in your program, to register a window with the operating system. In doing so you fill out a WNDCLASSEX structure describing your window, and also setting the message processing callback function (the part we are interested in).
The scenario
As mentioned previously, when setting up our WNDCLASSEX structure we usually pass a non-member function into the structure as a callback mechanism for system/window events (usually names something like MsgProc). This non member function gets invoked when messages are sent to our application from the OS and we can handle them appropriately.
In a lot of situations (especially when developing games applications) we have some kind of manager class responsible for initialising the window, perhaps a graphics api etc, and it would be nice for this manager class to be able to handle the message loop it’s self using a class member function. This is handy as it allows events in the message loop to directly affect the state and behaviour of the manager class.
The problem is that when registering your window, the WNDCLASSEX structure will not take a class member function as a parameter (due to it needing a handle to the class instance at runtime). I have seen and used many hacks to allow a class to handle this job (involving function pointers / static class methods etc etc) but none have been as efficient as the one which follows…
- Give the WNDCLASSEX structure a non-member function to act as a …”middle man” message loop
- When calling CreateWindow() pass in a pointer to the class instance (usually “this“)
- Inside the non member message loop extract this pointer and redirect the call
Example
Here is an example of redirecting the message loop to the WndProc() method of a Manager instance…
Window Setup
//Setup the window class
WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, MainWndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL,"demo", NULL};
//Register window class with OS
RegisterClassEx(&wc);
// "this" is used to let the window know of our manager class instance
CreateWindow("demo", "demo", MODE_WINDOWED, 100, 100, 640, 480, GetDesktopWindow(), NULL, wc.hInstance, this);
Non-member Message Loop
//NON MEMBER MESSAGE LOOP
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static Manager* app = 0;
switch( msg )
{
case WM_CREATE:
{
// Get the pointer to the manager instance we passed
// into CreateWindow
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
app = (sys::Core*)cs->lpCreateParams;
return 0;
}
}
if( app )
{
return app->MsgProc(msg, wParam, lParam); //Re-call the message loop on our manager instance
}
else
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
Manager::MsgProc (Member Message Loop)
//MEMBER MESSAGE LOOP
LRESULT WINAPI CALLBACK Manager::MsgProc(UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
//Handle the message here inside the Manager member function
}
}