win32: Alternative message loop

Started by
3 comments, last by demonkoryu 17 years, 11 months ago
First off: Hello, I'm new here but I've been reading the forums every now and then and found them tremendously useful :) And now about the problem... Before I want to dive into directx and opengl and all that I want to make sure I know enough win32 programming to be sure that won't be a problem for any future games. Thus, it has been my ideal to create an easy wrapper class, that'd make creating windows no more difficult than: OpenWindow ( some params ); I know there's a tutorial on this site about making such a class, but I want to do things different and before I'm actually going to create the class I am testing with alternative message loops to make the job easier. I came up with the following:

#include <windows.h>
#define WIN32_LEAN_AND_MEAN

// start the main window loop immediately
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

	// Create a MSG struct instance
	MSG msg;

	// Create a WNDCLASSEX struct instance
	WNDCLASSEX wc;

	// Create a window handle
	HWND hWnd;

	// Fill the members of the WNDCLASSEX struct
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = NULL;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.lpfnWndProc = DefWindowProc;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.hCursor = LoadCursor(hInstance,IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance,IDI_APPLICATION);
	wc.hIconSm = LoadIcon(hInstance,IDI_APPLICATION);
	wc.hInstance = hInstance;
	wc.lpszClassName = "MyWindow";
	wc.lpszMenuName = NULL;
	
	// Register the actual class...
	if ( !RegisterClassEx ( &wc ) ) {
		MessageBox ( NULL, "Could not register window class!\nThis program will close now.", "Fatal Error", MB_OK|MB_ICONEXCLAMATION );
		return 0;
	}

	// Open a window and show it
	hWnd = CreateWindowEx ( WS_EX_OVERLAPPEDWINDOW, "MyWindow", "Test Window", WS_SYSMENU|WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL );
	if ( hWnd == NULL ) {
		MessageBox(NULL,"Could not open window display!\nThis program will close now.", "Fatla Error", MB_OK|MB_ICONEXCLAMATION);
	}

	ShowWindow ( hWnd, nCmdShow );
	UpdateWindow ( hWnd );
	
	// Now the ingenious part... The while message loop...
	int quit = 0;
	
	while ( quit == 0 )
	{		

		if ( PeekMessage ( &msg, hWnd, 0, 0, PM_REMOVE ) ) {

			TranslateMessage ( &msg );
			DispatchMessage ( &msg );

		}

		if ( msg.message == WM_QUIT  ) {

			PostQuitMessage ( 0 );

			quit = 1;

		} 
		
	}

    return 0;
}

Basically, the idea is to put the message loop inside the main window loop because I want my future windows program to look like this:

#include "mywinwrapclass.h"

OpenWindow ( "My Window Name", x, y, width, height );

While ( GetWindowMessage() != WM_QUIT ) {

  // do some stuff

}

Please note that the GetWindowMessage() function would be 'self-made'. Now, for the actual problem... I use VS6 and the first codeblock (the 'alternative message loop' test program) runs fine. It opens a window, and when you press the X button it closes. At least the window disappears, about the actual closing i'm not so sure because when I open my task manager I see that the CPU is on 100% and the program (WinLoop.exe) is taking it's full attention and looks far from being closed... :S Is there something I'm missing? Must I free the window class or something because I didn't use a normal windows callback function?
Advertisement
I had this exact problem a few days ago; try setting the hWnd parameter in PeekMessage() to NULL and see if that helps.
------------------------------Support the Blue Skies in Games Campaign!A blog... of sorts.As a general rule, if you don't have a general rule in your signature, you aren't as awesome as someone who does. General rules roxor teh big one one ones.
You should really have an own WindowProc, because SendMessage bypasses GetMessage and calls the window proc directly.

Also, PeekMessage doesn't retrieve the WM_QUIT event (you need GetMessage for that). So your program doesn't know that it should end and goes on and on forever.

if ( msg.message == WM_QUIT  ) {  PostQuitMessage ( 0 );  quit = 1;} 


PostQuitMessage posts the quit message. This usage is quite senseless (if it would work, it would send a WM_QUIT message in response to a WM_QUIT message, which would lead to an endless loop.

A better way would to write a WindowProc and then respond to the WM_CLOSE and WM_DESTROY messages:

LRESULT CALLBACK myWindowProc( HWND wnd, unsigned int msg, LPARAM, WPARAM ){   switch (msg) {      case WM_CLOSE: DestroyWindow( wnd ); return TRUE; break;      case WM_DESTROY: PostQuitMessage( 0 ); return TRUE; break;      default: break;   }   return DefWindowProc( wnd, msg, lp, wp );}

Thanks for the quick replies. The first one didn't work, unfortunately, but Konfusius' suggestion did the trick ;)

EDIT: Bah, I was a bit too enthusiastic to see that though the processor had gone back to its usual 2-4% the .exe was still running according to the taskmanager :( Below is the new way of doing the message loop, should I let the winmain function return something different? I'm a bit baffled that a normal window callback that returns 0 when the wm_destroy message is being processed does the job better than a simple 'if ( msg.message == wm_destroy )'...




Basically, I still want to experiment without the usual window callback function, but your endless loop advice from PostQuitMessage(0) was quite welcome. I now used GetMessage instead of PeekMessage and the messageloop now looks like this:

while ( quit == 0 ) {

if ( GetMessage ( &msg, NULL, 0, 0 ) > 0) {

TranslateMessage ( &msg );
DispatchMessage ( &msg );

}

if ( msg.message == WM_CLOSE ) {

DestroyWindow ( hWnd );

}

if ( msg.message == WM_DESTROY ) {

PostQuitMessage ( 0 );

}

if (msg.message == WM_QUIT) {

quit = 1;

}

}

It works perfectly, thanks. I think I can finally get on with creating the actual wrapper, and though I'm a bit concerned about your note on SendMessage() sending messages immediately to the callback function I'm hopeful that there will be ways around that ;)

[Edited by - rogierpennink on April 29, 2006 7:17:10 AM]
Hi,
WinMain should return the value of WM_QUIT, e.g. msg.wParam.
WM_QUIT @ MSDN

The difference between posted and sent messages are detailed here: Nonqueued messages

Sadly, there are no ways around creating an own WndProc, but it isn't complicated. About window procedures

Hope this helps,
Konfu.

This topic is closed to new replies.

Advertisement