The sample application for this source code is a very simple program that
basically just pops up a window and provides feedback as to what messages were
processed when certain events occur. You should download and run the program to
see how it works and what this tutorial is working towards showing you. Before
we can actually create a window, there are a few steps that we must take, but
even before that -- let's take a quick look at WinMain.
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int Cmd) {
MSG msg;
... // other initialization code;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
|
WinMain is called by the system when our program is first run. It's the starting
point of our application. The first parameter is the handle to the instance of
our application. The second parameter will always be NULL for our purposes. The
third parameter is a string pointer to the command line. The last parameter
specifies a show state (there are several values that start with "SW_" that you
can look up in the help files). We will look at the other initialization code in
a moment, but take a look at the while block. GetMessage gets a message
from our thread's message queue and puts it into our MSG
variable. The only time GetMessage returns 0 is when it receives a WM_QUIT message.
You can use GetLastError to get error information if GetMessage returns
an error (-1). Otherwise its return will be non-zero. The GetMessage parameters provided
say that we want to retrieve any type of message available.
The message is received into the msg variable which is then used by TranslateMessage to
translate special keyboard messages into messages that are sent to the thread's message queue (you don't
really need to worry about what this means right now). DispatchMessage then sends the message
to the proper window procedure. Our window procedure is a special function that will process all of
our messages. Note: there is a function called PeekMessage you can look up on your own time.
Its quite useful because it returns (boolean) immediately instead of waiting around for a message
like GetMessage does. It has its advantages, but I won't discuss them here.
Now lets see how we go about actually creating our window.
First we need to register the window class. This would happen somewhere in the
"other initialization code" section I left out of the WinMain above. Our window
class can be registered via code such as:
// Setup and register the window class;
WNDCLASS wClass;
wClass.style =CS_HREDRAW|CS_VREDRAW;
wClass.lpfnWndProc =WindowProcedure; // callback function;
wClass.cbClsExtra =0;
wClass.cbWndExtra =0;
wClass.hInstance =hInstance;
wClass.hIcon =LoadIcon(hInstance,IDI_APPLICATION);
wClass.hCursor =LoadCursor(NULL,IDC_ARROW);
wClass.hbrBackground =(HBRUSH)(COLOR_WINDOW+3);
wClass.lpszMenuName =NULL;
wClass.lpszClassName =WINDOWNAME;
RegisterClass(&wClass);
|
The WNDCLASS structure contains window class attributes for the window we plan
on creating. For a complete description and listing of all the available
constants, read the help files that came with your compiler. (Word to the wise:
Throughout your days of Windows coding, you will most likely be dealing with
MANY constants, api calls, and things of this nature. Be sure to familiarize
yourself with the help files. They're extremely useful when you're learning the
way things work and as a general reference.) I'll briefly try to explain what
each member means:
style
|
Specifies the class style. CS_HREDRAW and CS_VREDRAW mean that our window
will redraw whenever our window is moved or resized horizontally or vertically.
|
lpfnWndProc
|
Specifies our window's 'window procedure', which handles the messages that
are sent to it. We'll see more on that later.
|
cbClsExtra
|
Amount of extra space (in bytes) to allocate for the class structure.
|
cbWndExtra
|
Amount of extra space (in bytes) to allocate for the window structure.
|
hInstance
|
Instance handle.
|
hIcon
|
Handle to an icon (use a resource handle)
|
hCursor
|
Handle to a cursor (use a resource handle)
|
hbrBackground
|
Handle to a brush to use as the class background. There are several "COLOR_"
HBRUSH values you can look up in the help files.
|
lpszMenuName
|
Pointer to a string that holds the menu name (from a resource). We aren't
using a menu for this example program.
|
lpszClassName
|
Pointer to a string that specifies our class name. WINDOWNAME is #defined
elsewhere in the program as "Simple Sample Application".
|
After setting up our WNDCLASS structure, we register our class by using RegisterClass which
registers our window class so we can use CreateWindow to actually create our window such
as the following code does.
// Create the window and store the handle;
hWnd = CreateWindow(WINDOWNAME, // class name;
WINDOWNAME, // window name;
WS_OVERLAPPEDWINDOW, // window style;
CW_USEDEFAULT, CW_USEDEFAULT, // starting position (x,y);
320, 240, // width and height;
NULL, // parent handle;
NULL, // menu handle;
hInstance, // instance handle;
NULL); // other parameters;
// Check if window creation failed; otherwise show and update;
if(hWnd==NULL) return FALSE;
else {
ShowWindow (hWnd, Cmd);
UpdateWindow(hWnd);
}
|
The parameters should be fairly self explanatory (again, all the values for
things such as 'window style' can be located in the help files), but I'll
quickly explain them. The first parameter is the class name that we registered
earlier. The second parameter is the window name -- which will show up in our
window caption. The next parameter is the window style, which in our case is
WS_OVERLAPPEDWINDOW. There are many combinations of styles you can use, but
you'll have to look up all the values in the help file because there are too
many for me to list here. The next two parameters specify the starting position
of the window (horizontally and vertically). CW_USEDEFAULT just means to use the
default position. The next two parameters specify the window's width and height
respectively. The next parameter is the handle to a parent window. If our window
was a child or owned window, we'd set this parameter to the parent window
handle. Next up is a menu handle, but we're not using a menu so it's NULL. The
next-to-last parameter is our instance handle and the last parameter is a
pointer to other data to be sent to the window. After creating the window, you
should usually check if the returned handle is valid then call ShowWindow
and UpdateWindow which will set our window's show state and then
tell it to repaint itself.
Now we would have a functioning window on our screen as shown below:
But don't think we're done just yet. We still need to write the window procedure
which is how we make our seemingly useless and pointless window respond to some
events. |