Creating a window is as easy as calling the CreateWindow function.
What you may not be accustomed to is the idea of an operating system making calls to a program. Yet this is fundamental to Windows' architecture.
Every window that a program creates has an associatedwindow procedure. This window procedure is a function that could be either in the program itself or in a dynamic-link library. Windows sends a message to a window by calling the window procedure. The window procedure does some processing based on the message and then returns control to Windows.
A window is an object. The code is the window procedure. The data is information retained by the window procedure and information retained by Windows for each window and window class that exists in the system.
Hello.c
/*------------------------------------------------------------
HELLOWIN.C -- Displays "Hello, Windows 98!" in client area
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#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 ("HelloWin") ;
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, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, SW_SHOWMAXIMIZED) ;
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_CREATE:
PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, TEXT ("Hello, Windows 98!"), -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) ;
}
//
HINSTANCE
Handle to an "instance"—the program itself
HWND
Handle to a window
HDC
Handle to a device context
A handle is simply a number (usually 32 bits in size) that refers to an object.
The message loop
Windows maintains a "message queue" for each windows program currently running under Windows. When an input event occurs,Windows translates the event into a "message" that it places in the program's message queue.
A program retrieves these messages from the message queue by executing a block of code known as the "message loop".
The Window Procedure
The real action occurs in the window procedure. The window procedure determines what the window displays in its
client area and how the window responds to user input.
A window procedure is always associated with a particular window class that you register by
calling RegisterClass.
The Windows Programming Hurdles
In HELLOWIN, WinMaincontains only program overhead necessary to register the window class, create the window, and retrieve and dispatch messages from the message queue.
Programmers are well acquainted with the idea of calling on the operating system to do something. For example,
C programmers use the fopenfunction to open a file. The fopenfunction is implemented with a call to the
operating system to open a file. No problem
But Windows is different. Although Windows has a couple thousand function calls, Windows also makes calls to
yourprogram, specifically to the window procedure we have called WndProc.
All these calls to WndProcare in the form of messages. In most Windows programs, the bulk of the program is
dedicated to handling these messages. The messages that Windows can send to a program are generally identified
with names that begin with the letters WM and are defined in the WINUSER.H header file.
Queued and Nonqueued Messages
and then route these messages to some location(GetMessage,DispatchMessage)? Or does it receive messages directly from outside the program?Well, both.
Messages can be either "queued" or "nonqueued."
The queued messages are those that are placed in a program's message queue by Windows. In the program's message loop, the messages are retrieved and dispatched to the window procedure.
The nonqueued messages are the results of calls by Windows directly to the window procedure.
It is said that queued messages are "posted" to a message queue and that nonqueued messages are
"sent" to the window procedure. In any case, the window procedure gets all the messages—both queued and
nonqueued—for the window. The window procedure is "message central" for the window.
The queued messages are primarily those that result from user input in the form of keystrokes.
The nonqueued messages are everything else. Nonqueued messages often result from calling certain Windows
functions. For example, when WinMaincalls CreateWindow, Windows creates the window and in the process sends
the window procedure a WM_CREATE message.
Although Windows programs can have multiple threads of execution, each thread's message queue handles
messages for only the windows whose window procedures are executed in that thread. In other words,the
message loop and the window procedure do not run concurrently. When a message loop retrieves a message from
its message queue and calls DispatchMessageto send the message off to the window procedure,DispatchMessage
does not return until the window procedure has returned control back to Windows.
However, the window procedure could call a function that sends the window procedure another message, in which
case the window procedure must finish processing the second message before the function call returns, at which
time the window procedure proceeds with the original message. For example, when a window procedure calls
UpdateWindow, Windows calls the window procedure with a WM_PAINT message. When the window procedure
finishes processing the WM_PAINT message, the UpdateWindowcall will return controls back to the window
procedure.
This means that window procedures must be reentrant. In most cases, this doesn't cause problems, but you
should be aware of it. For example, suppose you set a static variable in the window procedure while processing a
message and then you call a Windows function. Upon return from that function, can you be assured that the
variable is still the same? Not necessarily—not if the particular Windows function you call generated another
message and the window procedure changes the variable while processing that second message. This is one of the
reasons why certain forms of compiler optimization must be turned off when compiling Windows programs