Saturday, August 2, 2008

c++ Windows Programing - Creating a window

This tutorial will cover how to create a window. If you haven't already you should read the Hello World tutorial for Windows Programming first.

In the last tutorial I described how to create a windows program that displays a message box. We are going to extend on that tutorial and create a window this time.

This will consists of 4 parts.

1. Register a new windows class (not to be confused with a c++ class)
2. Create the window
3. Display the window
4. Process Events.

Part 1. Registering a new window class

The first step is to fill in a windows structure that describes how your new window will look like. We'll use the WNDCLASSEX structure.


WNDCLASSEX wc;

// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));

// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"MyClass";

RegisterClassEx(&wc);

We first declare a new instance and zero out the memory of the instance. We then set appropriate parameters to define how the window will look. For full details on the paremeters you should consult msdn.

The lpfnWndProc is an important property. This defines a function that will be called back whenever this window needs to handle a message. We'll discuss more abot this in Part 4.

Part 2. Creating the window.

Now that we've defined the style of how our new window should look, we want to actually create the window. We'll use the CreateWindowEx function which has the following prototype:


HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);


Part 3: Display the Window

Displaying the window is accomplished by calling ShowWindow which has the prototype:


BOOL ShowWindow(
HWND hWnd,
int nCmdShow
);


Part 4: Processing Events

We now have the parts to describe the style of a window, register it, create it, and display it. But if we don't process the windows events nothing will happen. Remember lpfnWndProc from Part 1?

We must define that call back method. Anytime a message is received it will need to run through that method.

So first we need to get message off the messaging queue than define our callback.


// this struct holds Windows event messages
MSG msg;

// wait for the next message in the queue, store the result in 'msg'
while(GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);

// send the message to the WindowProc function
DispatchMessage(&msg);
}




// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}

// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}



Conclusion:

Putting it all together we have a program that looks like this:


#include
#include

LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
//Our window structure.
WNDCLASSEX wc;
ZeroMemory(&wc,sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_3DSHADOW;
wc.lpszClassName = L"WindowClass1";

RegisterClassEx(&wc);

// create the window and use the result as the handle
HWND hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL

ShowWindow(hWnd,nCmdShow);

MSG msg;
while(GetMessage (&msg,NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}

No comments: