Message Handling Problem ( was "Problem in Game Loop?" )

Started by
7 comments, last by Lenox 18 years, 10 months ago
Hey, I'm having a problem. It seems I'm having problems with my message handling. I can't exit the application by hitting 'escape' unless I use GetAsyncKeyState(). Here's some code: Main.cpp

void Kernel::newWindow( int W, int H )
{
	HWND hWind = NULL;

	WNDCLASSEX windowClass;
	windowClass.cbSize			=			sizeof( WNDCLASSEX );
	windowClass.style			=			CS_HREDRAW | CS_VREDRAW;
	windowClass.lpfnWndProc		=			WndProc;
	windowClass.cbClsExtra		=			0;
	windowClass.cbWndExtra		=			0;
	windowClass.hInstance		=			hInstance;
	windowClass.hIcon			=			LoadIcon( NULL, IDI_APPLICATION );
	windowClass.hCursor			=			LoadCursor( NULL, IDC_ARROW );
	windowClass.hbrBackground	=			(HBRUSH)GetStockObject( BLACK_BRUSH );
	windowClass.lpszMenuName	=			NULL;
	windowClass.lpszClassName	=			"window";
	windowClass.hIconSm			=			LoadIcon( NULL, IDI_WINLOGO );

	if( !RegisterClassEx( &windowClass ) )
	{
		return;
	};

	hWind = CreateWindowEx( NULL, "#32769", "Audeuroa Adakitsa",
							WS_OVERLAPPEDWINDOW | WS_VISIBLE,
							0, 0, W, H, NULL, NULL, NULL, NULL );


	if( !( hWind ) )
	{
		return;
	}

	if( FAILED( initD3D( hWind, 800, 600 , true ) ) )
	{
		DestroyD3D();
		return;
	}; 

	++currIndex;
};

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	try
	{

		kInst = new Kernel();

		kInst->setInst( hInstance );

		kInst->newWindow( 400, 400 );

		MSG msg;

		while( 1 )
		{
			while( PeekMessage( &msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE ) )
			{
				if( msg.message == WM_QUIT )
				{
					delete kInst;
                    return msg.wParam;
				};

//				TranslateMessage( &msg ); // We WANT to use Virtual Keycodes, so we MUST NOT call TranslateMessage
				DispatchMessage( &msg );
			}
/*
			if( GetAsyncKeyState( VK_ESCAPE ) )
			{
				break;
			};
*/
			Sleep( 1 );
		};
		
		delete kInst;
		return msg.wParam;
	}

	catch( gExceptionHandler::Exception )
	{
		MessageBox( NULL, "An exception occured, the program will now exit. Please send your Exception.log to BugCenter@Sineful.com.", "Exception" , MB_OK );
		return 0;
	}

	catch( ... )
	{
		MessageBox( NULL, "An exception occured. The program will now exit. " , "Exception" , MB_OK );
        return 0;
	}

};


// GetAsyncKeyState()
LRESULT CALLBACK WndProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam )
{
	switch( Message )
	{
	case WM_KEYDOWN:
		{
			switch( wParam )
			{
			case VK_ESCAPE:
				{
					PostQuitMessage( 0 );
					break;
				};
			};

			return 0;
		};
		
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc;
			hdc = BeginPaint( hWnd, &ps );

			RECT rect;
			GetClientRect( hWnd, &rect );

			EndPaint( hWnd, &ps );

			break;
		};

	case WM_CLOSE:
		{

			return 0;
		};

	case WM_DESTROY:
		{
			PostQuitMessage( 0 );
			break;
		};

	};

	return DefWindowProc( hWnd, Message, wParam, lParam );
};






For some reason, WndProc isn't handling the messages properly. I can push escape and the quit message won't be posted. [EDIT] Fixed no-close problem: Thanks Palish! Updated code. Updated code with my newWindow procedure. Haha, fproto pointed out that I forgot to complete that return, :P. [Edited by - Lenox on June 4, 2005 2:22:27 AM]
Advertisement
You're in an infinite loop, so your application is running in circles as fast as it can, and doesn't care about any other applications on your system:
while( 1 ){	if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )	{		if( msg.message == WM_QUIT )		{			break;		}			TranslateMessage( &msg );		DispatchMessage( &msg );	};};


If using 99% cpu is undesirable for your program, you can force your application to give up CPU control by using a Sleep(0) call. Though if you're writing a time-critical application, (aka graphics engine) you probably want all the CPU you can get.

while( 1 ){	if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )	{		if( msg.message == WM_QUIT )		{			break;		}		TranslateMessage( &msg );		DispatchMessage( &msg );	};            // give up CPU control to waiting threads        Sleep(0);};


If you wish for your application to use as much CPU as it can, only when nothing else needs it, you can set the thread priority to idle:

SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);/* ... your program loop here*/
pragma Fury:
Should it be taking up 99% since I have no rendering to do yet? I WILL take your Sleep( 0 ) advice.

Also, I found out why WM_KEYDOWN isn't being sent. For some reason, WndProc isn't even being called! Anyone know why? Thanks for any help in advance.
Quote:Original post by Lenox
Should it be taking up 99% since I have no rendering to do yet? I WILL take your Sleep( 0 ) advice.

1.) Yes it should be, you are in a loop.
2.) I'm not sure if you understood, but calling Sleep(0) is generally not something that you want to do in a game or graphics engine, you want full resources.
Quote:Original post by Saruman
Quote:Original post by Lenox
Should it be taking up 99% since I have no rendering to do yet? I WILL take your Sleep( 0 ) advice.

1.) Yes it should be, you are in a loop.
2.) I'm not sure if you understood, but calling Sleep(0) is generally not something that you want to do in a game or graphics engine, you want full resources.


I'm going to remove Sleep( 0 ) as soon as I actually have something to render.
I agree with the original poster, I think 100% resources at all times is not a good idea for Windows games, because it's common to pause to check IM or email. You probably want to design your heaviest loads to run at >= 30fps, so it's quite reasonable Sleep during lighter loads. BTW, I use Sleep(1), because Sleep(0) tends to nearly max out the CPU anyway! A granularity of 1 to 2 milliseconds hasn't bugged me at all.
Quote:Original post by Anonymous Poster
I agree with the original poster, I think 100% resources at all times is not a good idea for Windows games, because it's common to pause to check IM or email. You probably want to design your heaviest loads to run at >= 30fps, so it's quite reasonable Sleep during lighter loads. BTW, I use Sleep(1), because Sleep(0) tends to nearly max out the CPU anyway! A granularity of 1 to 2 milliseconds hasn't bugged me at all.



It worked. Sleep( 1 ) slowed it down to 0% CPU Usage as expected. Thanks. Now I just need help with why WndProc isn't being called.
Keep in mind that Sleep() (like GetTickCount()) has limited granularity.. if you type Sleep(1), your system will generally sleep for anywhere between 3 and 15ms!

In fact, if you have a CPU-greedy application running elsewhere, your program may not get control back for a couple hundred ms!

Best to avoid Sleep in any time-critical application.

You can pretty easily set your Thread Priority to idle, or intialize your Sleep-ing when your application loses focus.
Quote:Original post by pragma Fury
Keep in mind that Sleep() (like GetTickCount()) has limited granularity.. if you type Sleep(1), your system will generally sleep for anywhere between 3 and 15ms!

In fact, if you have a CPU-greedy application running elsewhere, your program may not get control back for a couple hundred ms!

Best to avoid Sleep in any time-critical application.

You can pretty easily set your Thread Priority to idle, or intialize your Sleep-ing when your application loses focus.


Ah, I see. Thanks! ( Remember: Sleep( 1 ) is just a temporary fix. But, I will be doing long periods of sleep while the application is minimized. )

This topic is closed to new replies.

Advertisement