PeekMessage() and GetMessage() not quitting the message loop

Started by
2 comments, last by TomKQT 13 years, 7 months ago
I'm in the process of writing a small wrapper for DirectX that just covers initialization. It's remarkably simple in that the majority of the settings are hard-coded, as it's just for use as a learning experience, however, I've run into some problems.

It's my message loop. I have two versions (one with GetMessage(), the first one I wrote in this piece, primarily for testing, and the other with PeekMessage(), which is the one I intend to use) These are as follows;

GetMessage;
MSG msg;BOOL bret = -1;while( ( bret = GetMessage( &msg, dx_win.handle(), 0, 0 ) ) != 0 ){	if( bret < 0 ){		wdx::MessageError( NULL, TEXT( "WinMain()" ) );		break;	}	TranslateMessage( &msg );	DispatchMessage( &msg );}	if( bret < 0 )	wdx::MessageError( NULL, TEXT( "WinMain()" ) );dx_win.Destroy();return bret;


PeekMessage;
while( true ){	if( dx_win.PeekMsg() == false )		break;	// do other game stuffs here}/* dx_win.PeekMsg() */bool DirectX9Window::PeekMsg(){	if( window == NULL )		return false;	MSG msg;	if( PeekMessage( &msg, window, 0, 0, PM_REMOVE ) != 0 ){				if( msg.message == WM_QUIT )			return false;		TranslateMessage( &msg );		DispatchMessage( &msg );	}	return true;}


The problem I'm having with the second one (and the first when I change the comparison of GetMessage's return from '>0' to '!=0' and remove the 'if' block inside it) is that the window closes, but the application continues. I'm pretty sure it's not a problem with the WndProc, either;
// DirectX9Window is the name of the class, and is the type of dx_win in // the previous code snippetsLRESULT CALLBACK DirectX9Window::MessageProc( UINT msg, WPARAM wp, LPARAM lp ){	if( msg == WM_DESTROY ){ // this is probably done in DefWindowProc anyway, but nevermind		PostQuitMessage( 0 );	}	else		return DefWindowProc( window, msg, wp, lp );}


The MessageError() function( creates a Message Box, formatting the result of GetLastError() ) is never called in the GetMessage snippet, but if I take out the surrounding 'if' block, the loop never quits. Thanks to breakpoints, I've found that there's a system error stating
{No Paging File Specified} No paging file was specified in the system configuration.

which doesn't make much sense to me, as I wasn't aware I would need a specified paging file to close a window.

Anyway, the long and short of my problem is that neither of the two message pumps above quit once my window is closed, with the exception of the GetMessage modifications I've already mentioned. As you can see, I'm programming in C++, in VC++ 2010 Express, and I'm getting a little frustrated with it. Time to go to bed and see if it's clearer in the morning..
Advertisement
Pass NULL instead of the window-handle to PeekMessage/GetMessage. WM_QUIT does not belong to a window, and is also sent after the window is destroyed, so the window handle will be invalid then. You usually want to handle all messages in the thread message queue, not just those associated with a specific window. More information: GetMessage.
Thank you very much for that, I can't believe (but somewhat guessed) it was that simple. Just my luck :P

It never occurred to me that messages could be for the application, rather than just the windows opened by it.

Again thanks for the correction.

[Edited by - webwraith on August 22, 2010 12:15:21 PM]
There's still a small problem with your message loop:

while( true ){	if( dx_win.PeekMsg() == false )		break;	// do other game stuffs here}/* dx_win.PeekMsg() */bool DirectX9Window::PeekMsg(){	if( window == NULL )		return false;	MSG msg;	if( PeekMessage( &msg, window, 0, 0, PM_REMOVE ) != 0 ){				if( msg.message == WM_QUIT )			return false;		TranslateMessage( &msg );		DispatchMessage( &msg );	}	return true;}


Let's imagine there are multiple messages waiting for you to process. But what you're doing is this:
1. Get and process one message.
2. Make game stuff (update, render etc.)
3. Get back to 1 as long as the message is not WM_QUIT.
You'll process all the waiting messages very slowly because you will be rendering after every single one.

You should do rendering only if PeekMessage returned false at the current frame.
This is the idea:
while (msg.message != WM_QUIT){	if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	else {		// do game stuff....	}}


In your case you could maybe for example not return just bool (true/false) from
bool DirectX9Window::PeekMsg()
but three different values which would mean
- there was no message
- there was a message other than WM_QUIT
- there was WM_QUIT message

This topic is closed to new replies.

Advertisement