Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
88 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Introduction
 Error Handling
 Win32 Skeleton
 Message Handler
 Conclusion

 Source code
 Printable version

 


  The Series

 Part I
 Part II

 

The Win32 Skeleton

Many game programmers I know don't really bother learning the basics of Windows programming. They just copy-paste an existing skeleton the got from someone else and write their game on top of it. Even though there is nothing really wrong with that, you will be limited by the skeleton. I'm not going to teach you much about the Win32 API, but I'll teach you enough to put you on the right track to create windows the way you want them to appear.

char szClassName [] = "Chapter2"; char szWinName [] = "Chapter2"; LRESULT CALLBACK WndProc(HWND,UINT, WPARAM, LPARAM);

The first two variables are the class name and window name. We'll use these in a minute. The function prototype is for handling messages (more on this later).

For any DOS or Unix programmer, your C/C++ program always starts with void main (), or if you want command line arguments void main (int argc, char *argv[ ]). In Windows it starts with WinMain, which has a few more parameters than you may like. You must also include windows.h in your files.

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hWnd; WNDCLASSEX wcl; bool bRunning; ZeroMemory (&wcl, sizeof (WNDCLASSEX)); wcl.cbSize = sizeof (WNDCLASSEX); wcl.hInstance = hInst; wcl.lpszClassName = szClassName; wcl.lpfnWndProc = WndProc; wcl.style = 0; wcl.lpszMenuName = NULL; wcl.cbClsExtra = NULL; wcl.cbWndExtra = NULL; wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wcl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wcl.hCursor = LoadCursor (NULL, IDC_ARROW); wcl.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);

The return type of WinMain is int APIENTRY. This is the way Windows handles specific Win32 API entries. We will also use LRESULT CALLBACK but that's a completely different story. We then have four parameters. The first one is the current instance of the program. The second one is the previous instance, but it's not used in Windows 95 or later, so you can just ignore it. The third parameter is an array of strings containing the command line arguments; all arguments are separated with a blank character and, as opposed to DOS/Unix, it doesn't include the executable name as the first parameter. The last parameter is how the Window will show in default mode.

We need another couple of variables. The first is the message to be processed, the second is the handle for the window, and the third one is where we will hold the window class information. The variable bRunning will tell us if the game is running or not.

We then set up our window class. The variable names are quite easy, so I'll just cover the not so obvious ones. cbSize is needed to let Windows know the size of the class when registering. lpfnWndProc is the message handler. cbClsExtra and cbWndExtra are extra properties of the class, which in this case are set to nothing.

if (!RegisterClassEx(&wcl)) { ErrorHandling.ProcessError (ERROR_REGISTER_CLASS); return (-1); }

We then try to register the class and if an error ocurrs we call our error handling routine and log it. You need to add #define ERROR_REGISTER_CLASS 1 to Error.h and the following piece of code to ProcessError just before default:.

case ERROR_REGISTER_CLASS : dwMsgSize = strlen ("Chapter 2 - Error log file\nCould'nt register class...\n"); lpzMessage = (LPSTR) malloc (dwMsgSize + 1); strcpy (lpzMessage, "Chapter 2 - Error log file\nCould'nt register class...\n"); break;

This will add the "Couldn't register class" error.

Back to WinMain, we need to create our window and show it. We set the class name, window name, type of window (WS_OVERLAPPEDWINDOW is the standard window with a title bar, minimize/maximize box and close box), and position and size (0,0, 640,480). We set the parent as the desktop, supply no menu, use the current instance and use NULL as the last parameter (advanced functions).

hWnd = CreateWindow (szClassName, szWinName, WS_OVERLAPPEDWINDOW, 0 , 0, 640, 480, HWND_DESKTOP, NULL, hInst, NULL); ShowWindow(hWnd, nCmdShow);

And finally we get to the last part of WinMain. We create a loop normally referred to as the message loop. The important thing you need to know is that it receives input from you or the Windows system and sends it to your message handler.

while (bRunning) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { bRunning = false; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } return 0; }

We finally return 0 to let the program know that we're done.

Is that it? No, we still need the message handler J.




Next : The Message Handler