PART I  GETTING STARTED
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Chapter 1  Hello, Windows
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Since its introduction in November 1985, Microsoft Windows has emerged as
the most popular graphical user interface environment for MS-DOS. Several
million copies of Windows have been shipped, and hundreds of Windows
applications are currently available.

For the user, Windows provides a multitasking graphical-based windowing
environment that runs programs especially designed for Windows. Such
programs include Microsoft Excel (spreadsheet and business graphics),
Microsoft Word for Windows (word processing), Aldus's PageMaker (desktop
publishing), Samna's Ami (word processing), Micrografx's Designer (drawing),
IBM's Current (a personal information manager), Asymetrix's ToolBook (a
software construction kit), and many others. Programs written for Windows
have a consistent appearance and command structure, and are thus often
easier to learn and use than conventional MS-DOS programs. Users can easily
switch among different Windows programs and exchange data between them.
Windows also provides an easy-to-use icon-based Program Manager for running
programs as well as a File Manager and Print Manager for file maintenance
and printer-queue management.

Although Windows exists primarily to run applications especially written for
the environment, Windows can also run many programs written for MS-DOS. Of
course, these programs cannot take advantage of many Windows features, but
in some cases they can be windowed and multitasked alongside Windows
programs.

For the program developer, Windows provides a wealth of built-in routines
that allow the use of menus, dialog boxes, scroll bars, and other components
of a friendly user interface. Windows also contains an extensive graphics
programming language that includes the use of formatted text in a variety of
fonts. Programmers can treat the keyboard, mouse, video display, printer,
system timer, and RS-232 communication ports in a device-independent manner.
Windows programs run the same on a variety of hardware configurations.

The "look and feel" of Windows also shows up in the OS/2 Presentation
Manager. OS/2 is the protected mode operating system developed by
International Business Machines Corporation (IBM) and Microsoft Corporation
as a successor to MS-DOS; the graphical user interface under OS/2 is called
the Presentation Manager. While the application program interfaces of
Windows and the OS/2 Presentation Manager are not the same, they have many
similarities and common structural elements.

A BRIEF HISTORY OF WINDOWS

Windows was announced by Microsoft Corporation in November 1983 and released
two years later in November 1985. Over the next two years, Windows 1.01 (the
first released version) was followed by several updates to support the
international market and to provide drivers for additional video displays
and printers.

Windows 2.0 was released in November 1987. This version incorporated several
changes to the user interface to make it consistent with the forthcoming
OS/2 Presentation Manager (released in October 1988). The most significant
of these changes involved the use of overlapping windows rather than the
"tiled" windows found in the earlier versions of Windows. Windows 2.0 also
included enhancements to the keyboard and mouse interface, particularly for
menus and dialog boxes.

Windows/386 (released shortly after Windows 2.0) used the Virtual-86 mode of
the 386 microprocessor to window and multitask many DOS programs that
directly access hardware. For symmetry, Windows 2.1 was renamed Windows/286.

Windows 3--the subject of this book--was introduced in a spectacular product
announcement on May 22, 1990. The earlier Windows/286 and Windows/386
versions have been merged into one product with this release. The big change
in Windows 3 is the support of the protected mode operation of Intel's 80286
and 80386 microprocessors. This gives Windows and Windows applications
access to up to 16 megabytes of memory. The Windows "shell" programs (the
Program Manager, Task Manager, and File Manager) have been completely
revamped.


THE USER'S PERSPECTIVE

Windows provides considerable advantages to both users and programmers over
the conventional MS-DOS environment. The benefits to users and the benefits
to program developers are really quite similar, because the job of a program
developer is to give users what they need and want. Windows makes this
possible.

The Graphical User Interface (GUI)

Windows is a graphical user interface (GUI), sometimes also called a "visual
interface" or "graphical windowing environment." The concepts behind this
type of user interface date from the mid-1970s, with the pioneering work
done at the Xerox Palo Alto Research Center (PARC) for machines such as the
Alto and the Star and for environments such as Smalltalk.

The work done at Xerox PARC was brought into the mainstream and popularized
by Apple Computer, Inc., first in the ill-fated Lisa and then a year later
in the much more successful Macintosh, introduced in January 1984. The Apple
Macintosh remains a significant challenger to IBM's dominance in the
personal-computer business market. It is not so much the hardware of the
Macintosh but its operating system that makes the machine so appealing to
users. The Mac is simply easier to use and learn than an IBM PC running
MS-DOS.

Since the introduction of the Macintosh, graphical user interfaces have
bloomed like wildflowers throughout the personal-computer industry and the
not-so-personal computer industry as well. For IBM-compatibles running
MS-DOS, there is Windows. For IBM-compatibles running OS/2, there is the
Presentation Manager. For the Commodore Amiga, there is Intuition. For the
Atari, there is GEM. For machines running UNIX, there is the X-Window
system. For Sun Microsystems workstations, there is NeWS. For the NeXT,
there is NextStep.

It is obvious that the graphical user interface is now (in the words of
Microsoft's Charles Simonyi) the single most important "grand consensus" of
the personal-computer industry. Although the various graphical environments
differ in details, they have similar characteristics.


GUI Concepts and Rationale

All graphical user interfaces make use of graphics on a bitmapped video
display. Graphics provides better utilization of screen real estate, a
visually rich environment for conveying information, and the possibility of
a WYSIWYG (what you see is what you get) video display of graphics and
formatted text prepared for a printed document.

In earlier days, the video display was used solely to echo text that the
user typed using the keyboard. In a graphical user interface, the video
display itself becomes a source of user input. The video display shows
various graphical objects in the form of icons and input devices such as
buttons and scroll bars. Using the keyboard (or, more directly, a pointing
device such as a mouse), the user can directly manipulate these objects on
the screen. Graphics objects can be dragged, buttons can be pushed, and
scroll bars can be scrolled.

The interaction between the user and a program thus becomes more intimate.
Rather than the one-way cycle of information from the keyboard to the
program to the video display, the user directly interacts with the objects
on the display.


The Consistent User Interface

Users no longer expect to spend long periods of time learning how to use the
computer or mastering a new program. Windows helps because all Windows
programs have the same fundamental look and feel. The program occupies a
window--a rectangular area on the screen. It is identified by a caption bar.
Most program functions are initiated through the program's menu. Figure 1-1
shows a typical Windows program (in this case Write, the word processor
included in Windows) with the various window components labeled.

Some menu items invoke dialog boxes, in which the user enters additional
information. One dialog box found in almost every large Windows program
opens a file. (See Figure 1-2.) This dialog box looks the same (or very
similar) in many different Windows programs, and it is almost always invoked
from the same menu option.

Once you know how to use one Windows program, you're in a good position to
easily learn another. The menus and dialog boxes allow a user to experiment
with a new program and explore its features. Most Windows programs have both
a keyboard interface and a mouse interface. Although most functions of
Windows programs can be controlled through the keyboard, using the mouse is
often easier for many chores.

  (Figure 1-1. may be found in the printed book.)

  (Figure 1-2. may be found in the printed book.)

From the programmer's perspective, the consistent user interface results
from using the routines built into Windows for constructing menus and dialog
boxes. All menus have the same keyboard and mouse interface because Windows,
rather than the application program, handles this job.


The Multitasking Advantage

Although some people continue to question whether multitasking is really
necessary on a single-user computer, users definitely are ready for
multitasking and can benefit from it. The popularity of MS-DOS RAM-resident
programs such as Sidekick proves it. Although popups are not, strictly
speaking, multitasking programs, they do allow fast context switching. This
involves many of the same concepts as multitasking.

Under Windows, every program in effect becomes a RAM-resident popup. Several
Windows programs can be displayed and running at the same time. Each program
occupies a rectangular window on the screen, as shown in Figure 1-3 on the
following page. The user can move the windows around on the screen, change
their size, switch between different programs, and transfer data from one
program to another. Because this display looks something like a desktop (in
the days before the desk became dominated by the computer itself, of
course), Windows is sometimes said to use a "desktop metaphor" for the
display of multiple programs.

  (Figure 1-3. may be found in the printed book.)


Memory Management

An operating system cannot implement multitasking without doing something
about memory management. As new programs are started up and old ones
terminate, memory can become fragmented. The system must be able to
consolidate free memory space. This requires the system to move blocks of
code and data in memory.

Even Windows 1, running on an 8088 microprocessor, was able to perform this
type of memory management. Under real mode, this can only be regarded as an
astonishing feat of software engineering. Programs running under Windows can
overcommit memory; a program can contain more code than can fit into memory
at any one time. Windows can discard code from memory and later reload the
code from the program's .EXE file. A user can run several copies (called
"instances") of a program; all these instances share the same code in
memory. Programs running in Windows can share routines located in other .EXE
files called "dynamic link libraries." Windows includes a mechanism to link
the program with the routines in the dynamic link libraries at run time.
Windows itself is a set of dynamic link libraries.

Thus, even in Windows 1, the 640-KB memory limit of the PC's architecture
was effectively stretched without requiring any additional memory. But
Microsoft didn't stop there: Windows 2 gave the Windows applications access
to expanded memory (EMS), and Windows 3 runs in protected mode to give
Windows applications access to up to 16 megabytes (MB) of extended memory.


The Device-Independent Graphics Interface

Windows is a graphical interface, and Windows programs can make full use of
graphics and formatted text on both the video display and the printer. A
graphical interface is not only more attractive in appearance, but it can
also impart a high level of information to the user, as you can see in
Figure 1-4.

Programs written for Windows do not directly access the hardware of graphics
display devices such as the screen and printer. Instead, Windows includes a
graphics programming language (called the Graphics Device Interface, or GDI)
that allows the easy display of graphics and formatted text. Windows
virtualizes display hardware. A program written for Windows will run with
any video board or any printer for which a Windows device driver is
available. The program does not need to determine what type of device is
attached to the system.

Putting a device-independent graphics interface on the IBM PC was not an
easy job for the developers of Windows. The PC design was based on the
principle of open architecture. Third-party hardware manufacturers were
encouraged to develop peripherals for the PC and have done so in great
number. Although several standards have emerged, conventional MS-DOS
programs for the PC must individually support many different hardware
configurations. For example, it is fairly common for an MS-DOS
word-processing program to be sold with one or two disks of small files,
each one supporting a particular printer.

  (Figure 1-4. may be found in the printed book.)

Windows programs do not require these drivers because the support is part of
Windows. This benefits users because most Windows programs require very
little in the way of installation. Everything a program needs can be
included in the program's single .EXE file. The user can often copy the .EXE
file to the fixed disk, load Windows, and go.


MS-DOS Applications

Although Windows primarily exists to run new programs specifically designed
for the environment, Windows can also run many non-Windows MS-DOS programs.
The Windows User's Guide refers to these as "standard applications," but
many Windows programmers call them "old applications" or "old apps."

These MS-DOS programs can be divided into two broad categories: Well-behaved
applications (or "good old apps") are those that use the MS-DOS and PC ROM
BIOS (basic input/output system) software interrupts to read the keyboard
and write to the video display. These programs can generally run in a
window.

"Bad apps" are those that write directly to the video display, use graphics,
or take control of the hardware keyboard interrupt. The term "bad" here
refers not to the quality of the program--many of the best programs written
for the PC are bad apps when it comes to Windows--but to the way in which
the program uses the hardware of the PC. When running on a 286-based
machine, there is simply no way Windows can allow such a program to be
windowed or multitasked. However, Windows can use the "virtual 86" mode of
the 386 microprocessor to window and multitask even bad applications.



THE PROGRAMMER'S PERSPECTIVE

Windows has the reputation of being easy for users but difficult for
programmers. If you have no prior experience with programming for a
graphical user interface, you should be warned right now that you will
encounter some very strange concepts. Almost every programmer who begins
writing code for Windows must go through some mental reorientation to
assimilate these concepts.

If at first you find Windows programming to be difficult, awkward, bizarrely
convoluted, and filled with alien concepts, rest assured that this is a
normal reaction. You are not alone.

Windows and MS-DOS

You start up Windows as if it were a normal application program running
under MS-DOS. But as Windows loads, it becomes almost a full-fledged
operating system. It's not quite an operating system because it runs on top
of MS-DOS. While Windows is running, it shares responsibility with MS-DOS
for managing the hardware resources of the computer. Basically, MS-DOS
continues to manage the file system, while Windows does everything  else.
Windows commands the video display, keyboard, mouse, printer, and serial
ports and is responsible for memory management, program execution, and
scheduling.

Windows is strong where MS-DOS is weak, and weak where MS-DOS is adequate.
Windows includes almost no support of file I/O, which is one of the most
essential chores of a minimal operating system such as MS-DOS. This leads to
some amusing--or not so amusing--consequences. It is easier in a Windows
program to create a disk-based metafile containing a complex series of
graphics drawing commands than to create a simple ASCII text file. The
former is a Windows job; the latter requires that the program use MS-DOS.


The Windows Commitment

Programming for Windows is an all-or-nothing proposition. For example, you
cannot write an MS-DOS application--even a well-behaved one--and use Windows
only for some graphics. If you want to use any part of Windows, you must
make the commitment to write a full-fledged Windows program.

The reason for this will become more obvious as you learn about the
structure of a Windows program. Everything in Windows is interconnected. If
you want to draw some graphics on the video display, you need something
called a "handle to a device context." To get that, you need a "handle to a
window." To get that, you must create a window and be prepared to receive
"messages" to the window. To receive and process messages, you need a
"window procedure." And at that point you're writing a Windows program. You
can't fly unless you leave the ground.


The Function Calls

Windows 3 supports over 550 function calls that applications can use. It is
highly unlikely that you will ever memorize the syntax to all these calls.
Most Windows programmers keep the Windows Programmer's Reference manual
within easy reach.

Each of the Windows functions has a descriptive name written in mixed
uppercase and lowercase letters, such as CreateWindow. This function (as you
might guess) creates a window for your program. Another example: the
function IsClipboardFormatAvailable determines whether the clipboard is
holding data of a particular format.

All the Windows functions are declared in a header file named WINDOWS.H,
included in the Windows Software Development Kit. WINDOWS.H is an important
part of the Windows documentation. You might want to print a copy or use a
file browser for quick reference.

You use these Windows functions in your Windows program the same way you use
C library functions such as strlen. However, there are some differences
between the Windows functions and the standard C library functions.

Windows functions are always declared as far pascal functions. These are two
keywords that Microsoft has added to its version of C. The far keyword
indicates that the  Windows function is in a different code segment than the
program's code. (You'll see the reason for this shortly.)

The pascal keyword indicates that the function's calling sequence is
different than the normal C calling sequence. Normally, the C compiler
generates code that pushes parameters on the stack from right to left
beginning with the last parameter. The code calling the function is
responsible for adjusting the stack pointer after the function returns. With
the pascal calling sequence, the parameters are pushed on the stack from
left to right and the called function cleans up the stack. The pascal
calling sequence is used in Windows because it is more efficient.

With one oddball exception, any pointer passed to a Windows function must be
a far pointer. This is something you normally don't have to worry about
because the compiler will extend short pointers to long pointers based on
the function template in WINDOWS.H.


Dynamic Linking

If you've been working with MS-DOS programming for awhile, you might guess
that a Windows program interfaces with Windows through a software interrupt
such as the  MS-DOS Interrupt 0x21. You might guess that the linker adds
bindings to your Windows programs that convert the Windows function calls
into this software interrupt. But you would be wrong. A Windows program
interfaces to Windows through a process called "dynamic linking."

Like MS-DOS programs, Windows executables have the filename extension .EXE.
However, this is not the same .EXE format that is used in MS-DOS. Instead,
Windows programs use a .EXE format called the New Executable file format,
similar to that used in OS/2. Whenever a Windows program calls a Windows
function, the C compiler generates assembly-language code for a far call. A
table in the .EXE file identifies the function being called using a dynamic
link library name and either a name or a number (called the ordinal number)
of the function in that library.

Windows itself consists largely of three dynamic link libraries, called
KERNEL (responsible for memory management, loading and executing programs,
and scheduling), USER (the user interface and windowing), and GDI (the
graphics). These libraries contain the code and data for the Windows
functions. You can find these three dynamic link libraries in the SYSTEM
subdirectory of your Windows directory.

When a Windows program is loaded into memory, the far calls in the program
are resolved to point to the entry of the function in the dynamic link
library, which is also loaded into memory. This is why all Windows functions
must be defined as far: The code in the dynamic link libraries is not in the
same segment as the program's code. Also, pointers passed in Windows
functions must also be defined as far to avoid confusion with the dynamic
link library's own code and data segments.

Generally, you don't have to worry about the use of far calls and far
pointers because the functions are declared as far functions with far
pointers in WINDOWS.H: The C compiler will perform the necessary address
translations for you.

When you link a Windows program to produce an executable, you must link with
a special "import library" provided with the Windows Software Development
Kit. This import library contains the dynamic link library names and ordinal
numbers of all the Windows functions. LINK uses this information to
construct the table in the .EXE file that Windows uses to resolve calls to
Windows functions when loading the program.


Object-Oriented Programming

When programming for Windows, you're really engaged in a type of
object-oriented programming. This is most evident in the object you'll be
working with most in Windows_ the object that gives Windows its name, the
object that will soon seem to take on anthropomorphic characteristics, the
object that may even show up in your dreams, the object known as the
"window."

Windows are rectangular objects on the screen. A window receives user input
from the keyboard or mouse and displays graphical output on its surface.

An application window usually contains the program's title bar, menu, sizing
border, and perhaps some scroll bars. Dialog boxes are additional windows.
Moreover, the surface of a dialog box always contains several additional
windows called "child windows." These child windows take the form of push
buttons, radio buttons, check boxes, text entry fields, list boxes, and
scroll bars.

The user sees these windows as objects on the screen and interacts directly
with these objects by pushing a button or scrolling a scroll bar.
Interestingly enough, the programmer's perspective is analogous to the
user's perspective. The window receives this user input in the form of
"messages" to the window. A window also uses messages to communicate with
other windows.

Understanding these messages is one of the hurdles you'll have to jump in
becoming a Windows programmer.


Message-Driven Architecture

The first time I saw a graphical user interface in action, I was puzzled.
The demonstration included a rudimentary word processor running in a window.
The word processor would reformat its text when the program's window was
resized.

It was obvious to me that the operating system was handling the details of
the window-resizing logic, and that the program was capable of responding to
this system function. How did the program know when its window was resized?
What was the mechanism the operating system used to convey this information
to the window? My previous programming experience was useless in
understanding how this worked.

It turns out that the answer to this question is central to understanding
the architecture used in graphical user interfaces. In Windows, when a user
resizes a window, Windows sends a message to the program indicating the new
window size. The program can then adjust the contents of its window to
reflect the new size.

"Windows sends a message to the program." I hope you didn't read that
statement without blinking. What on earth could it mean? We're talking about
program code here, not an electronic mail system. How can an operating
system send a message to a program?

When I say that "Windows sends a message to a program," I mean that Windows
calls a function within the program. The parameters to this function
describe the particular message. This function located in your Windows
program is known as the "window procedure."


The Window Procedure

You are undoubtedly accustomed to the idea of a program making calls to the
operating system. This is how a program opens a disk file, for example. 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' object-oriented
architecture.

Every window that a program creates has an associated window 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.

More precisely, a window is always created based on a "window class." The
window class identifies the window procedure that processes messages to the
window. The use of a window class allows multiple windows to be based on the
same window class and hence use the same window procedure. For example, all
buttons in all Windows programs are based on the same window class. This
window class is associated with a window procedure (located in the Windows
USER.EXE dynamic link library) that processes messages to all the button
windows.

In object-oriented programming, an "object" is a combination of code and
data. 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.

A window procedure processes messages to the window. Very often these
messages inform a window of user input from the keyboard or mouse. This is
how a push-button window knows that it's being "pressed," for example. Other
messages tell a window when it is being resized, or when the surface of the
window needs to be repainted.

When a Windows program begins execution, Windows creates a "message queue"
for the program. This message queue stores messages to all the various
windows a program  may create. The program includes a short chunk of code
called the "message loop" to retrieve these messages from the queue and
dispatch them to the appropriate window procedure. Other messages are sent
directly to the window procedure without being placed in the message queue.

If your eyes are beginning to glaze over with this excessively abstract
description of Windows architecture, maybe it will help to see how the
window, the window class, the window procedure, the message queue, the
message loop, and the window messages all fit together in the context of a
real program.



YOUR FIRST WINDOWS PROGRAM

In their classic book The C Programming Language (2d ed., Prentice Hall,
1988), Brian Kernighan and Dennis Ritchie begin discussing C with the
now-famous "Hello, world" program:

#include 

main ()
     {
     printf ("Hello, world\n") ;
     }

In the remainder of this chapter, I will show you the analogous program
written for Microsoft Windows. The program is called HELLOWIN, and it
creates a window that displays the text string "Hello, Windows!"

Lest you collapse from shock when you first look at the HELLOWIN code, I'll
warn you now that there are three files involved, and that the HELLOWIN.C
source code file is over 80 lines long. Most of these 80 lines are overhead.
You'll have similar overhead in almost every Windows program you write.

Rather than ask why the "Hello, Windows" program is so long and complex,
let's ask why the traditional "Hello, world" program is so short and simple.

What's Wrong with this Program?

The output model for the "Hello, world" program and other traditional C
programs is an antique piece of hardware known as the teletype. The teletype
resembles a typewriter with a continuous roll of paper. In the not too
distant past, programmers would sit at a teletype and type in commands that
were echoed to the paper. The computer responded by printing its output on
the paper.

The teletype metaphor was extended to the video display in the early days of
computers. The video display became a "glass teletype" that simply scrolled
when text reached the bottom of the screen.

How can the traditional "Hello, world" program display text without telling
the operating system the particular output device on which the text is to
appear? Because there is only one output device--the video display used as
if it were a teletype. If the user wishes the output to go elsewhere, it
must be redirected from the command line.

How can the program display text without telling the system where on the
output device the text is to appear? Because the text always appears where
the cursor happens to be, probably on the next line after you execute the
program. Suppose you want to display "Hello, world" in the center of the
screen. You'd have to use some device-dependent control codes to first
position the cursor at the desired location.

Let's say you want to run several "Hello, world" programs at one time and
see their output on the screen. What a mess! The copies of the program would
interfere with each other. There is nothing in the teletype metaphor to
separate output from several programs running concurrently.

It's also interesting that you see the "Hello, world" output even after the
program terminates. Rather than properly cleaning up after itself, the
program is leaving remnants of its existence on the video display.

The "Hello, world" program is so simple because it is designed for a simpler
age and simpler computers and simpler output devices. It's not in the same
ballpark as what we think of today as modern software, and it's not even
playing the same game.


The HELLOWIN Files

The three files necessary to create the "Hello, Windows" program are shown
in Figure 1-5:

  þ   HELLOWIN.MAK is a "make" file.

  þ   HELLOWIN.C is the C source code file.

  þ   HELLOWIN.DEF is a module definition file.

 HELLOWIN.MAK

#------------------------
# HELLOWIN.MAK make file
#------------------------

hellowin.exe : hellowin.obj hellowin.def
     link hellowin, /align:16, NUL, /nod slibcew libw, hellowin
     rc hellowin.exe

hellowin.obj : hellowin.c
     cl -c -Gsw -Ow -W2 -Zp hellowin.c


 HELLOWIN.C

/*---------------------------------------------------------
   HELLOWIN.C -- Displays "Hello, Windows!" in client area
                 (c) Charles Petzold, 1990
  ---------------------------------------------------------*/

#include 

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                    LPSTR lpszCmdParam, int nCmdShow)
     {
     static char szAppName[] = "HelloWin" ;
     HWND        hwnd ;
     MSG         msg ;
     WNDCLASS    wndclass ;

     if (!hPrevInstance)
          {
          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 = GetStockObject (WHITE_BRUSH) ;
          wndclass.lpszMenuName  = NULL ;
          wndclass.lpszClassName = szAppName ;

          RegisterClass (&wndclass) ;
          }

     hwnd = CreateWindow (szAppName,         // window class name
                    "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, nCmdShow) ;
     UpdateWindow (hwnd) ;
     while (GetMessage (&msg, NULL, 0, 0))
          {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
          }
     return msg.wParam ;
     }

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
     {
     HDC         hdc ;
     PAINTSTRUCT ps ;
     RECT        rect ;

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

               GetClientRect (hwnd, &rect) ;

               DrawText (hdc, "Hello, Windows!", -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) ;
     }

 HELLOWIN.DEF

;-------------------------------------
; HELLOWIN.DEF module definition file
;-------------------------------------

NAME           HELLOWIN

DESCRIPTION    'Hello Windows Program (c) Charles Petzold, 1990'
EXETYPE        WINDOWS
STUB           'WINSTUB.EXE'
CODE           PRELOAD MOVEABLE DISCARDABLE
DATA           PRELOAD MOVEABLE MULTIPLE
HEAPSIZE       1024
STACKSIZE      8192
EXPORTS        WndProc

These are standard files that you'll create for every Windows program you
write. Generally when you begin a new Windows program, you'll copy the
standard files from an existing program and then make appropriate changes to
them.

Most Windows programmers do all their program development and compiling
outside of Windows under MS-DOS, and then load Windows to test the program.
You can also create and compile a Windows program in the Microsoft C 6
Programmer's WorkBench. I'll be discussing the source code files as if you
create them in a text editor of your choice and then compile the program
from the MS-DOS command line outside of Windows.

If you have Windows, the Windows Software Development Kit, and the Microsoft
C Professional Development System (the C 6 compiler) properly installed, you
can create HELLOWIN.EXE from the three files shown in Figure 1-5 by
executing:

NMAKE HELLOWIN.MAK

on the MS-DOS command line. You can then run Windows and the HELLOWIN.EXE
program by executing:

WIN HELLOWIN

The program creates a normal application window as shown in Figure 1-6 on
the following page. The window displays "Hello, Windows!" in the center of
its client area.

When you think about it, this window has an amazing amount of functionality
in its mere 80 lines of code. You can grab the title bar with the mouse
pointer and move the window around the screen. You can grab the sizing
borders and resize the window. When the window changes size, the program
will automatically reposition the "Hello, Windows!" text string in the new
center of the client area. You can press the maximize button and zoom
HELLOWIN to fill the screen. You can press the minimize button and compress
the program into an icon. You can invoke all these options from the system
menu and, in addition, close the window to terminate the program.

While you may be pleased to see that HELLOWIN has all the functionality of a
normal Windows program, you may not look so pleasant-faced when you see the
source code required to create this program. But let's be brave while I
proceed to dissect this program piece by piece and analyze it to death.

  (Figure 1-6. may be found in the printed book.)


The Make File

To ease compilation of Windows programs, you can use the NMAKE utility
included in the Microsoft C Professional Development System. Whenever you
change something in one of the HELLOWIN source files, all you need do is
run:

NMAKE HELLOWIN.MAK

to create the updated HELLOWIN.EXE executable.

A make file consists of one or more sections, each of which begins with a
left-justified line that lists a target file, followed by a colon, followed
by one or more dependent files. This line is followed by one or more
indented command lines. These commands create the target file from the
dependent files. If the last modification date and time of any of the
dependent files is later than the last modification date and time of the
target file, then NMAKE executes the indented command lines.

Normally, NMAKE will update only the target file in the first section of the
make file. However, if one of the dependent files is itself a target file in
another section of the make file, then NMAKE will update that target first.

The HELLOWIN.MAK make file contains two sections. The first runs the
LINK.EXE linker if HELLOWIN.OBJ or HELLOWIN.DEF has been altered more
recently than HELLOWIN.EXE:

hellowin.exe : hellowin.obj hellowin.def
     link hellowin, /align:16, NUL, /nod slibcew libw, hellowin
     rc hellowin.exe

The second section runs the CL.EXE C compiler if HELLOWIN.C has been changed
more recently than HELLOWIN.OBJ:

hellowin.obj : hellowin.c
     cl -c -Gsw -Ow -W2 -Zp hellowin.c

Because HELLOWIN.OBJ is a dependent file in the first section of the make
file and a target file in the second section, NMAKE will check whether
HELLOWIN.OBJ needs updating before re-creating HELLOWIN.EXE. Thus, the make
file should be analyzed from the bottom up.

Running the CL.EXE C compiler creates the HELLOWIN.OBJ object module from
the HELLOWIN.C source code file:

cl -c -Gsw -Ow -W2 -Zp hellowin.c

Several compiler switches are required (or recommended) for compiling
Windows programs:

  þ   The -c switch indicates that the program should be compiled only and
      not yet linked. The link is a separate step.

  þ   The -Gsw switch is actually two switches: -Gs and -Gw. The -Gs switch
      disables checks for stack overflow. Because stack overflow messages
      are written to standard error output (and are hence ignored by
      Windows), it's best simply to be sure that you are using a sufficient
      stack. (Four kilobytes is recommended.)

  þ   The -Gw switch is a special Windows switch that inserts special prolog
      and epilog code in all far functions in the program. This code (which
      I'll discuss in Chapter 7) aids Windows in moving code and data
      segments in memory.

  þ   The -Ow switch concerns optimization. With this switch the compiler
      will avoid some optimizations that may cause problems specifically
      with Windows programs.

  þ   The -W2 switch enables warning level 2 for displaying warning
      messages. You should make an effort to write programs that show no
      warning messages when you compile with this switch. Windows will not
      tolerate sloppy programming, which can lead to nasty bugs.

  þ   The -Zp switch packs structure fields on byte boundaries. This is
      required for some of the structures defined in WINDOWS.H that programs
      use to communicate with Windows. Windows assumes that all structures
      are packed.

The first section of the make file runs two commands if HELLOWIN.OBJ or
HELLOWIN.DEF has been altered more recently than HELLOWIN.EXE. The first
indented command runs LINK:

link hellowin, /align:16, NUL, /nod slibcew libw, hellowin

The first field indicates the HELLOWIN.OBJ object file. The .OBJ extension
is assumed. The second field would normally list the name of the executable
file, but I'm letting it default to HELLOWIN.EXE. The /align:16 switch tells
LINK to align code and data segments on 16-byte boundaries in the
HELLOWIN.EXE file for better space efficiency. (The default is 512-byte
boundaries.)

The third field is the name of an optional map file. This is set to NUL to
create no map file. The fourth field lists the libraries followed by the
/nod (no default libraries) switch. SLIBCEW.LIB is the small model Windows C
run time library created during installation of the Windows Software
Development Kit.

LIBW.LIB is an import library that contains information LINK uses to set up
a table in the .EXE file so that Windows can dynamically link the program's
calls to Windows functions with the Windows dynamic link libraries that
contain those functions.

The fifth field indicates the name of the program's module definition file,
HELLOWIN.DEF. The .DEF extension is assumed. (I'll discuss this file later
in this chapter.) It contains information that LINK uses to construct
HELLOWIN.EXE.

The second indented command runs the Windows resource compiler, RC.EXE:

rc hellowin.exe

The resource compiler sets a couple flags in the HELLOWIN.EXE file to
indicate that this is a Windows 3\-compatible application. Primarily, this
avoids a Windows 3 message that warns the user that the program may crash
because it has not been modified for protected-mode operation. Later on,
we'll use the resource compiler to add menus and dialog boxes to our Windows
programs.


The C Source Code File

The second file in Figure 1-5 is HELLOWIN.C, the C source code file. It may
take awhile before you recognize that this program is indeed written in C!

Let's first take a global look at HELLOWIN.C before getting into details.
The file contains only two functions: WinMain and WndProc. WinMain is the
entry point to the program. It is the equivalent of the standard C main
function. Every Windows program has a WinMain function.

WndProc is the window procedure for HELLOWIN's window. This function
processes messages to the window. No code in HELLOWIN.C calls WndProc
directly: WndProc is called only from Windows. However, there is a reference
to WndProc in WinMain, which is why the function is declared near the top of
the program before WinMain.


The Windows Function Calls

HELLOWIN makes calls to no less than 16 Windows functions. In the order they
occur in HELLOWIN, these functions (with a brief description) are:

  þ   LoadIcon--Loads an icon for use by a program

  þ   LoadCursor--Loads a cursor for use by a program

  þ   GetStockObject--Obtains a graphics object (in this case a brush used
      for painting the window's background)

  þ   RegisterClass--Registers a window class for the program's window

  þ   CreateWindow--Creates a window based on a window class

  þ   ShowWindow--Displays the window on the screen

  þ   UpdateWindow--Directs the window to paint itself

  þ   GetMessage--Obtains a message from the message queue

  þ   TranslateMessage--Translates some keyboard messages

  þ   DispatchMessage--Sends a message to a window procedure

  þ   BeginPaint--Initiates the beginning of window painting

  þ   GetClientRect--Obtains the dimensions of the window's client area

  þ   DrawText--Displays a text string

  þ   EndPaint--Ends window painting

  þ   PostQuitMessage--Inserts a "quit" message into the message queue

  þ   DefWindowProc--Performs default processing of messages

These functions are documented in the Windows Programmer's Reference and
declared in WINDOWS.H. I'll discuss each of them as we encounter them while
dissecting the program.


Uppercase Identifiers

You'll notice the use of quite a few uppercase identifiers in HELLOWIN.C.
These identifiers are defined in WINDOWS.H.

Several of these identifiers contain a two-letter or three-letter prefix
followed by an underscore:

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
CS_HREDRAW           DT_SINGLELINE  WM_DESTROY
IDI_APPLICATION      CS_VREDRAW     DT_CENTER
WS_OVERLAPPEDWINDOW  IDC_ARROW      DT_VCENTER
WM_PAINT             CW_USEDEFAULT

These are simply numeric constants. The prefix indicates a general category
to which the constant belongs, as indicated in this table:

Prefix                  Category
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
CS                      class style
IDI                     ID for an icon
IDC                     ID for a cursor
WS                      window style
CW                      create window
WM                      window message
DT                      draw text

You almost never need to remember numeric constants when programming for
Windows. Virtually every numeric constant used in Windows has an identifier
defined in WINDOWS.H.


New Data Types

Other identifiers used in HELLOWIN.C are new data types, also defined in
WINDOWS.H. The ones used in the program are:

Data Type        Meaning
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
FAR              same as far
PASCAL           same as pascal
WORD             unsigned integer (16 bits)
DWORD            unsigned long integer (32 bits)
LONG             signed long integer (32 bits)
LPSTR            far (or long) pointer to a character string

These are fairly self-explanatory. The people who originally developed
Windows thought that it would someday be ported to other microprocessors.
These new data types were defined to ease the porting of Windows
applications to other architectures. Rather than use machine-specific data
sizes (such as the size of C integer), the new data types were devised to
keep programs consistent regardless of the processor on which they run.

Of course, Windows will probably never be ported to other architectures, but
the Windows functions are still defined using these new data types, and
Windows programmers continue to use them.

HELLOWIN also uses four data structures (which I'll discuss later in this
chapter) defined in WINDOWS.H:

Structure               Meaning
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
MSG                     The message structure
WNDCLASS                The window class structure
PAINTSTRUCT             The paint structure
RECT                    The rectangle structure

The first two data structures are used in WinMain to define two structures
named msg and wndclass. The second two are used in WndProc to define two
structures  named ps and rect.


Getting a Handle on Handles

Finally, there are three uppercase identifiers for various types of
"handles":

Identifier             Meaning
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
HANDLE                 Generic handle
HWND                   Handle to a window
HDC                    Handle to a device context

Handles are used quite frequently in Windows. Before the chapter is over,
you also encounter HICON (a handle to an icon), HCURSOR (a handle to a mouse
cursor), and HBRUSH (a handle to a graphics brush).

A handle is simply a 16-bit number that refers to an object. The handles in
Windows are similar to file handles used in conventional C or MS-DOS
programming. A program almost always obtains a handle by calling a Windows
function. The program uses the handle in other Windows functions to refer to
the object. The actual value of the handle is unimportant to your program,
but the Windows module that gives your program the handle knows how to use
it to reference the object.


Hungarian Notation

You may also notice that some of the variables in HELLOWIN.C have
peculiar-looking names. One example is lpszCmdParam, passed as a parameter
to WinMain.

Many Windows programmers use a variable-naming convention known as Hungarian
notation, in honor of the legendary Microsoft programmer Charles Simonyi.
Very simply, the variable name begins with a lowercase letter or letters
that denote the data type of the variable. For example, the lpsz prefix in
lpszCmdParam stands for "long pointer to a string terminated by zero."

The h prefix in hInstance and hPrevInstance stands for "handle"; the n
prefix in nCmdShow stands for "number," and usually specifies an integer.
Two of the parameters to WndProc also use Hungarian notation: wParam is a
WORD and lParam is a LONG.

When naming structure variables, you can use the structure name (or an
abbreviation of the structure name) in lowercase as either a prefix to the
variable name or as the entire variable name. For example, in the WinMain
function in HELLOWIN.C, the msg variable is a structure of the MSG type;
wndclass is a structure of the WNDCLASS type. In the WndProc function, ps is
a PAINTSTRUCT structure and rect is a RECT structure.

Hungarian notation helps you avoid errors in your code before they turn into
bugs. Because the name of a variable describes both the use of a variable
and its data type, you are much less inclined to make coding errors
involving mismatched data types.

The variable name prefixes I'll be using in this book are shown in the
following table:


Prefix     Data Type
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
c          char
by         BYTE (unsigned char)
n          short or int
i          int
x, y       short (used as x-coordinate or y-coordinate)
cx, cy     short (used as x or y length; the c stands for "count")
b          BOOL (int)
w          WORD (unsigned int)
l          LONG (long)
dw         DWORD (unsigned long)
fn         function
s          string
sz         string terminated by 0 byte



The Program Entry Point

With this global look at HELLOWIN.C out of the way, we can now begin the
line-by-line dissection of the program. The code begins with an #include
statement to include the WINDOWS.H header file:

#include 

WINDOWS.H contains declarations of the Windows functions, the Windows
structures, the new data types, and numeric constants.

This is followed by a forward declaration of the WndProc function:

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

The declaration is required because WndProc is referenced by some code in
the WinMain function.

In a C program written for a conventional environment, the entry point is a
function called main. This is where the program begins execution. (Actually,
the main function is the entry point to the part of the program written by
the programmer. Usually the C compiler will insert some start-up code in the
executable file. The start-up code then calls main.) The entry point of a
Windows program is a function called WinMain. (As is the case with main,
WinMain is actually called from some start-up code inserted into the
executable file.) WinMain is always defined like this:

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                         LPSTR lpszCmdParam, int nCmdShow)

This function uses the PASCAL calling sequence and returns an integer to the
start-up code. The function must be named WinMain. It has four parameters.

The hInstance parameter is called the "instance handle." This is a number
that uniquely identifies the program when it is running under Windows. It
could be that the user is running multiple copies of the same program under
Windows. (For example, most Windows users at one time or another have loaded
multiple versions of the CLOCK program to see what happens.) Each copy is
called an "instance," and each has a different hInstance value. The instance
handle is comparable to a "task ID" or "process ID" number common in
mulitasking operating systems.

The hPrevInstance ("previous instance") parameter is the instance handle of
the most recent previous instance of the same program that is still active.
If no other copies of the program are currently loaded, then hPrevInstance
will be 0 or NULL.

The lpszCmdParam parameter is a long (or far) pointer to a 0-terminated
string that contains any command-line parameters passed to the program. It
is possible to run a Windows program with a command-line parameter by typing
the program name and the parameter into the Run dialog box invoked from
either the Program Manager or the File Manager.

The nCmdShow parameter is a number indicating how the window is to be
initially displayed in Windows. This number is assigned by whatever program
executes the program to run under Windows. Programs do not often need to
examine this number, but they can if they want. In most cases the number is
either a 1 or a 7. But it's best not to think of the value as a 1 or a 7.
Rather, think of the value as SW_SHOWNORMAL (defined in WINDOWS.H as 1) or
SW_SHOWMINNOACTIVE (defined as 7). The SW prefix in these identifiers stands
for "show window." This indicates whether the user launched the program to
be displayed as a normal window or to be initially minimized.


Registering the Window Class

A window is always created based on a window class. The window class
identifies the window procedure that processes messages to the window. This
is important, so I'll repeat it: A window is always created based on a
window class. The window class identifies the window procedure that
processes messages to the window.

More than one window can be created based on a single window class. For
example, all button windows in Windows are created based on the same window
class. The window class defines the window procedure and some other
characteristics of the windows that are created based on that class. When
you create a window you define additional characteristics of the window that
are unique to that window.

Before you create a window for your program, you must register a window
class by calling RegisterClass. The RegisterClass function requires a single
parameter: a pointer to a structure of type WNDCLASS. The WNDCLASS structure
is defined in WINDOWS.H like this:

typedef struct tagWNDCLASS
     {
     WORD    style ;
     LONG    (FAR PASCAL *lpfnWndProc) () ;
     int     cbClsExtra ;
     int     cbWndExtra ;
     HANDLE  hInstance ;
     HICON   hIcon ;
     HCURSOR hCursor ;
     HBRUSH  hbrBackground ;
     LPSTR   lpszMenuName ;
     LPSTR   lpszClassName ;
     }
     WNDCLASS ;

In WinMain, you must define a structure of type WNDCLASS, generally like
this:

WNDCLASS wndclass ;

You then define the 10 fields of the structure and call RegisterClass:

RegisterClass (&wndclass) ;

Only the first instance of a program needs to register the window class. The
window class then becomes available to all subsequent instances of the
program. For this reason, HELLOWIN initializes the fields of the WNDCLASS
structure and calls RegisterClass only if hPrevInstance equals NULL.

The WNDCLASS structure has 10 fields. The two most important fields are the
last and the second. The last field is the name of the window class (which
is generally the same as the name of the program). The second field
(lpfnWndProc) is the address of the window procedure used for all windows
created based on this class (which is the function WndProc in HELLOWIN.C).
All the other fields describe characteristics of all windows based on this
window class.

The statement:

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

combines two "class style" identifiers with a C bitwise OR operator. In
WINDOWS.H, the various identifiers beginning with the CS prefix are defined
as 16-bit constants with one bit set. For example, CS_VREDRAW is defined as
0x0001, and CS_HREDRAW is defined as 0x0002. Identifiers defined in this way
are sometimes called "bit flags." You combine the bit-flag identifiers with
the C OR operator.

These two class-style identifiers indicate that all windows created based on
this class are to be completely repainted whenever the horizontal window
size (CS_HREDRAW) or the vertical window size (CS_VREDRAW) changes. If you
resize HELLOWIN's window, you'll see that the text string is redrawn to be
in the new center of the window. These two identifiers ensure that this
happens.

The second field of the WNDCLASS structure is initialized by the statement:

wndclass.lpfnWndProc = WndProc ;

This sets the window procedure for this window class to WndProc, which is
the second function in HELLOWIN.C. This window procedure will process all
messages to all windows created based on this window class. The lpfn prefix
in the field name is Hungarian notation for "long pointer to a function."

The next two statements:

wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;

reserve some extra space in the class structure and the window structure
that Windows maintains internally. A program can use this extra space for
its own purpose. HELLOWIN does not use this feature, so zero is specified.
The cb prefix in the field names stands for a "count of bytes."

The next field is simply the instance handle of the program (which is one of
the parameters to WinMain):

wndclass.hInstance = hInstance ;

The statement:

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

sets an icon for all windows created based on this window class. The icon is
a small bitmap picture that appears when the program is minimized. Later in
this book you'll learn how to create customized icons for your Windows
programs. Right now, we'll take an easy approach and use a predefined icon.

To obtain a handle to a predefined icon, you call LoadIcon with a first
parameter set to NULL. (When loading your own customized icon, this
parameter would be set to the instance handle of the program.) The second
parameter is an identifier beginning with the IDI ("ID for an icon") defined
in WINDOWS.H. The IDI_APPLICATION icon is simply a white square with a black
outline. The LoadIcon function returns a handle to this icon. We don't
really care about the value of this handle. It's simply used to set the
value of the hIcon field. The hIcon field is defined in the WNDCLASS
structure to be of type HICON, which stands for "handle to an icon."

The statement:

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

is very similar to the previous statement. The LoadCursor function loads a
predefined mouse cursor known as IDC_ARROW and returns a handle to the
cursor. This handle is assigned to the hCursor field of the WNDCLASS
structure. When the mouse cursor appears over the client area of a window
that is created based on this class, the cursor becomes a small arrow.

The next field specifies the background color of the client area of windows
created based on this class. The hbr prefix of the hbrBackground field name
stands for "handle to a brush." A brush is a graphics term that refers to a
colored pattern of pixels used to fill an area. Windows has several
standard, or "stock," brushes. The GetObject call shown here returns a
handle to a white brush:

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

This means the background of the client area of the window will be solid
white, which is a common choice.

The next field specifies the window class menu. HELLOWIN has no application
menu, so the field is set to NULL:

wndclass.lpszMenuName  = NULL ;

Finally the class must be given a name. This is the same as the name of the
program, which is the "HelloWin" string stored in the szAppName variable:

wndclass.lpszClassName = szAppName ;

When all 10 fields of the structure have been initialized, HELLOWIN
registers the window class by calling RegisterClass. The only parameter to
the function is a pointer to the WNDCLASS structure:

RegisterClass (&wndclass) ;


Creating the Window

The window class defines general characteristics of a window, thus allowing
the same window class to be used for creating many different windows. When
you actually create a window by calling CreateWindow, you specify more
detailed information about the window. Rather than using a data structure as
RegisterClass does, the CreateWindow call requires all the information to be
passed as parameters to the function. Here's the CreateWindow call in
HELLOWIN.C:

hwnd = CreateWindow (szAppName,         // window class name
               "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

The Microsoft C compiler recognizes the // symbol for single-line comments.
The comments describe the parameters to the CreateWindow function.

Although you need to register a window class only for the first instance of
a program, you must create a window separately for each instance. Each
instance has its own window, and all the windows are based on the same
window class.

The parameter marked "window class name" is szAppName, which contains the
string "HelloWin"--the name of the window class we just registered. This is
how the window is associated with the window class.

The window created by this program is a normal overlapped window with a
caption bar, a system menu box to the left of the caption bar, minimize and
maximize icons to the right of the caption bar, and a thick window-sizing
border. That's a standard style of windows, and it has the WINDOWS.H name
WS_OVERLAPPEDWINDOW, which appears as the "window style" parameter. The
"window caption" is the text that will appear in the caption bar.

The parameters marked "initial x position" and "initial y position" specify
the initial position of the upper left corner of the window relative to the
upper left corner of the screen. By using the identifier CW_USEDEFAULT for
these parameters, we're indicating we want Windows to use the default
position for an overlapped window. (CW_USEDEFAULT  is defined as 0x8000.) By
default, Windows positions successive overlapped windows at stepped
horizontal and vertical offsets from the upper left corner of the display.

Similarly, the "initial x size" and "initial y size" parameters specify the
width and height of the window. The CW_USEDEFAULT identifier again indicates
that we want Windows to use a default size for the window. The default size
extends to the right side of the display and above the icon area at the
bottom of the screen.

The parameter marked "parent window handle" is set to NULL because this
window has no parent window. (When a parent-child relationship exists
between two windows, the child window always appears on the surface of its
parent.) The "window menu handle" is also set to NULL because the window has
no menu. The "program instance handle" is set to the instance handle passed
to the program as a parameter of WinMain. Finally, a "creation parameters"
pointer is set to NULL. You could use this pointer to access some data that
you might later want to reference in the program.

The CreateWindow call returns a handle to the created window. This handle is
saved in the variable hwnd, which is defined to be of type HWND (handle to a
window). Every window in Windows has a handle. Your program uses the handle
to refer to the window. Many Windows functions require hwnd as a parameter
so that Windows knows to which window the function applies. If a program
creates many windows, each has a different handle. The handle to a window is
one of the most important handles a Windows program (pardon the expression)
handles.


Displaying the Window

After the CreateWindow call returns, the window has been created internally
in Windows. However, the window does not yet appear on the video display.
Two more calls are needed. The first is:

ShowWindow (hwnd, nCmdShow) ;

The first parameter is the handle to the window just created by
CreateWindow. The second parameter is the nCmdShow value passed as a
parameter to WinMain. This determines how the window is to be initially
displayed on the screen. If nCmdShow is SW_SHOWNORMAL (equal to 1), the
window is displayed normally. If nCmdShow is SW_SHOWMINNOACTIVE (equal to
7), then the window is initially displayed as an icon.

The ShowWindow function puts the window (or icon) on the display. If the
second parameter to ShowWindow is SW_SHOWNORMAL, the client area of the
window is erased with the background brush specified in the window class.
The function call:

UpdateWindow (hwnd) ;

then causes the client area to be painted. It accomplishes this by sending
the window procedure (the WndProc function in HELLOWIN.C) a WM_PAINT
message. We'll examine shortly how WndProc deals with this message.


The Message Loop

After the UpdateWindow call, the window is fully visible on the video
display. The program must now make itself ready to read keyboard and mouse
input from the user. 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":

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

The msg variable is a structure of type MSG, which is defined in WINDOWS.H
as follows:

typedef struct tagMSG
     {
     HWND  hwnd ;
     WORD  message ;
     WORD  wParam ;
     LONG  lParam ;
     DWORD time ;
     POINT pt ;
     }
     MSG ;

The POINT data type is yet another structure, defined like this:

typedef struct tagPOINT
     {
     int x ;
     int y ;
     }
     POINT ;

The GetMessage call that begins the message loop retrieves a message from
the message queue:

GetMessage (&msg, NULL, 0, 0) ;

This call passes to Windows a far pointer to the MSG structure called msg.
The second, third, and fourth parameters are set to NULL or 0 to indicate
that the program wants all messages for all windows created by the program.
Windows fills in the fields of the message structure with the next message
from the message queue. The fields of this structure are:

  þ   hwnd--the handle to the window to which the message is directed. In
      the HELLOWIN program, this is the same as the hwnd value returned from
      CreateWindow, because that's the only window this program has.

  þ   message--the message identifier. This is a number that identifies the
      message. For each message, there is a corresponding identifier defined
      in WINDOWS.H that begins with the prefix WM ("window message"). For
      example, if you position the mouse pointer over HELLOWIN's client area
      and press the left mouse button, Windows will put a message in the
      message queue with a message field equal to WM_LBUTTONDOWN, which is
      the value 0x0201.

  þ   wParam--a 16-bit "message parameter," the meaning and value of which
      depend on the particular message.

  þ   lParam--a 32-bit message parameter dependent on the message.

  þ   time--the time the message was placed in the message queue.

  þ   pt--the mouse coordinates at the time the message was placed in the
      message queue.

If the message field of the message retrieved from the message queue is
anything except WM_QUIT (which equals 0x0012), then GetMessage returns a
nonzero value. A WM_QUIT message causes the program to fall out of the
message loop. The program then terminates, returning the wParam member of
the msg structure.

The statement:

TranslateMessage (&msg) ;

passes the MSG structure back to Windows for some keyboard translation.
(I'll discuss this more in Chapter 3.) The statement:

DispatchMessage (&msg) ;

again passes the MSG structure back to Windows. Windows then sends the
message to the appropriate window procedure for processing. That window
procedure is the WndProc function in HELLOWIN. After WndProc processes the
message, it then returns to Windows, which is still servicing the
DispatchMessage call. When Windows returns to HELLOWIN following the
DispatchMessage call, the message loop continues with the next GetMessage
call.


The Window Procedure

All that I've described so far is really just overhead. The window class has
been registered, the window has been created, the window has been displayed
on the screen, and the program has entered a message loop to retrieve
messages from the message queue.

The real action occurs in the window procedure, which Windows programmers
commonly call a "window proc" (pronounced "prock"). The window procedure
determines what the window displays in its client area and how the window
responds to user input.

In HELLOWIN, the window procedure is the function called WndProc. A window
procedure can have any name. A Windows program can contain more than one
window procedure. A window procedure is always associated with a particular
window class that you register by calling RegisterClass. The CreateWindow
function creates a window based on a particular window class. More than one
window can be created based on the same window class.

A window procedure is always defined like this:

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

Note that the four parameters to the window procedure are identical to the
first four fields of the MSG structure.

The first parameter is hwnd, the handle to the window receiving the message.
This is the same handle returned from the CreateWindow function. For a
program like HELLOWIN, which creates only one window, this is the only
window handle the program knows about. If a program creates multiple windows
based on the same window class (and hence the same window procedure), then
hwnd identifies the particular window receiving the message.

The second parameter is a number (specifically, a 16-bit unsigned integer or
WORD) that identifies the message. The last two parameters (a WORD called
wParam and a 32-bit signed long integer or LONG called lParam) provide more
information about the message. These are called "message parameters." What
these parameters contain is specific to each type of message.


Processing the Messages

Each message that a window procedure receives is identified by a number,
which is the message parameter to the window procedure. The WINDOWS.H header
file defines identifiers beginning with the prefix WM ("window message") for
each message parameter.

Generally, Windows programmers use a switch and case construction to
determine what message the window procedure is receiving and how to process
it accordingly. When a window procedure processes a message, it should
return 0 from the window procedure. All messages that a window procedure
chooses not to process must be passed to a Windows function named
DefWindowProc. The value returned from DefWindowProc must be returned from
the window procedure.

In HELLOWIN, WndProc chooses to process only two messages: WM_PAINT and
WM_DESTROY. The window procedure is structured like this:

switch (message)
     {
     case WM_PAINT :
[ process WM_PAINT message ]
          return 0 ;

     case WM_DESTROY :
[ process WM_DESTROY message ]
          return 0 ;
     }

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

It is essential to call DefWindowProc for all messages that your window
procedure does not process.


The WM_PAINT Message

The first message that WndProc processes is WM_PAINT. This message is
extremely important in Windows programming. It informs a program when part
or all of the window's client area is "invalid" and must be repainted.

How does a client area become invalid? When the window is first created, the
entire client area is invalid because the program has not yet drawn anything
on the window. The first WM_PAINT message (which normally occurs when the
program calls UpdateWindow in WinMain) directs the window procedure to draw
something on the client area.

When you resize HELLOWIN's window, the client area also becomes invalid.
You'll recall that the style parameter of HELLOWIN's wndclass structure was
set to the flags  CS_HREDRAW and CS_VREDRAW. This directs Windows to
invalidate the whole window when the size changes. The window procedure
receives a WM_PAINT message.

When you minimize HELLOWIN to be displayed as an icon and then restore the
window again to its previous size, Windows does not save the contents of the
client area. Under a graphical environment, this would be too much data.
Instead, Windows invalidates the window. The window procedure receives a
WM_PAINT message and itself restores the contents of its window.

When you move windows around so they overlap, Windows does not save the area
of a window covered by another window. When that area of the window is later
uncovered, it is flagged as invalid. The window procedure receives a
WM_PAINT message to repaint the contents of the window.

Before sending the window procedure a WM_PAINT message, Windows erases the
background of the invalid area using the brush specified in the
hbrBackground field of the WNDCLASS structure used to register the window
class. In the case of HELLOWIN, this is a stock white brush, which means
that Windows erases the background of the window by coloring it white.

WM_PAINT processing almost always begins with a call to BeginPaint:

hdc = BeginPaint (hwnd, &ps) ;

and ends with a call to EndPaint:

EndPaint (hwnd, &ps) ;

In both cases, the first parameter is a handle to the program's window and
the second parameter is a pointer to a structure of type PAINTSTRUCT.
PAINTSTRUCT contains some information that a window procedure can use for
painting the client area. (I'll discuss the fields of this structure in the
next chapter.)

BeginPaint returns a "handle to a device context." A device context refers
to a physical output device (such as a video display) and its device driver.
You need the device context handle to display text and graphics in the
client area of a window. Using the device context handle returned from
BeginPaint, you cannot draw outside the client area, even if you try.
EndPaint releases the device context handle so that it is no longer valid.
EndPaint also validates the entire client area.

If a window procedure does not process WM_PAINT messages (which is very
rare), they must be passed on to DefWindowProc. DefWindowProc simply calls
BeginPaint and EndPaint in succession so that the client area is validated.

After WndProc calls BeginPaint, it calls GetClientRect:

GetClientRect (hwnd, &rect) ;

The first parameter is the handle to the program's window. The second
parameter is a pointer to a variable named rect defined as type RECT in
WndProc.

RECT is a "rectangle" structure defined in WINDOWS.H. It has four int fields
named left, top, right, and bottom. GetClientRect sets these four fields to
the dimensions of the client area of the window. The left and top fields are
always set to 0. The right and bottom fields are set to the width and height
of the client area in pixels.

WndProc doesn't do anything with this RECT structure except pass a pointer
to it as the fourth parameter of DrawText:

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

DrawText (as the name implies) draws text. Because this function draws
something, the first parameter is a handle to the device context returned
from BeginPaint. The second parameter is the text to draw, and the third
parameter is set to -1 to indicate that the text string is terminated with a
0 byte.

The last parameter is a series of bit flags defined in WINDOWS.H. The flags
indicate that the text should be displayed as a single line centered
horizontally and vertically within the rectangle specified by the fourth
parameter. This function call thus causes the string "Hello, Windows!" to be
displayed centered in the client area.

Whenever the client area becomes invalid (as it does when you change the
size of the window), Windows erases the background of the window and WndProc
receives a new WM_PAINT message. WndProc obtains the updated window size by
calling GetClientRect and again displays the text in the new center of the
window.


The WM_DESTROY Message

The WM_DESTROY message is another important message. This message indicates
that Windows is in the process of destroying a window based on a command
from the user. The message is a result of the user selecting Close from the
program's system menu or pressing Alt-F4.

HELLOWIN responds to this message in a standard way by calling:

PostQuitMessage (0) ;

This function inserts a WM_QUIT message in the program's message queue. I
mentioned earlier that GetMessage returns nonzero for any message other than
WM_QUIT that it retrieves from the message queue. When GetMessage retrieves
a WM_QUIT message, GetMessage returns 0. This causes WinMain to drop out of
the message loop and exit, terminating the program.


The Module Definition File

In addition to the C source code, another file is required for Windows
programs. It is called a "module definition file" and has the extension
.DEF. The module definition file aids the LINK linker in creating the .EXE
file by telling it the characteristics of the program's code and data
segments, the size of the program's local data heap (from which the program
can allocate memory), and the size of the program's stack. This information
becomes part of the header section of the New Executable file format. The
HELLOWIN.DEF file is shown in Figure 1-5 on page 16.

The NAME line defines HELLOWIN as a program (rather than a dynamic link
library) and gives it a module name, which is usually the name of the
program's .EXE file. The DESCRIPTION line simply inserts some text into the
.EXE file. This is an excellent place for a copyright notice or version
information. The EXETYPE line identifies the program as a Windows program.
(OS/2 programs also use module definition files and the New Executable file
format.)

The STUB is a program that is inserted into the .EXE file to be executed
when anyone attempts to run HELLOWIN.EXE from the MS-DOS command line. The
WINSTUB.EXE program included with the Windows Software Development Kit
simply displays the message "This program requires Microsoft Windows" and
terminates.

The CODE statement indicates that the program's code segment is flagged as
PRELOAD (which means that Windows will load the segment into memory
immediately) and MOVEABLE (which means that Windows can move the code
segment to another location in memory if it needs to consolidate blocks of
free memory). The DISCARDABLE option makes the code "discardable" (which
means that Windows can discard the code segment from memory and later reload
it from the .EXE file). These are the normal options for Windows programs.
If you follow proper Windows programming practice, you will not (in theory)
encounter any problems when Windows moves your code.

The DATA statement indicates that we want the data segment to be PRELOAD,
MOVEABLE, and MULTIPLE. Again, we are giving Windows permission to move the
data segment in memory if necessary. The MULTIPLE keyword requests that each
instance of the program gets its own separate data segment. This is
necessary because the data segment contains the program's stack and other
data items that must be separate for each instance. The code segment, on the
other hand, is shared by all instances of the program.

The HEAPSIZE line specifies the amount of extra local memory (memory in the
program's own data segment) that will be available for allocation. The value
depends on what the program needs. HELLOWIN doesn't need to allocate any
local memory, but we'll throw in a small value nonetheless. Windows can
expand a program's local heap if necessary.

The STACKSIZE line specifies the size of the stack. The value 8192 bytes is
a minimum recommended value. You'll want a bigger stack size if your program
has recursive functions or large non-static variables.

Finally, the EXPORTS line lists the window procedure WndProc. For reasons
I'll discuss in Chapter 7, all window procedures that a program contains
must be listed in the EXPORTS section of the module definition file.



THE WINDOWS PROGRAMMING HURDLES

Even with my explanation of HELLOWIN, the structure and workings of the
program are probably still somewhat mysterious. In a short C program written
for a conventional environment, the entire program may be contained in the
main function. In HELLOWIN, WinMain contains only program overhead necessary
to register the window class, create the window, and retrieve and dispatch
messages from the message queue.

All the real action of the program occurs in the window procedure. In
HELLOWIN, this action is not much--it simply displays a text string in its
window. But in later chapters you'll find that almost everything a Windows
program does it does in response to a message to a window procedure. This is
one of the major conceptual hurdles that you must leap to begin writing
Windows programs.

Don't Call Me, I'll Call You

As I mentioned earlier, programmers are familiar with the idea of calling on
the operating system to do something. For instance, C programmers use the
open or fopen function to open a file. The library functions provided with
the compiler have code that eventually calls the operating system to open
the file. No problem.

But Windows is different. Although Windows has more than 550 functions that
your program can call, Windows also makes calls to your program,
specifically to the window procedure we have called WndProc. The window
procedure is associated with a window class that the program registers by
calling RegisterClass. A window that is created based on this class uses
this window procedure for processing all messages to the window. Windows
sends a message to the window by calling the window procedure.

Windows calls WndProc when a window is first being created. Windows calls
WndProc when the window is later destroyed. Windows calls WndProc when the
window has been resized or moved or made into an icon. Windows calls WndProc
when an item has been selected from a menu. Windows calls WndProc when a
scroll bar is being moved or clicked with the mouse. Windows calls WndProc
to tell it when it must repaint its client area.

All these calls are in the form of messages. In most Windows programs, the
bulk of the program is dedicated to handling these messages. The 130 or so
different messages that Windows can send to a window procedure are all
identified with names that begin with the letters WM and defined in
WINDOWS.H.

Actually, the idea of a routine within a program that is called from outside
the program is not unheard of in normal programming. The signal function in
C can trap a Ctrl-Break. You may have experience with intercepting hardware
interrupts in assembly language or using one of the ON constructions in
Microsoft BASIC. The Microsoft Mouse driver has a method that non-Windows
programs can use to be notified of mouse activity.

In Windows, this concept is extended to cover everything. Everything that
happens to a window is relayed to the window procedure in the form of a
message. The window procedure then responds to this message in some way or
passes the message to DefWindowProc for default processing.

The wParam and lParam parameters to the window procedure are not used in
HELLOWIN except as parameters to DefWindowProc. These parameters give the
window additional information about the message. The meaning of the
parameters is message-dependent.

Let's look at an example. Whenever the client area of a window changes in
size, Windows calls that window's window procedure. The hwnd parameter to
the window procedure is the handle of the window changing in size. The
message parameter is WM_SIZE. The wParam parameter for a WM_SIZE message is
the value SIZENORMAL, SIZEICONIC, SIZEFULLSCREEN, SIZEZOOMSHOW, or
SIZEZOOMHIDE (defined in WINDOWS.H as the numbers 0 through 4). The wParam
parameter indicates whether the window is being  minimized, maximized, or
hidden (as a result of another window being maximized). The lParam parameter
contains the new size of the window. The new width (a 16-bit value) and the
new height (a 16-bit value) have been stuck together in the 32-byte lParam.
WINDOWS.H includes macros to help you extract these two values from lParam.
We'll do this in the next chapter.

Sometimes messages generate other messages as a result of DefWindowProc
processing. For example, suppose you run HELLOWIN and select Close from the
system menu using either the keyboard or the mouse. DefWindowProc processes
this keyboard and mouse input. When it detects that you have selected the
Close option, it sends a WM_SYSCOMMAND message to the window procedure.
WndProc passes this message to DefWindowProc. DefWindowProc responds by
sending a WM_CLOSE message to the window procedure. WndProc again passes
this message to DefWindowProc. DefWindowProc responds to the WM_CLOSE
message by calling DestroyWindow. DestroyWindow causes Windows to send a
WM_DESTROY message to the window procedure. WndProc finally responds to this
message by calling PostQuitMessage to put a WM_QUIT message in the message
queue. This message causes the message loop in WinMain to terminate and the
program to end.


Queued and Nonqueued Messages

I've talked about Windows sending messages to a window, which means that
Windows calls the window procedure. But a Windows program also has a message
loop that retrieves messages from a message queue by calling GetMessage and
dispatches them to the window procedure by calling DispatchMessage.

So, does a Windows program poll for messages (exactly as a normal program
polls for keyboard data) and then route these messages to some location? 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 and retrieved
and dispatched in the message loop. The nonqueued messages are sent to the
window directly when Windows calls the window procedure. The result is that
the window procedure gets all the messages--both queued and nonqueued--for
the window. Structurally, Windows programs are very clean, because they have
one central point of message processing. It is said that queued messages are
posted to a message queue while nonqueued messages are sent to the window
procedure.

The queued messages are primarily those that result from user input in the
form of keystrokes (such as WM_KEYDOWN and WM_KEYUP), characters that result
from keystrokes (WM_CHAR), mouse movement (WM_MOUSEMOVE), and mouse button
clicks (WM_LBUTTONDOWN). Queued messages also include the timer message
(WM_TIMER), the repaint message (WM_PAINT), and the quit message (WM_QUIT).
The nonqueued messages are everything else. In many cases the nonqueued
messages  result from queued messages. When you pass a nonqueued message to
DefWindowProc within the window procedure, Windows often processes the
message by sending the window procedure other messages.

This process is obviously complex, but fortunately most of the complexity is
Windows' problem rather than our program's. From the perspective of the
window procedure, these messages come through in an orderly, synchronized
manner. The window procedure can do something with these messages or ignore
them. For this reason, the window procedure has been called the "ultimate
hook." Messages notify the window procedure of almost everything that
affects the window.

The nonqueued messages often result from calling certain Windows function
calls or by explicitly sending a message by calling SendMessage. (Messages
can also be placed in a message queue by calling PostMessage.)

For example, when WinMain calls CreateWindow, Windows creates the window and
in the process sends the window procedure a WM_CREATE message. When WinMain
calls ShowWindow, Windows sends the window procedure WM_SIZE and
WM_SHOWWINDOW messages. When WinMain calls UpdateWindow, Windows sends the
window procedure a WM_PAINT message.

Messages are not like hardware interrupts. While processing one message in a
window procedure the program will not be interrupted by another message.
Only when the window procedure calls a function that generates a new message
will the message procedure process the message before the function returns.

The message loop and the window procedure do not run concurrently. When the
window procedure is processing a queued message, it is the result of a call
to DispatchMessage in WinMain. DispatchMessage does not return until the
window procedure has processed the message.

But notice that the window procedure must be reentrant. That is, Windows
often calls WndProc with a new message as a result of WndProc calling
DefWindowProc with a previous message. This is one reason that a Windows
program requires a 8-KB stack, as indicated in the module definition (.DEF)
file. In most cases the reentrancy of the window procedure presents no
problem, but you should be aware of it.

In many cases, the window procedure must retain information it obtains in
one message and use it while processing another message. This information
must be saved in variables defined as static in the window procedure or in
global variables.

Of course, you'll get a much better feel for all this in later chapters as
the window procedures are expanded to process more messages.


Nonpreemptive Multitasking

The GetMessage call within the message loop is important for another reason.
Except for some device drivers that must process hardware interrupts (such
as the timer, keyboard, mouse, and serial port), Windows usually treats
HELLOWIN as if it were the only program running under the system. Windows
will not arbitrarily switch away from HELLOWIN and run some other program.
The exception is during the GetMessage call. If HELLOWIN's message queue has
no waiting messages and another program has some messages in its message
queue, then Windows switches from HELLOWIN to the other program. That makes
sense, does it not?

You can think of it this way: In most cases, when your program calls a
function in Windows, you can expect that the function will be processed and
return control to your program within a reasonable period of time. When you
call GetMessage, however, it may be some time before Windows returns with a
message if the program's message queue does not contain any messages and
another program's message queue does. Windows can take advantage of the
delay caused by an empty message queue during a GetMessage call to switch to
another program that has messages waiting. As a result, Windows has a
"jumpy" type of multitasking. Sometimes a program has a long job to do, and
all other programs running under Windows seem to stop running during this
time.

Rather than "jumpy multitasking," this characteristic is usually called
"nonpreemptive multitasking." Windows is multitasking between programs by
switching between them. But Windows is not doing this as it is done within a
traditional multitasking system, based on the tick of a hardware clock and
allocating each program a tiny time-slice to do its stuff. It's multitasking
at the point where programs check the message queue for messages.

The process is actually a little more complex than that: Windows also
switches between programs during PeekMessage and WaitMessage calls, but
these are less common than GetMessage. Furthermore, the WM_PAINT and
WM_TIMER messages are treated as low-priority messages, so Windows can
switch from a program if only WM_PAINT and WM_TIMER messages are present in
the queue.


The Learning Curve

Yes, as you've undoubtedly determined from this chapter, Windows programming
is certainly different from programming for a conventional environment like
MS-DOS. Nobody will claim that Windows programming is easy.

When I first started learning Windows programming, I decided to do what I
had always done when learning a new operating system or a new language--to
write a simple "hex dump" program to display the contents of a file. In the
conventional MS-DOS environment, such a program involves command-line
processing, rudimentary file I/O, and screen output formatting. However, my
Windows hex-dump program turned into a monster. It required that I learn
about menus, dialog boxes, scroll bars, and the like. As a first Windows
program, it was definitely a mistake, demanding that I absorb too much all
at once.

Yet when this program was finished, it was quite unlike any hex-dump program
I had written. Rather than obtain the filename from a command line, WINDUMP
(as I called it) presented a list box showing all the files in the current
directory. Rather than write its output to the screen in a simple teletype
fashion, WINDUMP had scroll bars so I could move to any part of the file. As
an extra bonus, I could even run two copies of WINDUMP to compare two files
side by side. In short, WINDUMP was the first hex-dump program I wrote that
I was actually proud of.

What you have to ask yourself is this: Do I want my programs to use a more
modern and productive user interface, one that includes menus, dialog boxes,
scroll bars, and graphics? If you answer yes, then the question becomes: Do
I want to write all this menu, dialog box, scroll bar, and graphics code
myself? Or would I rather take advantage of all the code already inside
Windows for this? In other words, is it easier to learn how to use 550
function calls or to write them yourself? Is it easier to orient your
programming mind to the message-driven architecture of Windows or struggle
with using several different sources of user input in a traditional model?

If you're going to write your own user interface logic, you had better close
this book and get to work right away. Meanwhile, the rest of us are going to
learn how to display and scroll text in a window.