#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PTSTR cmdline,
int cmdshow)
{
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
return DefWindowProc(hwnd, wm, wp, lp);
}
The first thing one sees are the two macro definitions, UNICODE
and _UNICODE
. These macros cause our program to understand wide character strings (wchar_t[n]
), not plain narrow strings(char[n]
). As a result, all string literals must be wrapped in a TEXT(
macro. The generic character type for Win32 strings is TCHAR
, whose definition depends on whether or not UNICODE
is defined. A new header is included: <tchar.h>
contains the declaration of TCHAR
.
A window consists of what is known as a window class. This describes information about a window that is to be shared between instances of it, like the icon, the cursor, and others. A window class is identified by a window class name, which is given in the CLSNAME
global variable in this example. The first act of WinMain
is to fill in the window class structure, WNDCLASSEX wc
. The members are:
cbClsExtra
, which is common to all instances. This is often 0.hInst
argument in WinMain
to this field.LoadIcon(NULL, IDI_APPLICATION)
loads the default application icon.LoadCursor(NULL, IDC_ARROW)
loads the default cursor.GetStockObject (WHITE_BRUSH)
gives a handle to a white brush. The return value must be cast because GetStockObject
returns a generic object.CLSNAME
global variable stores the window class name.After this structure is initialized, the RegisterClassEx
function is called. This causes the window class to be registered with Windows, making it known to the application. It returns 0 on failure.
Now that the window class has been registered, we can display the window using CreateWindowEx
. The arguments are:
WNDCLASSEX::lpszClassName
. The class menu is common to all instances of windows with the same class name. This argument, however, is specific for just this instance. If the window being created is a child window, then this is the ID of the child window. In this case, we are creating a parent window with no menu, so NULL is passed.If x
or y
or cx
or cy
is CW_USEDEFAULT
, then that argument's value will be determined by Windows. That is what is done in this example.
CreateWindowEx
returns the handle to the newly created window. If window creation failed, it returned NULL
.
We then show the window by calling ShowWindow
. The first argument for this function is the handle to the window. The second argument is the show style, which indicates how the window is to be displayed. Most applications just pass the cmdshow
argument passed in WinMain
. After the window is shown, it must be updated by a call to UpdateWindow
. It causes an update message to be sent to the window. We will learn what this means in another tutorial.
Now comes the heart of the application: The message pump. It pumps messages sent to this application by the operating system, and dispatches the messages to the window procedure. The GetMessage
call returns non-zero until the application receieves a messages that causes it to quit, in which case it returns 0. The only argument that concerns us is the pointer to an MSG
structure that will be filled in with information about the message. The other arguments are all 0.
Inside the message loop, TranslateMessage
translates virtual-key messages into character messages. The meaning of this, again, is unimportant to us. It takes a pointer to an MSG
structure. The call directly following it, DispatchMessage
, dispatches the message pointed to by its argument to the window's window procedure. The last thing WinMain
must do is return a status code. The wParam
member of the MSG
structure contains this return value, so it is returned.
But that's just for the WinMain
function. The other function is winproc
, the window procedure. It will handle messages for the window that are sent to it by Windows. The signature for winproc
is:
wm
argumentwm
argument. This argument is usually used to transmit pointers or handlesIn this simple program, we do not handle any messages ourselves. But that doesn't mean Windows doesn't either. This is why one must call DefWindowProc
, which contains default window handling code. This function must be called at the end of every window procedure.
HWND
returned by CreateWindowEx
.
LoadIcon
or LoadImage
(LoadIcon in this example).LoadIcon
or LoadImage
(LoadIcon in this example).MessageBox
to display an error icon.CreateWindowEx
's x
, y
, cx
, or cy
arguments. Causes Windows to choose a valid value for the argument for which CW_USEDEFAULT
was passed.UNICODE
is defined, this is a wchar_t
. Otheriwse, it is a char
.W
prefix). With the introduction of Win32, however, this is now a UINT_PTR
. This illustrates the point of these Windows aliases; they are there to protect programs from change.LONG
argument (LONG_PTR
in Win64).P
means pointer. The T
means generic character, and the STR
means string. Thus, this is a pointer to a TCHAR
string. Other string types include:
PTSTR
const TCHAR *
LPCTSTR
wchar_t *
)const wchar_t *
LPWSTR
L
).