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: , , , , , ,

Preparing the Win32 API

Posted in Uncategorized by Patrick on March 25, 2008

I’ve started to learn a little Windows coding using its API today. I’m preparing it for my chat application i’m going to make in C++. Here’s how a typical hello world program looks like when coding in win32. It displays a message box on the screen which says “Hello world”.

Hello world in Win32

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
MessageBox(NULL, TEXT(“Hello world!”), TEXT(“Message”), 0);
return 0;
}

WinMain is the same as the main() function in C and C++ (the entry point of the application).

The hInstance parameter is a handler to the current window. It seems that the second parameter hPrevInstance isn’t used anymore. It was used to keep track of other instances of the same application. Last time it was used was in 16-bit Windows. The parameter is always NULL.

The third parameter szCmdLine takes care of the commands the application is started with.

The last parameter iCmdShow indicates how the program should be displayed, for example if it’s going to be maximized, minimized or hidden.

Chat application

Posted in Uncategorized by Patrick on March 24, 2008

My next project I have in mind, is going to be a chat application in C++. This is project is originally something we’re doing in school and I chose to make an internet chat with a server and a client. I haven’t thought out all the details about the project yet, but I started on it a couple of weeks ago. In the beginning, I had decided to use SDL because it’s easy to use when making graphical applications and it also has SDLnet for networking. My plans has changed however.

In order to implement a GUI, I decided to use the Win32 API together with C++. I know from experience that Win32 coding is quite nasty and extremely hard, so I hope i’ll pull it off somehow.