First Windows Application


By RoD
The following code is a build up on the basic "hello world" program I showed you earlier. Take a minute to review it, maybe even key it into your compiler and run it, and then we will break it down so that it is easier to understand what is actually going on.

/*	Trim fat from windows*/
#define WIN32_LEAN_AND_MEAN	
#pragma comment(linker, "/subsystem:windows")
/*	Pre-processor directives*/
#include "stdafx.h"
#include <windows.h>
/*	Windows Procedure Event Handler*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT paintStruct;
	/*	Device Context*/
	HDC hDC; 
	/*	Text for display*/
	char string[] = "Hello, World!"; 
	/*	Switch message, condition that is met will execute*/
	switch(message)
	{
		/*	Window is being created*/
		case WM_CREATE: 
			return 0;
			break;
		/*	Window is closing*/
		case WM_CLOSE: 
			PostQuitMessage(0);
			return 0;
			break;
		/*	Window needs update*/
		case WM_PAINT: 
			hDC = BeginPaint(hwnd,&paintStruct);
			/*	Set txt color to blue*/
			SetTextColor(hDC, COLORREF(0x00FF0000));
			/*	Display text in middle of window*/
			TextOut(hDC,150,150,string,sizeof(string)-1);
			EndPaint(hwnd, &paintStruct);
			return 0;
			break;
		default:
			break;
	}
	return (DefWindowProc(hwnd,message,wParam,lParam));
}
/*	Main function*/
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	WNDCLASSEX  windowClass;		//window class
	HWND		hwnd;				//window handle
	MSG			msg;				//message
	bool		done;				//flag saying when app is complete
	/*	Fill out the window class structure*/
	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(WHITE_BRUSH);
	windowClass.lpszMenuName = NULL;
	windowClass.lpszClassName = "MyClass";
	windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
	/*	Register window class*/
	if (!RegisterClassEx(&windowClass))
	{
		return 0;
	}
	/*	Class registerd, so now create window*/
	hwnd = CreateWindowEx(NULL,		//extended style
		"MyClass",			//class name
		"A Real Win App",		//app name
		WS_OVERLAPPEDWINDOW |		//window style
		WS_VISIBLE |
		WS_SYSMENU,
		100,100,			//x/y coords
		400,400,			//width,height
		NULL,				//handle to parent
		NULL,				//handle to menu
		hInstance,			//application instance
		NULL);				//no extra parameter's
	/*	Check if window creation failed*/
	if (!hwnd)
		return 0;
	done = false; //initialize loop condition variable
	/*	main message loop*/
	while(!done)
	{
		PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE);
		if (msg.message == WM_QUIT) //check for a quit message
		{
			done = true; //if found, quit app
		}
		else
		{
			/*	Translate and dispatch to event queue*/
			TranslateMessage(&msg); 
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}
Well isn't this a whole mess of code! The first thing that you may have noticed is #define WIN32_LEAN_AND_MEAN. This syntax prevents Visual C++ from linking modules that you aren't going to need in your application.

Moving on we come to the include line #include <windows.h>. This includes all the headers you need in this application. Sometimes you may want to include <windowsx.h>, which will give you a few useful macros to use in Windows development.

The first function we arrive at is the WndProc function. We've discussed this before, so I am just going to highlight two lines I have added here.
HDC	hDC;				//device context
Char string[] = "Hello World!";	//display text
These two lines are essential as they declare the device context that we are going to use to output to the window we create, and the string that we will display. As we continue on in the code we arrive at the switch statement. This switch is used to determine the message being passed to the windows procedure. In this particular instance we want to take a closer look at the WM_PAINT block.
case WM_PAINT: 
			hDC = BeginPaint(hwnd,&paintStruct);
			/*	Set txt color to blue*/
			SetTextColor(hDC, COLORREF(0x00FF0000));
			/*	Display text in middle of window*/
			TextOut(hDC,150,150,string,sizeof(string)-1);
			EndPaint(hwnd, &paintStruct);
			return 0;
			break;
When the window is moved, resized, or is otherwise changed the window needs to be updated. The first noticeable change here is the use of the hDC device context. The win32 function BeginPaint() returns the graphics device context for the hwnd passed to it. You can then use this hDC to set the text color with SetTextColor() and follow up with the TextOut() function to display the text. If you want to know more about these functions, check out MSDN.

Next function up is the WinMain() function. Most of the WinMain() content is pretty straight forward, but were going to review a few parts of it for good measure. The msg variable holds the message received by PeekMessage() from the queue, and will be sent to TranslateMessage() and DispatchMessage(). The variable done is a Boolean value used by your message loop and will not equal true until a WM_QUIT message has been received from the queue to indicate that the application is about to be closed.

For easier understanding we will break the order of each setup task into a list.
1.	Window-class setup
2.	Window-class registration
3.	Window Creation
4.	Message loop with event handler
We now have a fully working Windows application! I encourage you to toy around with the code and alter it to your liking. Don't be discouraged by errors or problems, for it is these things that make us better.
Happy Coding!


Previous: The WinMain procedure
Next: Introduction to WGL
Back to OpenGL tutorial index