Patrick’s development blog

Win32 API – Creating a window

Posted in Uncategorized by Patrick on March 29, 2008

Thing aren’t exactly going fast forward with this project or learning about the Win32 API, due to my lack of motivation of reading stuff. I’ve managed to take my time to finish the application window for today at least. This is the complete code.

Create an application window

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Simple Window");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = szAppName;

if (!RegisterClass(&wndclass)) {
    MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
    return 0;
}

hwnd = CreateWindow(szAppName,
TEXT("Simple Application Window"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;

switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &rect);

DrawText(hdc, TEXT("Hello world!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd, &ps);

return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hwnd, message, wParam, lParam);

}

It’s a lot of code to explain, so i’ll try to cover the most relevant parts of the code in this post.

The window class
All kinds of windows and “controls” like buttons and check boxes are based on a certain window class. In my program above, this class is instantiated to use for the window. The window procedure that processes messages to the window is identified by the window class.

In my program, you can see that WNDCLASS wndclass; is definied in the WinMain function. This class/structure has to be registered using a call to RegisterClass after all fields of the structure are initialized.

Window class definition

WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName;

wndclass.style definies how the window should be created. The flags I specified in this example makes sure the program repaints every time the window is resized either horizontal or vertical. (CS_HREDRAW | CS_VREDRAW)

wndclass.lpfnWndProc This field sets the window procedure for this class (WndProc). The window procedure is the functon that handles all the messages. This window procedure will now process messages to all windows based on this class.

wndclass.cbClsExtra = 0, wndclass.cbWndExtra = 0
These fields are used internally to maintain some space, I have no idea what. All I know is that this program doesn’t use this extra space.

wndclass.hInstance = hInstance this line sets the instance of the program. It’s the same as the parameter.

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION)
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW)
These lines sets the icon and cursor type. Since I call these functions with the first parameter as NULL, a predetermined icon will be choosed.

wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
The background of the application will become white.

wndclass.lpszMenuName = NULL
I don’t use a menu in this program so I set this value to NULL. I’ll most likely become familiar with this later though, let’s save it for that time.

wndclass.lpszClassName
Last but not least, the application name. In this case, the name is of the type TCHAR.

This instance has to be registered as well.

Register the window class

if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Show some error message"), szAppName, MB_ICONERROR); return 0; }

After we’ve registered the window class, the actual window creation code comes into play. HWND hwnd definied at the top of the “main” function is a handle to the window. The created window will be saved into this variable.

Create the actual window

hwnd = CreateWindow(szAppName, TEXT("Simple Application Window"), WS_OVERLAPPEDWINDOW, 200, 250, 640, 480, NULL, NULL, hInstance, NULL);

The above example will simply create a window with a size of 640×480 pixels at the start position (200,250).

Right now, the window has only been created internally in Windows. In order to make the window appear on the video display, it’s necessary to make a call to ShowWindow and UpdateWindow.

Display window

ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd);

Like usual, it’s nothing really that’s necessary to memorize. It’s good to know though, that hwnd is the window handler we just created using CreateWindow and iCmdShow is used to keep track of the current state of the window (maximized, minimized, etc). ShowWindow shows the window on the screen, it sends the WM_PAINT message to the window procedure.

The last part of the application that makes it complete, is the event handling. Before going on to the window procedure, a while loop that retrieves all the messages from the message queue is necessary.

Retrieve all messages

while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

Where msg is a part of the MSG structure and the NULL parameters indicate that we want to retrieve ALL messages for this program. The DispatchMessage() function call sends the message to the window procedure. It’s the windows procedure that takes care of the actual event checking.

The window procedure

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); DrawText(hdc, TEXT("Hello world!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }

This is where we take care of the input and what actions that we take depending on which message we get. There isn’t much to explain about this code without going into too much background. The last return statement that returns the DefWindowProc(…) call, is the default processing of all messages that the window procedure doesn’t process. It’s important to remember.

The WM_PAINT code block is executed whenever the window is updated. In other words, it’s the code that displays the text on the screen. I won’t go into detail how it draws the text right now, because I honestly have no idea right now and I want this post to end.

Advertisements
Tagged with: , , , , , ,

6 Responses

Subscribe to comments with RSS.

  1. Nick M said, on August 17, 2008 at 12:44 pm

    Great information, many thanks.

  2. reswag said, on February 13, 2009 at 4:51 pm

    Very useful. Thanks for posting this.

  3. Darrick said, on February 21, 2009 at 10:45 pm

    It’s been so difficult to find a clean example of basic windows code. As I’m just starting to learn this, your posts have been very helpful.

    Thankyou for taking the time to put these up.

    I wish you luck in your endeavors.

  4. Yeoh HS said, on May 7, 2009 at 9:30 am

    Nice work. Keep it up.

  5. Greg said, on August 25, 2009 at 5:56 pm

    Useless.
    Just read the Petzold and MSDN (15 years old doc to create a window !!!)

  6. Patrick said, on August 25, 2009 at 6:43 pm

    Greg:
    Well yes, though the Windows API itself is useless.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: