Sign in to follow this  

MsgProc kill-window events

This topic is 4195 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm sorry in advance if I wasn't supposed to ask Windows-specific code in this forum, but here goes: Since I've started my first serious Windows programming, I've never felt truly comfortable with my Windows code. I wish that there was a simple, "right" way to create a window and run a main loop, but there obviously isn't. I'm sure that every single create-your-first window tutorial I have ever looked at has been slightly different. Because of all this uncertainty, I wanted to ask the people here (who apparently know a bit more than I do) a question about creating a MsgProc(). The one I currently use (with all the game logic taken out) is shown here:
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{

	case WM_CLOSE:
		DestroyWindow(hWnd);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_KEYUP:
		if(wParam==VK_ESCAPE)
		{
			PostQuitMessage(0);
		}
		return 0;

	}

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


and here is my WinMain():
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
	WNDCLASS wc;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.hCursor=LoadCursor(0, IDC_ARROW);
	wc.hIcon=LoadIcon(0, IDI_APPLICATION);
	wc.hInstance=hInst;
	wc.lpfnWndProc=WinProc;
	wc.lpszClassName="synth";
	wc.lpszMenuName=0;
	wc.style=CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);
	HWND hwnd=CreateWindow("synth", "the_synth", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100,
		800, 600, 0, 0, hInst, 0);
    
	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message!=WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{

			if(quit_game)
			{
				PostQuitMessage(0);
				break;
			}

	
		}
	}

	UnregisterClass("synth", hInst);

	return 0;
}


My questions are: -Is my MsgProc() redundant? Do I really need to have procedures for WM_CLOSE, WM_DESTROY, and WM_QUIT? Does MsgProc() even handle the WM_QUIT event? -Is the basic structure of my main loop correct (in the sense that it is sound and will not generate strange bugs as soon as I test it on a friend's computer)? -Is my UnregisterClass() call necessary? It's just that someone told me in another thread that I'm not supposed to make this call and that Windows handles this stuff without being told. Is that true? I'm afraid that if I delete that line then the program will cease to be sound (in the same sense as in the previous question.) Thanks a lot!

Share this post


Link to post
Share on other sites
Your MsgProc looks fine. It is not necessary to handle WM_QUIT and I am certain that message never makes it to the window. At minimum I always handle WM_CLOSE and WM_DESTROY (my WM_CLOSE generally just calls DestroyWindow() and WM_DESTROY does the cleanup).

Your main loop looks correct

UnregisterClass() is unnecessary. Classes registered by an application are automatically unregistered when that application closes. You can call it and it wont hurt anything but most people dont bother.

Share this post


Link to post
Share on other sites
Your code looks fine,

The only point I would make is that in general I would prefere to use the superseding 'extended' windows functions and structures, they're similar to those you are using but offer more flexibility.

The ones you want to look into are:
WNDCLASSEX (instead of WNDCLASS)
RegisterClassEx (instead of RegisterClass)
CreateWindowEx (instead of CreateWindow)

There is no UnregisterClassEx, just UnregisterClass, and you dont have to make this call anyway as Windows automatically sorts this out for you. The only point in it is if you want to unregister the class before the end of the program but thats a rare occurance and clearly doesnt apply in your case.

Share this post


Link to post
Share on other sites
Quote:
Original post by synth_cat
What exact differences are in the "Ex" functions? Will I ever notice them?

Thanks!


Well thats the thing.. you might not ever need to use them, personally I just do by default (it's worth pointing out that I'm not sure if there actually are any real disadvantages to not using the Ex functions). The Ex functions just add extended functionality to what you can already do, such as setting extended-window-styles, giving a small-icon for windows, etc

Take a look at the msdn docs for more info on them.

I think ultimately the decision rests on whether you need or want this extra 'flexibilty'.
They're not difficult to use however, just an extra parameter here and there.

Share this post


Link to post
Share on other sites
synth_cat,

The 'Ex' functions are the extended functions. Originally Win32 was written for 16-bit code, but now this has been replaced with extended versions for 32 bit applications. Essentially, use the extended functions always, unless none is supplied.

-brad

Share this post


Link to post
Share on other sites
I use the Ex versions. The main advantage is you can specify different icons to use for the large and small versions of your window icon. If you only specify the large one (Which will happen if you don't use the Ex versions), Windows will shrink your large icon (32x32) image to 16x16, which may cause some artifacts. Alternatively, you could display a completely different icon if you wanted.

Share this post


Link to post
Share on other sites
You'll have to use CreateWindowEx if you want to wrap your windows code into a class. So you can pass in the "this" pointer as the last param (then in your static WndProc you handle WM_NCCREATE and record the pointer so you can pass the messages onto your non-static WndProc that actually handles the messages).

I might be misunderstanding you but don't put game logic in your WndProc. Event handling (input, etc) fine but I wouldn't put logic in it.

I basically do this:

while(!done)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
done = true;
SendEvent(QUITTING, 0, 0); // Let everyone know that cares we're shutting down.
}
else
{
//TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

MainGameLoop();
}


I have more in there and tossed in a few generic things just to demostrate. But basically that's how it works. The MainGameLoop handles everything, it's coded by the game not the engine.

Hope this helps.

Share this post


Link to post
Share on other sites
Mike2343

- I don't really want to put my windows code into a class, so I guess that won't be a problem. When I said that I put "game logic" in my WndProc, all I meant was that I use the WM_KEYDOWN event to toggle some globals, more or less. Is that bad practice?

Share this post


Link to post
Share on other sites
Quote:
Original post by synth_cat
Mike2343

- I don't really want to put my windows code into a class, so I guess that won't be a problem. When I said that I put "game logic" in my WndProc, all I meant was that I use the WM_KEYDOWN event to toggle some globals, more or less. Is that bad practice?


Generally speaking using globals is bad practice anyway.
Using the WndProc to handle input via WM_KEYDOWN however is a valid method. [smile]

Share this post


Link to post
Share on other sites
Quote:

Generally speaking using globals is bad practice anyway.


Whoa! That's bad! I use globals all the time (my level editor must have at least forty of them.) Why is using globals dangerous? And what am I supposed to use as an alternative?

What exactly do you mean by "globals" anyway? Does "globals are bad practice" only apply to booleans? The reason I'm asking this is that I use large global arrays in my game, like an array for projectile objects, an array for enemey objects, and even proxy buffers that are dumped into vertex buffers in my drawing procedure so that I don't have to unlock the vertex buffers every single time I want to outline a quad or something.

All these big global arrays are used heavily throughout my code; all of my functions make specific calls to them. Am I going to have to completely restructure my game to keep it safe?

Share this post


Link to post
Share on other sites
Those global arrays etc are all "bad" in the sense ANYTHING can change them. And good luck 3 months from now tracking down the bug that creeps up because you forgot something way deep in your acient code was modifying it too. That should take a few weeks of hunting :)

If you're using an OO language like C++ you should really get a modern book on data structures. All this stuff could be in classes and can easily be passed to each others. So far my engine has 0 globals and one singleton (with it's replacement already coded and in but the old references are going away slowly).

And the way you handle your input is fine. Game logic, to me atleast, normally means stuff like "make enemy do this, drop box here after trigger is hit" not stuff like input ;-)

If you have more questions I'll try and check this thread tomorrow night.

Share this post


Link to post
Share on other sites
Example code:

int WINAPI WinMain(HINSANCE hInstance, HINSTANCE, LPSTR, int)
{
CGame theGame;

// Init
if(!theGame.Init(hInstance))
return -1;

// Run
theGame.Run();

// Cleanup
theGame.Shutdown();
return 0;
}


Then everything is wrapped up in your CGame class. There's an article on My Website which describes how to wrap a window into a class, and use the message procedure nicely without globals.

Another bad thing about globals, is if you do a large project like a game, then you'll end up with hundreds, if not thousands of global variables, which will end up very difficult to keep track of. Is timeTillNextTick the time that the game should next tick? The time the audio should update? What? If you use more specific variable names, then you'll end up with massively long variable names which will just end up as a mess.

Share this post


Link to post
Share on other sites
Thanks, Evil Steve. I guess that does make sense/

However, I have over 14K lines of code I'm working with now. Would it be worth the trouble to convert all of it? And, by the way, isn't an object local to WinMain() pretty much the same thing as a global object anyway?

Share this post


Link to post
Share on other sites
WinMain is a function just like any other function. Just happens to be the entry point (of sorts) for Windows. It's still a local variable.

Not to sound rude but maybe you should read up a bit more on programming before progressing. It's counter-productive in the end to get bogged down in bad design and bugs then to stop and work on something smaller and get the basics down a bit better. I did this same thing and stopped coding (years ago) for about a year. Big waste of time in the end lol.

Share this post


Link to post
Share on other sites
No offense taken; you're definitely right. I guess this is because I am completely self taught and there are a lot of details I miss. I've always steered away from using OOP functionality because I know so little about it and because I'd heard more than once that game programming was supposed to be relatively free of that kind of stuff (excepting DirectX, obviously.) I'm not sure if I'll ever work up the drive to convert _all_ of my code, though...

Share this post


Link to post
Share on other sites

This topic is 4195 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this