0% found this document useful (0 votes)
221 views

Windows Programming

The document discusses windows in Windows-based graphical applications. It describes that a window is an area on the screen where an application displays output and receives user input. It also discusses the desktop window, application windows, the client area, non-client area including title bar, menu bar, buttons, and scroll bars. It describes controls, dialog boxes, and window attributes like class name, style, and creation functions.

Uploaded by

Vlad Zahiu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
221 views

Windows Programming

The document discusses windows in Windows-based graphical applications. It describes that a window is an area on the screen where an application displays output and receives user input. It also discusses the desktop window, application windows, the client area, non-client area including title bar, menu bar, buttons, and scroll bars. It describes controls, dialog boxes, and window attributes like class name, style, and creation functions.

Uploaded by

Vlad Zahiu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 69

Windows

In a graphical Windows-based application, a window is a rectangular area of the screen where the application displays
output and receives input from the user. Therefore, one of the first tasks of a graphical Windows-based application is to
create a window.

A window shares the screen with other windows, including those from other applications. Only one window at a time
can receive input form the user (the window which has focus). The user can use the mouse, keyboard, or other input
device to interact with this window and the application that owns it.

About Windows
1. The Desktop Window
When you start the system, it automatically creates the desktop window. The desktop window is a system-defined
window that paints the background of the screen and serves as the base for all windows displayed by all applications.

The desktop window uses a bitmap to paint the background of the screen. The pattern created by the bitmap is called
the desktop wallpaper. By default, the desktop window uses the bitmap from a .bmp file specified in the registry as the
desktop wallpaper.

The GetDesktopWindow() function returns a handle to the desktop window.

A system configuration application, such as a Control Panel item, changes the desktop wallpaper by using the
SystemParametersInfo() function with the wAction parameter set to SPI_SETDESKWALLPAPER and the
lpvParam parameter specifying a bitmap file name. SystemParametersInfo() then loads the bitmap from the
specified file, uses the bitmap to paint the background of the screen, and enters the new file name in the registry.

2. Application Windows
Every graphical Windows-based application creates at least one window called the main window, that serves as the
primary interface between the user and the application. Most applications also create other windows, either directly or
indirectly, to perform tasks related to the main window. Each window plays a part in displaying output and receiving
input form the user.

When you start an application, the system also associates a taskbar button with the application. The taskbar button
contains the program icon and title. When the application is active, its taskbar button is displayed in the pushed state.

An application window includes elements such as the following:

 a title bar
 a menu bar
 the window menu (formerly known as the system menu)
 the minimize button
 the maximize button
 the restore button
 the close button
 a sizing border
 a client area
 a horizontal scroll bar
 a vertical scroll bar
An application's main window typically includes all of these components. The following illustration shows these
components in a typical main window:

3. Client Area
The client area is the part of a window where the application displays output, such as text or graphics. For example, a
desktop publishing application displays the current page of a document in the client area. The application must provide a
function, called a window procedure, to process input to the window and display output in the client area.

4. Nonclient Area
The title bar, menu bar, window (or system) menu, minimize and maximize buttons, sizing border, and scroll bars, are
referred to collectively as the window's nonclient area. The system manages most aspects of the nonclient area. The
application manages the appearance and behavior of its client area.

4.1 The Title Bar


The title bar displays an application-defined icon and line of text. Typically, the text specifies the name of the application
or indicates the purpose of the window. An application specifies the icon and text when creating the window. The title
bar also makes it possible for the user to move the window by using a mouse or other pointing device.

4.2 The Menu Bar


Most applications include a menu bar that lists the commands supported by the application. Items in the menu bar
represent the main categories of commands. Clicking an item on the menu bar typically opens a pop-up menu whose
items correspond to the tasks within a given category. By clicking a command, the user directs the application to carry
out a task.

4.3 The Window Menu


The window menu is created and managed by the system. It contains a standard set of menu items that, when chosen by
the user, set a window's size or position, close the application, or perform tasks.

4.4 The Minimize, Maximize, Restore and Close Buttons


The buttons in the upper-right corner affect the size and position of the window:

 When you click the maximize button, the system enlarges the window to the size of the screen and positions the
window, so it covers the entire desktop, minus the taskbar. At the same time, the system replaces the maximize
button with the restore button.
 When you click the restore button, the system restores the window to its previous size and position.
 When you click the minimize button, the system reduces the window to the size of its taskbar button, positions
the window over the taskbar button, and displays the taskbar button in its normal state. To restore the
application to its previous size and position, click its taskbar button.
 When you click the close button, the apllication exits.

4.5 The Sizing Border


The sizing border is an area around the perimeter of the window that enables the user to size the window by using a
mouse or other pointing device.

4.6 The Scroll Bars


The horizontal scroll bar and vertical scroll bar convert mouse or keyboard input into values that an application uses to
shift the contents of the client area either horizontally or vertically. For example, a word-processing application that
displays a lengthy document typically provides a vertical scroll bar to enable the user to page up and down through the
document.

5. Controls and Dialog Boxes


An application can create several types of windows in addition to its main window, including controls and dialog boxes.

A control is a window that an application uses to obtain a specific piece of information from the user, such as the name
of a file to open, or the desired point size of a text selection. Applications use controls to obtain information needed to
control a particular feature of an application. For example, a word-processing application typically provides a control to
let the user turn word wrapping on and off.

Controls are always used in conjunction with another window - typically, a dialog box. A dialog box is a window that
contains one or more controls. An application uses a dialog box to prompt the user for input needed to complete a
command. For example, an application that includes a command to open a file would display a dialog box that includes
controls in which the user specifies a path and a file name. Dialog boxes do not typically use the same set of window
components as does a main window. Most have a title bar, a window menu, a border (non-sizing), and a client area, but
they typically do not have a menu bar, minimize and maximize buttons, or scroll bars.

A message box is a special dialog box that displays a note, caution, or warning to the user. For example, a message box
can inform the user of a problem the application has encountered while performing a task.

6. Window Attributes
An application must provide the following information when creating a window (with the exception of the window
handle, which the creation function returns to uniquely identify the new window):

 class name
 window name
 window style
 extended window style
 position
 size
 parent or owner window handle
 menu handle or child-window identifier
 application instance handle
 creation data
 window handle
6.1 The Class Name
Every window belongs to a window class. An application must register a window class before creating any windows of
that class. The window class defines most aspects of a window's appearance and behavior. The chief component of a
window class is the window procedure, a function that receives and processes all input and requeste sent to the window.
The system provides the input and requests in the form of messages.

6.2 Window Name


A window name is a text string that identifies a window for the user. A main window, dialog box, or message box,
typically displays its window name in its title bar, if present. A control may display its window name, depending on the
control's class. For example, buttons, edit controls, and static controls display their window names within the rectangle
occupied by the control. However controls such as list boxes and combo boxes do not display their window names.

To change the window name after creating the window, use the SetWindowText() function. This function uses the
GetWindowTextLength() and GetWindowText() functions to retrieve the current window-name string from
the window

6.3 Window Style


Every window has one or more window styles. A window style is a named constant that defines an aspect of the
window's appearance and behavior that is not specified by the window's class. An application usually sets the window
styles when creating windows. It can also set the styles after creating a window by using the
SetWindowLong()function (or SetWindowLongPtr() in the case of 64-bit applications).

The system and, to some extent, the window procedure for the class, interpret the window styles.

Some window styles apply to all windows, but most apply to windows of specific window classes. The general window
styles are represented by constants that begin with the WS_ prefix. They can be combined with the OR operator to form
different types of windows, including main windows, dialog boxes, and child windows. The class-specific window styles
define the appearance and behavior of windows belonging to the predefined control classes. For example, the
SCROLLBAR class specifies a scroll bar control, but the SBS_HORZ and SBS_VERT styles determine whether a
horizontal or vertical scroll bar control is created.

6.4 Extended Window Style


Every window can optionally have one or more extended window styles. An extended window style is a named constant
that defines an aspect of the window's appearance and behavior that is not specified by the window class or the other
window styles. An application usually sets extended window styles when creating windows. It can also set the styles
after creating a window by using the SetWindowLong() function.

6.5 Position
A window's position is defined as the coordinates of its upper left corner:

 These coordinates, sometimes called window coordinates, are always relative to the upper left corner of the
screen.
 For a child window, these coordinates are relative to the upper left corner of the parent window's client area.

For example, a top-level window having the coordinates (10,10) is placed 10 pixels to the right of the upper left corner of
the screen and 10 pixels down from it. A child window having the coordinates (10, 10) is placed 10 pixels to the right of
the upper left corner of its parent window's client area and 10 pixels down form it.

The WindowFromPoint() function retrieves a handle to the window occupying a particular point on the screen.
Similarly, the ChildWindowFromPoint() and ChildWindowFromPointEx() functions retrieve a handle to the
child window occupying a particular point in the parent window's client area. Although
ChildWindowFromPointEx() can ignore invisible, disabled, and transparent child windows,
ChildWindowFromPoint() cannot.
6.6 Size
A window's size (width and height) is given in pixels. A window can have zero width or height. If an application sets a
window's width and height to zero, the system sets the size to the default minimum window size. To discover the
default minimum window size, an application uses the GetSystemMetrics() function with the SM_CXMIN and
SM_CYMIN flags.

6.7 Parent or Owner Window Handle


A window can have a parent window. A window that has a parent is called a child window. The parent window provides
the coordinate system used for positioning a child window. Having a parent window affects aspects of a window's
appearance. For example, a child window is clipped so that no part of the child window can appear outside the borders
of its parent window. A window that has no parent, or whose parent is the desktop window, is called a top-level window.
An application uses the EnumWindows() function to obtain a handle to each of its top-level windows.
EnumWindows() passes the handle to each top-level window, in turn, to an application-defined callback function,
EnumWindowsProc().

A window can own, or be owned by, another window. An owned window always appears in front of its owner window, is
hidden when its owner window is minimized, and is destroyed when its owner window is destroyed.

6.8 Menu Handle or Child-Window Identifier


A child window can have a child-window identifier, a unique, application-defined value associated with the child window.
Child-window identifiers are especially useful in applications that create multiple child windows. When creating a child
window, an application specifies the identifier of the child window. After creating the window, the application can
change the window's identifier by using the SetWindowLong() function, or it can retrieve the identifier by using the
GetWindowLong() function.

Every window, except a child window, can have a menu. An application can include a menu by providing a menu handle
either when registering the window's class or when creating the window.

6.9 Application Instance Handle


Every application has an instance handle associated with it. The system provides the instance handle to an application
when the application starts. Because it can run multiple copies of the same application, the system uses instance
handles to internally distinguish one instance of an application from another. The application must specify the instance
handle in many different windows, including those that create windows.

6.9 Creation Data


Every window can have application-defined creation data associated with it. When the window is first created, the
system passes a pointer to the data on to the window procedure of the window being created. The window procedure
uses the data to initialize application-defined variables.

6.10 Window Handle


After creating a window, the creation function returns a window handle that uniquely identifies the window. A window
handle has the HWND data type. An application must use this type when declaring a variable that holds a window handle.
An application uses this handle in other functions to direct their actions to the window.

An application can use the FindWindow() function to discover whether a window with the specified class name or
window name exists in the system. If such a window exists, FindWindow() returns a handle to the window. To limit
the search to the child windows of a particular application, use the FindWindowEx() function.

The IsWindow() function determines whether a window handle identifies a valid existing window.
There are special constants that can replace a window handle in certain functions. For example, an application can use
HWND_BROADCAST in the SendMessage() and SendMessageTimeout() functions, or HWND_DESKTOP in the
MapWindowPoints() function.

7. Window Creation
To create application windows, use the CreateWindow() or CreateWindowEx() function. You must provide the
information required to define the window attributes. CreateWindowEx() has a parameter, dwExStyle, that
CreateWindow() does not have. Otherwise, the functions are identical. In fact, CreateWindow() simply calls
CreateWindowEx() with the dwExStyle parameter set to zero.

It should be noted that there are additional functions for creating special-purpose windows such as dialog boxes and
message boxes (such as DialogBox(), CreateDialog() and MessageBox()).

7.1Main Window Creation


Every Windows-based application must have WinMain() (or wWinMain()) as its entry point function. WinMain()
performs a number of tasks, including registering the window class for the main window and creating the main window.
WinMain() registers the main window class by calling the RegisterClass() function, and it creates the main
window by calling the CreateWindowEx() function.

Your WinMain() function can also limit your application to a single instance. Create a named mutex using the
CreateMutex() function. If GetLastError() returns ERROR_ALREADY_EXISTS, another instance of your
application exists (it created the mutext) and you should exit WinMain().

The system does not automatically display the main window after creating it. Instead, an application must use the
ShowWindow() function to display the main window. After creating the main window, the application's WinMain()
function calls ShowWindow(), passing it two parameters: a handle to the main window and a flag specifying whether
the main window should be minimized or maximized when it is first displayed. Normally, the flag can be set to any of the
constants beginning with the SW_ prefix. However, when ShowWindow() is called to display the application's main
window, the flag must be set to SW_SHOWDEFAULT. This flag tells the system to display the window as directed by the
program that started the application.

If a window class was registered with the Unicode version of RegisterClass(), the window receives only Unicode
messages. To determine whether a window uses the Unicode character set or not, call IsWindowUnicode().

7.2 Window-Creation Messages


When creating any window, the system sends messages to the window procedure for the window. The window sends:

 WM_NCCREATE - after creating the window's nonclient area (before creating the window's client area)
 WM_CREATE - after creating the window's client area

The window procedures receives both messages before the system displays the window. Both messages include a
pointer to a CREATESTRUCT structure that contains all the information specified in the CreateWindowEx()
function. Typically, the window procedure performs initialization tasks upon receiving these messages.

When creating a child window, the system sends the WM_PARENTNOTIFY message to the parent window after sending
the WM_NCCREATE and WM_CREATE messages. It also sends other messages while creating a window. The number
and order of these messages depend on the window class and style and on the function used to create the window.

7.3 Multithreaded Applications


A Windows-based application can have multiple threads of execution, and each thread can create windows. The thread
that creates a window must contain the code for its procedure.
An application can use the EnumThreadWindows() function to enumerate the windows created by a particular
thread. This function passes the handle to each thread window, in turn, to an application-defined callback function,
EnumThreadWndProc().

The GetWindowThreadProcessId() function returns the identifier of the thread that created a particular window.

To set the show state of a window created by another thread, use the ShowWindowAsync() function.

Window Features
1. Window Types
This section describes the following types of windows:

 Overlapped windows
 Pop-up windows
 Child windows
 Layered windows
 Message-only windows

1.1 Overlapped Windows


An overlapped window is a top-level window that has a title bar, border, and client area. It is meant to serve as an
application's main window. It can also have a window menu, minimize and maximize buttons, and scroll bars. An
overlapped window used as a main window typically includes all of these components.

By specifying the WS_OVERLAPPED or WS_OVERLAPPEDWINDOW style in the CreateWindowEx() function, an


application creates an overlapped window:

 WS_OVERLAPPED - The window has a title bar and border.


 WS_OVERLAPPEDWINDOW - The window has a title bar, sizing border, window menu, and minimize and
maximize buttons.

1.2 Pop-up Windows


A pop-up window is a special type of overlapped window used for dialog boxes, message boxes, and other temporary
windows that appear outside an application's main window. Title bars are optional for pop-up windows. Otherwise, pop-
up windows are the same as overlapped windows of the WS_OVERLAPPED style.

You create a pop-up window by specifying the WS_POPUP style in CreateWindowEx(). To include a title bar, specify
the WS_CAPTION style. Use the WS_POPUPWINDOW style to create a pop-up window that has a border and a window
menu. The WS_CAPTION style must be combined with the WS_POPUPWINDOW style to make the window menu visible.

1.3 Child Windows


A child window has the WS_CHILD style and is confined to the client area of its parent window. An application typically
uses child windows to divide the client area of the parent window into functional areas. You create a child window by
specifying the WS_CHILD style in the CreateWindowEx() function.

A child window must have a parent window. The parent window can be:

 An overlapped window
 A pop-up window
 A child window
You specify the parent window when you call CreateWindowEx(). If you specify the WS_CHILD style in
CreateWindowEx() but do not specify a parent window, the system does not create the window.

A child window has a client area but no other features, unless they are explicitly requested. An application can request a
title bar, a window menu, minimize and maximize buttons, a border, and scroll bars for a child window, but a child
window cannot have a menu. If the application specifies a menu handle, either when it registers the child's window class
or creates the child window, the menu handle is ignored. If no border style is specified, the system creates a borderless
window. An application can use borderless child windows to divide a parent window's client area while keeping the
divisions invisible to the user.

1.3.1 Child Window Positioning


The system always positions a child window relative to the upper left corner of its parent window's client area.

No part of a child window ever appears outside the borders of its parent window. If an application creates a child
window that is larger than the parent window or positions a child window so that some or all of the child window
extends beyond the borders of the parent, the system clips the child window. That is, the portion outside the parent
window's client area is not displayed.

Actions that affect the parent window can also affect the child window, as follows:

Parent Window Child Window


Destroyed Destroyed before the parent window is destroyed
Hidden Hidden before the parent window is hidden. A child window is visible only when the
parent window is visible.
Moved Moved with the parent window's client area. The child window is responsible for
painting its client area after the move.
Shown Shown after the parent window is shown.

1.3.2 Child Window Clipping


The system does not automatically clip a child window from the parent window's client area. This means the parent
window draws over the child window if it carries out any drawing in the same location as the child window. However,
the system does clip the child window from the parent window's client area if the parent window has the
WS_CLIPCHILDREN style. If the child window is clipped, the parent window cannot draw over it.

A child window can overlap other child windows in the same client area. A child window that shares the same parent
window as one or more other child windows is called a sibling window. Sibling windows can draw in each other's client
area, unless one of the child window has the WS_CLIPSIBLINGS style. If a child window does have this style any
portion of its sibling window that lies within the child window is clipped.

If a window has either the WS_CLIPCHIDREN or WS_CLIPSIBLINGS style, a slight loss in performance occurs. Each
window takes up system resources, so an application should not use child windows indiscriminately. For best
performance, an application that needs to logically divide its main window should do so in the window procedure of the
main window rather than by using child windows.

1.3.3 Child Window Relationship to Parent Window


An application can change the parent window of an existing child window by calling the SetParent() function. In this
case, the system removes the child window form the client area of the old parent and moves it to the client area of the
new parent window. If SetParent() specifies a NULL handle, the desktop window becomes the new parent window.
In this case, the child window is drawn on the desktop, outside the borders of any other window. The GetParent()
function retrieves a handle to a child window's parent window.

The parent window relinquishes a portion of its client area to a child window, and the child window receives all input
from this area. The window class need not be the same for each of the child windows of the parent window. This means
that an application can fill a parent window with child windows that look different and carry out different tasks. For
example, a dialog box can contain many types of controls, each one a child window that accepts different types of data
from the user.

A child window has only one parent window, but a parent can have any number of child windows. Each child window, in
turn, can have child windows. In this chain of windows, each child window is called a descendant window of the original
parent window. An application uses the IsChild() function to discover whether a given window is a child window or
a descendant window of a given parent window.

The EnumChildWindows() function enumerates the child windows of a parent window. Then,
EnumChildWindows() passes the handle to each child window to an application-defined callback function.
Descendant windows of the given parent window are also enumerated.

1.3.4 Child Window Messages


The system passes a child window's input messages directly to the child window. The messages are not passed through
the parent window. The only exception is if the child window has been disabled by the EnableWindow() function. In
this case, the system passes any input messages that would have gone to the child window to the parent window
instead. This permits the parent window to examine the input messages and enable the child window, if necessary.

A child window can have a unique integer identifier. Child window identifiers are important when working with control
windows. An application directs a control's activity by sending it messages. The application uses the control's child
window identifier to direct the messages to the control. In addition, a control sends notification messages to its parent
window. A notification message includes the control's child window identifier, which the parent uses to identify which
control sent the message. An application specifies the child-window identifier for other types of child windows by setting
the hMenu parameter of the CreateWindowEx() function to a value rather than a menu handle.

1.4 Layered Windows


Using a layered window can significantly improve performance and visual effects for a window that has a complex shape,
animates its shape, or wishes to use alpha blending effects. The system automatically composes and repaints layered
windows and the windows of underlying applications. As a result, layered windows are rendered smoothly, without the
flickering typical of complex window regions. In addition, layered windows can be partially translucent, that is, alpha-
blended.

To create a layered window, specify the WS_EX_LAYERED extended window style when calling the
CreateWindowEx() function, or call the SetWindowLong() function to set WS_EX_LAYERED after the window
has been created. After the CreateWindowEx() function call, the layered window will not become visible until the
SetLayeredWindowAttributes() or UpdateLayeredWindow() function has been called for this window.

It should be noted that beginning with Windows 8, WS_EX_LAYERED can be used with child windows and top-level
windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.

To set the opacity level or the transparency color key for a given layered window, call
SetLayeredWindowAttributes(). After the call, the system may still ask the window to paint when the window
is shown or resized. However, because the system stores the image of a layered window, the system will not ask the
window to paint if parts of it are revealed as a result of relative window moves on the desktop. Legacy applications do
not need to restructure their painting code if they want to add translucency or transparency effects for a window,
because the system redirects the painting of windows that called SetLayeredWindowAttributes() into off-
screen memory and recomposes it to achieve the desired effect.

For faster and more efficient animation or if per-pixel alpha is needed, call UpdateLayeredWindow().
UpdateLayeredWindow() should be used primarily when the application must directly supply the shape and
content of a layered window, without using the redirection mechanism the system provides through
SetLayeredWindowAttributes(). In addition, using UpdateLayeredWindow() directly uses memory more
efficiently, because the system does not need the additional memory required for storing the image of the redirected
window. For maximum efficiency in animating windows, call UpdateLayeredWindow() to change the position and
the size of a layered window. Please note that after SetLayeredWindowAttributes() has been called,
subsequent UpdateLayeredWindow() calls will fail until the layering style bit is cleared and set again.

Hit testing of a layered window is based on the shape and transparency of the window. This means that the areas of the
window that are color-keyed or whose alpha value is zero will let the mouse messages through. However, if the layered
window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and
the mouse events will be passed to other windows underneath the layered window.

1.5 Message-Only Windows


A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be
enumerated, and does not receive broadcast messages. The window simply dispatches messages.

To create a message-only windows, specify the HWND_MESSAGE constant or a handle to an existing message-only
window in the hWndParent parameter of the CreateWindowEx() function. You can also change an existing
window to a message-only window by specifying HWND_MESSAGE in the hWndNewParent parameter of the
SetParent() function.

To find message-only windows, specify HWND_MESSAGE in the hWndParent parameter of the FindWindowsEx()
function. In addition, FindWindowsEx() searches message-only windows as well as top-level windows if both the
hWndParent and hWndChildAfter parameters are NULL.

2. Window Relationships
There are many ways that a window can relate to the user or another window. A window may be an owned window,
foreground window, or background window. A window also has a z-order relative to other windows.

2.1 Foreground and Background Windows


Each process can have multiple threads of execution, and each thread can create windows. The thread that created the
window with which the user is currently working is called the foreground thread, and the window is called the
foreground window. All other threads are background threads, and the windows created by background threads are
called background windows.

Each thread has a priority level that determines the amount of CPU time the thread receives. Although an application
can set the priority level of its threads, normally the foreground thread has a slightly higher priority level than the
background threads. Because it has a higher priority, the foreground thread receives more CPU time than the
background threads. The foreground thread has a normal base priority of 9. A background thread has a normal base
priority of 7.

The user sets the foreground window by clicking a window, or by using the ALT + TAB or ALT + ESC key combination. To
retrieve a handle to the foreground window, use the GetForegroundWindow() function. To check if your
application window is the foreground window, compare the handle returned by GetForegroundWindow() to that
of your application window.

An application sets the foreground window by using the SetForegroundWindow() function.

The system restricts which processes can set the foreground window. A process can set the foreground window only if
one of the following conditions is true:

 The process is the foreground process.


 The process was started by the foreground process.
 The process received the last input event.
 There is no foreground process.
 The foreground process is being debugged.
 The foreground is not locked (check the LockSetForegroundWindow() function).
 The foreground lock time-out has expired (check SPI_GETFOREGROUNDLOCKTIMEOUT in the
SystemParametersInfo() function).
 No menu items are active.

A process that can set the foreground window can enable another process to set the foreground window by calling the
AllowSetForegroundWindow() function, or by calling the BroadcastSystemMessage() function with the
BSF_ALLOWSFW flag. The foreground process can disable calls to SetForegroundWindow() by calling the
LockSetForegroundWindow() function.

2.2 Owned Windows


An overlapped or pop-up window can be owned by another overlapped or pop-up window. Being owned places several
constraints on a window:

 An owned window is always above its owner in z-order.


 The system automatically destroys an owned window when its owner is destroyed.
 An owned window is hidden when its owner is minimized.

Only an overlapped or pop-up window can be an owner window. A child window cannot be an owner window. An
application creates an owned window by specifying the owner's window handle as the hWndParent parameter of
CreateWindowEx() when it creates a window with the WS_OVERLAPPED or WS_POPUP style. The hWndParent
parameter must identify an overlapped or pop-up window. If hWndParent identifies a child window, the system
assigns ownership to the top-level parent window of the child window. After creating an owned window, an application
cannot transfer ownership of the window to another window.

Dialog boxes and message boxes are owned windows by default. An application specifies the owner window when
calling a function that creates a dialog box or message box.

An application can use the GetWindow() function with the GW_OWNER flag to retrieve a handle to a window's owner.

2.3 Z-Order
The z-order of a window indicates the window's position in a stack of overlapping windows. This window stack is
oriented along an imaginary axis, the z-axis, extending outward from the screen. The window at the top of the z-order
overlaps all other windows. The window at the bottom of the z-order is overlapped by all other windows.

The system maintains the z-order in a single list. It adds windows to the z-order based on whether they are topmost
windows, top-level windows, or child windows. A topmost window overlaps all other non-topmost windows, regardless
of whether it is the active or foreground window. A topmost window has the WS_EX_TOPMOST style. All topmost
windows appear in the z-order before any non-topmost windows. A child window is grouped with its parent in z-order.

When an application creates a window, the system puts it at the top of the z-order for windows of the same type. You
can use the BringWindowToTop() function to bring a window to the top of the z-order for windows of the same
type. You can rearrange the z-order by using the SetWindowPos() and DeferWindowPos() functions.

The user changes the z-order by activating a different window. The system positions the active window at the top of the
z-order for windows of the same type. When a window comes to the top of z-order, so do its child windows. You can use
the GetTopWindow() function to search all child windows of a parent window and return a handle to the child
window that is highest in z-order. The GetNextWindow() function retrieves a handle to the next or previous window
in z-order.
3.Window Show State
At any one given time, a window may be active or inactive, hidden or visible, and minimized, maximized, or restored.
These qualities are referred to collectively as the window state.

3.1 Active Window


An active window is the top-level window of the application with which the user is currently working. To allow the user
to easily identify the active window, the system places it at the top of the z-order and changes the color of its title bar
and border to the system-defined active window colors. Only a top-level window can be an active window. When the
user is working with a child window, the system activates the top-level parent window associated with the child window.

Only one top-level window in the system is active at a time. The user activates a top-level window by clicking on it (or
one of its child windows), or by using the ALT + ESC or ALT + TAB key combination. An application activates a top-level
window by calling the SetActiveWindow() function. Other functions can cause the system to activate a different
top-level window, including SetWindowPos(), DeferWindowPos(), SetWindowPlacement(), and
DestroyWindow(). Although an application can activate a different top-level window at any time, to avoid confusing
the user, it should do so only in response to a user action. An application uses the GetActiveWindow() function to
retrieve the handle to the active window.

When the activation changes from a top-level window of one application to the top-level window of another, the system
sends a WM_ACTIVATEAPP message to both applications, notifying them of the change. When the activation changes
to a different top-level window in the same application, the system sends both windows a WM_ACTIVATE message.

3.2 Disabled Windows


A window can be disabled. A disabled window receives no keyboard or mouse input form the user, but it can receive
messages from other windows, from other applications, and from the system. An application typically disables a window
to prevent the user from using the window. For example, an application may disable a push button in a dialog box to
prevent the user from choosing it. An application can enable a disabled window at any time. Enabling a window restores
normal input.

By default, a window is enabled when created. An application can specify the WS_DISABLED style, however, to disable
a new window. An application enables or disables an existing window by using the EnableWindow() function. The
system sends a WM_ENABLE message to a window when its enabled state is about to change. An application can
determine whether a window is enabled by using the IsWindowEnabled() function.

When a child window is disabled, the system passes the child's mouse input messages to the parent window. The parent
uses the messages to determine whether to enable the child window.

Only one window at a time can receive keyboard input - that window is said to have the keyboard focus. If an application
uses the EnableWindow() function to disable a keyboard-focus window, the window loses the keyboard focus in
addition to being disabled. EnableWindow() then sets the keyboard focus to NULL meaning no window has the
focus. If a child window, or other descendant window, has the keyboard focus, the descendant window loses the focus
when the parent window is disabled.

3.3 Window Visibility


A window can be either visible or hidden. The system displays a visible window on the screen. It hides a hidden window
by not drawing it. If a window is visible, the user can supply input to the window and view the window's output. If a
window is hidden, it is effectively disabled. A hidden window can process messages from the system or from other
windows, but it cannot process input from the user or display output. An application sets a window's visibility state
when creating the window. Later, the application can change the visibility state.

A window is visible when the WS_VISIBLE style is set for the window. By default, the CreateWindowEx() function
creates a hidden window unless the application specifies the WS_VISIBLE style. Typically, an application sets the
WS_VISIBLE style after it has created a window to keep details of the creation process hidden from the user. For
example, an application may keep a new window hidden while it customizes the window's appearance. If the
WS_VISIBLE style is specified in CreateWindowEx(), the system sends the WM_SHOWWINDOW message to the
window after creating the window, but before displaying it.

An application can determine whether a window is visible by using the IsWindowVisible() function. An application
can show (make visible) or hide a window by using the ShowWindow(), SetWindowPos(), DeferWindowPos(),
or SetWindowPlacement() or SetWindowLong() function. These functions show or hide a window by setting or
removing the WS_VISIBLE style for the window. They also send the WM_SHOWWINDOW message to the window
before showing or hiding it.

When a parent window is visible, its associated child windows are also visible. Similarly, when the parent window is
hidden, its child windows are also hidden. Minimizing the parent window has no effect on the visibility state of the child
windows. That is, the child windows are minimized along with the parent, but the WS_VISIBLE style is not changed.

Even if a window has the WS_VISIBLE style, the user may not be able to see the window on the screen. Other
windows may completely overlap it or it may have been moved beyond the edge of the screen. Also, a visible child
window is subject to the clipping rules established by its parent-child relationship. If the parent window moves beyond
the edge of the screen, the child window also moves because a child window is drawn relative to the parent's upper left
corner. For example, a user may move the parent window containing the child window far enough off the edge of the
screen that the user may not be able to see the child window, even though the child window and its parent window
both have the WS_VISIBLE style.

3.4 Minimized, Maximized and Restored Windows


A maximized window is a window that has the WS_MAXIMIZE style. By default, the system enlarges a maximized
window so that it fills the screen or, in the case of a child window, the parent window's client area. Although a window's
size can be set to the same size of a maximized window, a maximized window is slightly different. The system
automatically moves the window's title bar to the top of the screen or to the top of the parent window's client area.
Also, the system disables the window's sizing border and the window-positioning capability of the title bar (so that the
user cannot move the window by dragging the title bar).

A minimized window is a window that has the WS_MINIMIZED style. By default, the system reduces a minimized
window to the size of its taskbar button and moves the minimized window to the taskbar. A restored window is a
window that has been returned to its previous size and position, that is, the size it was before it was minimized or
maximized.

If an application specifies the WS_MAXIMIZE or WS_MINIMIZE style in the CreateWindowEx() function, the
window is initially maximized or minimized. After creating a window, an application can use the CloseWindow()
function to minimize the window. The ArrangeIconicWindows() function arranges the icons on the desktop, or it
arranges a parent window's minimized child windows in the parent window. The OpenIcon() function restores a
minimized window to its previous size and position.

The ShowWindow() function can minimize, maximize, or restore a window. It can also set the window's visibility and
activation states. The SetWindowPlacement() function includes the same functionality as ShowWindow(), but it
can override the window's default minimized, maximized, and restored positions.

The IsZoomed() and IsIconic() functions determine whether a given window is maximized or minimized,
respectively. The GetWindowPlacement() function retrieves the minimized, maximized, and restored positions for
the window, and als determines the window's show state.
When the system receives a command to maximize or restore a minimized window, it sends the window a
WM_QUERYOPEN message. If the window procedure returns FALSE, the system ignores the maximize or restore
command.

The system automatically sets the size and position of a maximized window to the system-defined defaults for a
maximized window. To override these defaults, an application can either call the SetWindowPlacement() function
or process the WM_GETMINMAXINFO message that is received by a window when the system is about to maximize the
window. WM_GETMINMAXINFO includes a pointer to a MINMAXINFO structure containing values the system uses to
set the maximized size and position. Replacing these values overrides the defaults.

Window Size and Position


A window's size and position are expressed as a bounding rectangle, given in coordinates relative to the screen or the
parent window:

 The coordinates of a top-level window are relative to the upper left corner of the screen.
 The coordinates of a child window are relative to the upper left corner of the parent window.

An application specifies a window's initial size and position when it creates the window, but it can change the window's
size and position at any time.

Default Size and Position


An application can allow the system to calculate the initial size and/or position of a top-level window by specifying
CW_USEDEFAULT in CreateWindowEx(). If the application sets the window's coordinates to CW_USEDEFAULT
and has created no other top-level windows, the system sets the new window's position relative to the upper left corner
of the screen. Otherwise, it sets the position relative to the position of the top-level window that the application created
most recently. If the width and height parameters are set to CW_USEDEFAULT, the system calculates the size of the
new window. If the application has created other top-level windows, the system bases the size of the new window on
the size of the application's most recently created top-level window.

Specifying CW_USEDEFAULT when creating a child or pop-up windowo causes the system to set the window's size to
the default minimum window size.

Tracking Size
The system maintains a minimum and maximum tracking size for a window of the WS_THICKFRAME style. A window
with this tyle has a sizing border. The minimum tracking size is the smallest window size you can produce by dragging
the window's sizing border. Similarly, the maximum tracking size is the largest window size you can produce by dragging
the sizing border.

A window's minimum and maximum tracking sizes are set to system-defined default values when the system creates the
window. An application can discover the defaults and override them by processing the WM_GETMINMAXINFO message.

System Commands
An application that has a window menu can change the size and position of the window by sending system commands.
System commands are generated when the user chooses commands from the window menu. An application can
emulate the user action by sending a WM_SYSCOMMAND message to the window. The following system commands
affect the size and position of a window:

Command Description
Closes the window. This command sends a WM_CLOSE message to the window. The
SC_CLOSE
window carries out any steps needed to clean up and destroy itself.
SC_MAXIMIZE Maximizes the window.
SC_MINIMIZE Minimizes the window
SC_MOVE Moves the window.
SC_RESTORE Restores a minimized or maximized window to its previous size and position.
SC_SIZE Starts a size command. To change the size of the window, use the mouse or keyboard.

Size and Position Functions


After creating the window, an application can set the window's size or position by calling one of several different
functions, including:

 SetWindowPlacement() - Sets a window's minimized position, maximized position, restored size and
position, and show state.
 MoveWindow() - Sets the size or position of a single application window.
 SetWindowPos() - Sets the size or position of a single application window. This function includes a set of
flags that affect the window's show state.
 DeferWindowPos() - Use the BeginDeferWindowPos(), DeferWindowPos(), and
EndDeferWindowPos() functions to simultaneously set the position of a number of windows, including the
size, position, position in the z-order, and show state.

An application can retrieve the coordinates of a window's bounding rectangle by using the GetWindowRect()
function. GetWindowRect() fills a RECT structure with the coordinates of the window's upper left and lower right
corners. The coordinates are relative to the upper left corner of the screen, even for a child window. The
ScreenToClient() or MapWindowPoints() function maps the screen coordinates of a child window's bounding
rectangle to coordinates relative to the parent window's client area.

The GetClientRect() function retrieves the coordinates of a window's client area. GetClientRect() fills a
RECT structure with the coordinates of the upper left and lower right corners of the client area, but the coordinates are
relative to the client area itself. This means the coordinates of a client area's upper left corner are always (0, 0), and the
coordinates of the lower right corner are the width and height of the client area.

The CascadeWindows() function cascades the windows on the desktop or cascades the child windows of the
specified parent window. The TileWindows() function tiles the windows on the desktop or tiles the child windows of
the specified parent window.

Size and Position Messages


The system sends the WM_GETMINMAXINFO message to a window whose size or position is about to change. For
example, the message is sent when the user clicks Move or Size from the window menu or clicks the sizing border or title
bar. The message is also sent when an application calls SetWindowPos() to move or size the window.
WM_GETMINMAXINFO includes a pointer to a MINMAXINFO structure containing the default maximized size and
position for the window, as well as the default minimum and maximum tracking sizes. An application can override the
defaults by processing WM_GETMINMAXINFO and setting the appropriate members of MINMAXINFO. A window must
have the WS_THICKFRAME or WS_CAPTION style to receive WM_GETMINMAXINFO. A window with the
WS_THICKFRAME style receives this message during the window-creation process, as well as when it is being moved or
sized.

The system sends the WM_WINDOWPOSCHANGING message to a window whose size, position, position in the z-order,
or show state is about to change. This message includes a pointer to a WINDOWPOS structure that specifies the
window's new size, position, position in the z-order, and show state. By setting the members of WINDOWPOS, an
application can affect the window's new size, position, and appearance.

After changing a window's size, position in the z-order, or show state, the system sends the WM_WINDOWPOSCHANGED
message to the window. This message includes a pointer to WINDOWPOS that informs the window of its new size,
position, position in the z-order, and show state. Setting the members of the WINDOWPOS structure that is passed with
WM_WINDOWPOSCHANGED has no effect on the window. A window that must process WM_SIZE and WM_MOVE
messages must pass WM_WINDOWPOSCHANGED to the DefWindowProc() function. Otherwise, the system does not
send the WM_SIZE and WM_MOVE messages to the window.

The system sends the WM_NCCALCSIZE message to a window when the window is created or sized. The system uses
the message to calculate the size of a window's client area and the position of the client area relative to the upper left
corner of the window. A window typically passes this message to the default window procedure. However, this message
can be useful in applications that customize a window's nonclient area or preserve portions of the client area when the
window is sized.

Window Animation
You can produce special effects when showing or hiding windows by using the AnimateWindow() function. When the
window is animated in this manner, the system will either roll, slide, or fade the window, depending on the flags you
specify in a call to AnimateWindow().

By default, the system uses the roll animation. With this effect, the window appears to roll open (showing the window)
or roll closed (hiding the window). You can use the dwFlags parameter to specify whether the window rolls
horizontally, vertically, or diagonally.

When you specify the AW_SLIDE flag, the system uses slide animation. With this effect, the window appears to slide
into view (showing the window) or slide out of view (hiding the window). You can use the dwFlags parameter to
specify whether the window slides horizontally, vertically, or diagonally.

When you specify the AW_BLEND flag, the system uses an alpha-blended fade.

You can also use the AW_CENTER flag to make a window appear to collapse inward or expand outward.

Window Destruction
In general, an application must destroy all the windows it creates. It does this by using the DestroyWindow()
function. When a window is destroyed, the system hides the window, fi it is visible, and then removes any internal data
associated with the window. This invalidates the window handle, which cna no longer be used by the application.

An application destroys many of the windows it creates soon after creating them. For example, an application usually
destroys a dialog box window as soon as the application has sufficient input form the user to continue its task. An
application eventually destroys the main window of the application (before temrinating).

Before destroying a window, an application should save or remove any data associated with the window, and it should
release any system resources allocated for the window. If the application does not release the resources, the system will
free any resources not freed by the application.

Destroying a window does not affect the window class from which the window is created. New windows can still be
created using that class, and any existing windows of that class continue to operate. Destroying a window also destroys
the window's descendant windows. The DestroyWindow() function sends a WM_DESTROY message first to the
window, then to its child windows and descendant windows. In this way, all descendant windows of the window being
destroyed are also destroyed.

A window with a window menu receives a WM_CLOSE message when the user clicks Close. By processing this message,
an application can prompt the user for confirmation before destroying the window. If the user confirms that the window
should be destroyed, the application can call the DestroyWindow() function to destroy the window.

If the window being destroyed is the active window, both the active and focus states are transferred to another window.
The window that becomes the active window is the next windows, as determined by the ALT + ESC key combination. The
new active window then determines which window receives the keyboard focus.
Using Windows
Creating a Main Window
The first window an application creates is typically the main window. You create the main window by using the
CreateWindowEx() function, specifying the window class, window name, window styles, size, position, menu
handle, instance handle, and creation data. A main window belongs to an application-defined window class, so you must
register the window class and provide a window procedure for the class before creating the main window.

Most applications typically use the WS_OVERLAPPEDWINDOW style to create the main window. This style gives the
window a title bar, a window menu, a sizing border, and minimize and maximize buttons. The CreateWindowEx()
function returns a handle that uniquely identifies the window.

The following example creates a main window belonging to an application-defined window class. The window name, will
appear in the window's title bar. By combining the WS_VSCROLL and WS_HSCROLL styles with the
WS_OVERLAPPEDWINDOW style, the application creates a main window with horizontal and vertical scroll bars in
addition to the components provided by the WS_OVERLAPPEDWINDOW style. The four occurences of the
CW_USEDEFAULT constant set the initial size and position of the window to the system-defined default values. By
specifying NULL instead of a menu handle, the window will have the menu defined for the window class.
HWND hWndMain = CreateWindowEx(
0, // no extended styles
L"MyWindowClass", // class name
L"Window Title", // window name
WS_OVERLAPPEDWINDOW | // overlapped window
WS_HSCROLL | // horizontal scroll bar
WS_VSCROLL, // vertical scroll bar
CW_USEDEFAULT, // default horizontal position
CW_USEDEFAULT, // default vertical position
CW_USEDEFAULT, // default width
CW_USEDEFAULT, // default height
(HWND) NULL, // no parent or owner window
(HMENU) NULL, // class menu used
hInstance, // instance handle
NULL); // no window creation data

if (!hWndMain) {
return FALSE;
}

// Show the window using the flag specified by the program


// that started the application, and send the application
// a WM_PAINT message.
ShowWindow(hWndMain, SW_SHOWDEFAULT);
UpdateWindow(hWndMain);

It should be noted that the preceding example calls the ShowWindow() function after creating the main window. This
is done because the system does not automatically display the main window after creating it. By passing the
SW_SHOWDEFAULT flag to ShowWindow(), the application allows the program that started the application to set the
initial show state of the main window. The UpdateWindow() function sends the window its first WM_PAINT
message.
Creating, Enumerating, and Sizing Child Windows
You can divide a window's client area into different functional areas by using child windows. Creating a child window is
like creating a main window - you use the CreateWindowEx() function. To create a window of an application-
defined window class, you must register the window class and provide a window procedure before creating the child
window. You must give the child window the WS_CHILD style and specify a parent window for the child window when
you create it.

The following example divides the client area of an application's main window into three functional areas by creating
three child windows of equal size. Each child window is the same height as the main window's client area, but each is
one third it's width. The main window creates the child windows in response to the WM_CREATE message, which the
main window receives during its own window-creation process. Because each child window has the WS_BORDER style,
each has a thin line border. Also, because WS_VISIBLE style is not specified, each child window is initially hidden.
Notice also that each child window is assigned a child-window identifier.

The main window sizes and positions the child windows in response to the WM_SIZE message, which the main window
receives when its size changes. In response to WM_SIZE, the main window retrieves the dimensions of its client area by
using the GetClientRect() function and then passes the handle to each child window, in turn, to the application-
defined EnumChildProc() callback function. The size and position are based on the dimensions of the main
window's client area and the identifier of the child window. Afterward, EnumChildProc() calls the ShowWindow()
function to make the window visible.
#define ID_FIRSTCHILD 100
#define ID_SECONDCHILD 101
#define ID_THIRDCHILD 102

LONG APIENTRY MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM


lParam)
{
RECT rcClient;

switch (uMsg) {
case WM_CREATE:
for (int i = 0; i < 3; i++) {
CreateWindow(0,
"ChildWClass",
(LPCTSTR) NULL,
WS_CHILD | WS_BORDER,
0, 0, 0, 0,
hWnd,
(HMENU) (int) (ID_FIRSTCHILD + i),
hInstance,
NULL);
}
return 0;
case WM_SIZE: // main window changed size
// Get the dimensions of the main window's client
// area, and enumerate the child windows. Pass the
// dimensions to the child windows during enumeration.

GetClientRect(hWnd, &rcClient);
EnumChildWindows(hWnd, EnumChildProc, (LPARAM) &rcClient);
return 0;
// Process other messages.
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

BOOL CALLBACK EnumChildProc(HWND hWndChild, LPARAM lParam) {


LPRECT rcParent;
int i;

// Retrieve the child-window identifier. Use it to set the


// position of the child window.

idChild = GetWindowLong(hWndChild, GWL_ID);

if (idChild == ID_FIRSTCHILD) {
i = 0;
} else if (idChild == ID_SECONDCHILD) {
i = 1;
} else {
i = 2;
}

// Size and position the child window


rcParent = (LPRECT) lParam;
MoveWindow(hWndChild,
(rcParent->right / 3) * i,
0,
rcParent->right / 3,
rcParent->bottom,
TRUE);

// Make sure the child window is visible.

ShowWindow(hWndChild, SW_SHOW);

return TRUE;
}

Destroying a Window
You can use the DestroyWindow() function to destroy a window. Typically, an application sends the WM_CLOSE
message before destroying a window, giving the window the opportunity to prompt the user for confirmation before the
window is destroyed. A window that includes a window menu automatically receives the WM_CLOSE message when the
user clicks Close from the window menu. If the user confirms that the window should be destroyed, the application calls
DestroyWindow(). The system sends the WM_DESTROY message to the window after removing it from the screen.
In response to WM_DESTROY, the window saves its data and frees any resources it allocated. A main window concludes
its processing of WM_DESTROY by calling the PostQuitMessage() function to quit the application.

The following example shows how to prompt for user confirmation before destroying a window. In response to
WM_CLOSE, the example displays a dialog box that contains Yes, No, and Cancel buttons. If the user clicks Yes,
DestroyWindow() is called. Otherwise, the window is not destroyed. Because the window being destroyed is a main
window, the example calls PostQuitMessage() in response to WM_DESTROY.
case WM_CLOSE:
// Create the message box. If the user clicks
// the Yes button, destroy the main window.

if (MessageBox(hWnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES)


DestroyWindow(hWndMain);
else
return 0;
case WM_DESTROY:
// Post the WM_QUIT message to
// quit the application.

PostQuitMessage(0);
return 0;

Using Layered Windows


To have a dialog box come up as a translucent window, first create the dialog as usual. Then, on WM_INITDIALOG, set
the layered bit of the window's extended style and call SetLayeredWindowAttributes() with the desired alpha
value. The code might look like this:
// Set WS_EX_LAYERED on this window
SetWindowLong(hWnd,
GWL_EXSTYLE,
GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);

// Make this window 70% alpha


SetLayeredWindowAttributes(hWnd, 0, (255 * 70) / 100, LWA_ALPHA);

Note that the third parameter of SetLayeredWindowAttributes() is a value that ranges from 0 to 255, with 0
making the window completely transparent and 255 making it completely opaque. This parameter mimics the more
versatile BLENDFUNCTION of the AlphaBlend() function.

To make this window completely opaque again, remove the WS_EX_LAYERED bit by calling SetWindowLong() and
then ask the window to repaint. Removing the bit is desired to let the system know that it can free up some memory
associated with layering and redirection. The code might look like this:
// Remove WS_EX_LAYERED from the window styles.
SetWindowLong(hWnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);

// Ask the window and its children to repaint.


RedrawWindow(hWnd,
NULL,
NULL,
RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);

In order to use layered child windows, the application has to declare itself Windows 8-aware in the manifest.
Window Classes
A window class is a set of attributes that the system uses as a template to create a window. Each window is a member of
a window class. All window classes are process specific.

About Window Classes


Each window class has an associated window procedure shared by all windows of the same class.

The window procedure processes messages for all windows of that class and therefore controls their behavior and
appearance.

A process must register a window class before it can create a window of that class. Registering a window class associates
a window procedure, class styles, and other class attributes with a class name. When a process specifies a class name in
the CreateWindow() or CreateWindowEx() function, the system creates a window with the window procedure,
styles, and other attributes associated with that class name.

1. Types of Window Classes


There are three types of window classes:

 System classes
 Application global classes
 Application local classes
These types differ in scope and in when and how they are registered and destroyed.

1.1 System Classes


A system class is a window class registered by the system. Many system classes are available for all processes to use,
while others are used only internally by the system. Because the system registers these classes, a process cannot destroy
them.

The system registers the system classes for a process the first time one of its threads calls a User or Windows Graphics
Device Interface (GDI) function.

Each application receives its own copy of the system classes. All 16-bit Windows-based applications in the same VDM
share system classes, just as they do on 16-bit Windows.

The following table describes the system classes that are available for use by all processes:

Class Description
Button The class for a button.
ComboBox The class for a combo box.
Edit The class for an edit control.
ListBox The class for a list box.
MDIClient The class for an MDI client window.
ScrollBar The class for a scroll bar.
Static The class for a static control.
The following table describes the system classes that are available only for use by the system:

Class Description
ComboLBox The class for the list box contained in a combo box.
DDEMLEvent The class for Dynamic Data Exchange Management Library (DDEML) events.
Message The class for a message-only window.
#32768 The class for a menu.
#32769 The class for the desktop window.
#32770 The class for a dialog box.
#32771 The class for the task switch window.
#32772 The class for icon titles.

1.2 Application Global Classes


An application global class is a window class registered by an executable or DLL that is available to all other modules in
the process. For example, your .dll can call the RegisterClassEx() function to register a window class that defines
a custom control as an application global class so that a process that loads the .dll can create instances of the custom
control.

To create a class that can be used in every process, create the window class in a .dll and load the .dll in every process. To
load the .dll in every process, add its name to AppInit_DLLs value in the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows

Whenever a process starts, the system loads the specified .dll in the context of the newly started process before calling
its entry-point function. The .dll must register the class during its initialization procedure and must specify the
CS_GLOBALCLASS style.

To remove an application global class and free the storage associated with it, use the UnregisterClass() function.
1.3 Application Local Classes
An application local class is any window class that an executable or .dll registers for its exclusive use. Although you can
register any number of local classes, it is typical to register only one. This window class supports the window procedure
of the application's main window.

The system destroys a local class when the module that registered it closes. An application can also use the
UnregisterClass() function to remove a local class and free the storage associated with it.

2. How the System Locates a Window Class


The system maintains a list of structures for each of the three types of window classes. When an application calls the
CreateWindow() or CreateWindowEx() function to create a window with a specified class, the system uses the
following procedure to locate the class:

1. Search the list of application local classes for a class with the specified name whose instance handle matches the
module's instance handle. (Several modules can use the same name to register local classes in the same
process.)
2. If the name is not in the application local class list, search the list of application global classes.
3. If the name is not in the application global class list, search the list of system classes.

All windows created by the application use this procedure, including windows created by the system on the application's
behalf, such as dialog boxes. It is possible to override system classes without affecting other applications. That is, an
application can register an application local class having the same name as a system class. This replaces the system class
in the context of the application but does not prevent other applications from using the system class.

3. Registering a Window Class


A window class defines the attributes of a window, such as its:

 style
 icon
 cursor
 menu
 window procedure

The first step in registering a window class is to fill in a WNDCLASSEX structure with the window class information. The
next step is to pass the structure to the RegisterClassEx() function.

To register an application global class, specify the CS_GLOBALCLASS style in the style member of the
WNDCLASSEX structure. When registering an application local class, do not specify the CS_GLOBALCLASS style.

If you register the window class using the ANSI version of RegisterClassEx() (RegisterClassExA()), the
application requests that the system pass text parameters of messages to the windows of the created class using the
ANSI character set. If you register the class using the Unicode version of RegisterClassEx()
(RegisterClassExW()), the application requests that the system pass text parameters of messages to the windows
of the created class using the Unicode character set. The IsWindowUnicode() function enables applications to
query the nature of each window.

The executable or DLL that registered the class is the owner of the class. The system determines class ownership from
the hInstance member of the WNDCLASSEX structure passed to the RegisterClassEx() function when the
class is registered. For DLLs, the hInstance member must be the handle to the .dll instance.

The class is not destroyed when the .dll that owns it is unloaded. Therefore, if the system calls the window procedure for
a window of that class, it will cause an access violation, because the .dll containing the window procedure is no longer in
memory. The process must destroy all windows using the class before the .dll is unloaded and call the
UnregisterClass() function.

4. Elements of a Window Class


The elements of a window class define the default behavior of windows belonging to the class. The application that
registers a window class assigns elements to the class by setting appropriate members in a WNDCLASSEX structure and
passing the structure to the RegisterClassEx() function. The GetClassInfoEx() and GetClassLong()
functions retrieve information about a given window class. The SetClassLong() function changes elements of a
local or global class that the application has already registered.

Although a complete window class consists of many elements, the system requires only that an application supply the:

 class name
 window procedure address
 instance handle

Use the other elements to define default attributes for windows of the class, such as the shape of the cursor and the
content of the menu for the window. You must initialize any unused members of the WNDCLASSEX structure to zero or
NULL. The window class elements are as shown in the following table:

Element Purpose
Class Name Distinguishes the class from other registered classes.
Pointer to the function that processes all messages sent to windows in the class and
Window Procedure Address
defines the behavior of the window.
Instance Handle Identifies the application or .dll that registered the class.
Class Cursor Defines the mouse cursor that the system displays for a window of the class.
Class Icons Defines the large icon and the small icon.
Defines the color and pattern that fill the client area when the window is opened or
Class Background Brush
painted.
Class Menu Specifies the default menu for windows that do not explicitly define a menu.
Defines how to update the window after moving or resizing it, how to process double-
Class Styles clicks of the mouse, how to allocate space for the device context, and other aspects of
the window.
Specifies the amount of extra memory, in bytes, that the system should reserve for the
Extra Class Memory class. All windows in the class share the extra memory and can use it for any
application-defined purpose. The system initializes this memory to zero.
Specifies the amount of extra memory, in bytes, that the system should reserve for
Extra Window Memory each window belonging to the class. The extra memory can be used for any
application-defined purpose. The system initializes this memory to zero.

4.1 The Class Name


Every window class needs a class name to distinguish one class from another. Assign a class name by setting the
lpszClassName member of the WNDCLASSEX structure to the address of a null-terminated string that specifies the
name. Because window classes are process specific, window class names need to be unique only within the same
process. also, because class names occupy space in the system's private atom table, you should keep class name strings
as short as possible.

The GetClassName() function retrieves the name of the class to which a given window belongs.

4.2 The Window Procedure Address


Every class needs a window-procedure address to define the entry point of the window procedure used to process all
messages for windows in the class. The system passes messages to the procedure when it requires the window to carry
out tasks, such as painting its client area or responding to input from the user. A process assigns a window procedure to
a class by copying its address to the lpfnWndProc member of the WNDCLASSEX structure.

4.3 The Instance Handle


Every window class requires an instance handle to identify the application or .dll that registered the class. The system
requires an instance handle to keep track of all of the modules. The system assigns a handle to each copy of a running
executable or .dll.

The system passes an instance handle to the entry-point function of each executable (such as WinMain()) and .dll
(DllMain()). The executable or .dll assigns this instance handle to the class by copying it to the hInstance member of
the WNDCLASSEX structure.

4.4 The Class Cursor


The class cursor defines the shape of the cursor when it is in the client area of a window in the class. The system
automatically sets the cursor to the given shape when the cursor enters the window's client area and ensures it keeps
that shape while it remains in the client area. To assign a cursor to a window class, load a predefined cursor shape by
using the LoadCursor() function and then assign the returned cursor handle to the hCursor member of the
WNDCLASSEX structure. Alternatively, provide a custom cursor resource and use the LoadCursor() function to load
it from the application's resource.

The system does not require a class cursor. If an application sets the hCursor member of the WNDCLASSEX structure
to NULL, no class cursor is defined. The system assumes the window sets the cursor shape each time the cursor moves
into the window. A window can set the cursor shape by calling the SetCursor() function whenever the window
receives the WM_MOUSEMOVE message.

4.5 The Class Icons


A class icon is a picture that the system uses to represent a window of a particular class. An application can have two
class icons - one large and one small:

 The system displays a window's large class icon in the task-switch window that appears when the user presses
ALT + TAB, and in the large icon views of the task bar and explorer.
 The small class icon appears in a window's title bar and in the small icon views of the task bar and explorer.

To assign a large and small icon to a window class, specify the handles of the icons in the hIcon and hIconSm
members of the WNDCLASSEX structure. The icon dimensions must conform to required dimensions for large and small
class icons:

 For a large class icon, you can determine the required dimensions by specifying the SM_CXICON and
SM_CYICON values in a call to the GetSystemMetrics() function.
 For a small class icon, specify the SM_CXSMICON and SM_CYSMICON values in a call to the
GetSystemMetrics() function.

If an application sets the hIcon and hIconSm members of the WNDCLASSEX structure to NULL, the system uses the
default application icon as the large and small class icons for the window class. If you specify a large class icon but not a
small one, the system creates a small class icon based on the large one. However, if you specify a small class icon but not
a large one, the system uses the default application icon as the large class icon and the specified icon as the small class
icon.

You can override the large or small class icon for a particular window by using the WM_SETICON message. You can
retrieve the current large or small class icon by using the WM_GETICON message.
4.6 The Class Background Brush
A class background brush prepares the client area of a window for subsequent drawing by the application. The system
uses the brush to fill the client area with a solid color or pattern, thereby removing all previous images from that
location whether they belong to the window or not. The system notifies a window that its background should be painted
by sending the WM_ERASEBKGND message to the window.

To assign a background brush to a class, create a brush by using the appropriate GDI functions and assign the returned
brush handle to the hbrBackground member of the WNDCLASSEX structure.

Instead of creating a brush, an application can set the hbrBackground member to one of the standard system color
values.

To use a standard system color, the application must increase the background-color value by one. For example,
COLOR_BACKGROUND + 1 is the system background color. Alternatively, you can use the GetSysColorBrush()
function to retrieve a handle to a brush that corresponds to a standard system color, and then specify the handle in the
hbrBackground member of the WNDCLASSEX structure.

The system does not require that a window class have a class background brush. If this parameter is set to NULL, the
window must paint its own background whenever it receives the WM_ERASEBKGND message.

4.7 The Class Menu


A class menu defines the default menu to be used by the windows in the class if no explicit menu is given when the
windows are created. A menu is a list of commands from which a user can choose actions for the application to carry
out.

You can assign a menu to a class by setting the lpszMenuName member of the WNDCLASSEX structure to the address
of a null-terminated string that specifies the resource name of the menu. The menu is assumed to be a resource in the
given application. The system automatically loads the menu when it is needed. If the menu resource is identified by an
integer and not by a name, the application can set the lpszMenuName member to that integer by applying the
MAKEINTRESOURCE macro before assigning the value.

The system does not require a class menu. If an application sets the lpszMenuName member of the WNDCLASSEX
structure to NULL, windows in the class have no menu bars. Even if no class menu is given, an application can still define
a menu bar for a window when it creates the window.

If a menu is given for a class and a child window of that class is created, the menu is ignored.

4.8 The Class Styles


The class styles define additional elements of the window class. Two or more styles can be combined by using the
bitwise OR (|) operator. To assign a style to a window class, assign the style to the style member of the
WNDCLASSEX structure.

4.9 Classes and Device Contexts


A device context is a special set of values that applications use for drawing in the client area of their windows. The
system requires a device context for each window on the display but allows some flexibility in how the system stores
and treats the device context.

If no device-context style is explicitly given, the system assumes each window uses a device context retrieved from a
pool of contexts maintained by the system. In such cases, each window must retrieve and initialize the device context
before painting and free it after painting.

To avoid retrieving a device context each time it needs to paint inside a window, an application can specify the
CS_OWNDC style for the window class. This class style directs the system to create a private device context - that is, to
allocate a unique device context for each window in the class. The application need only retrieve the context once and
then use it for all subsequent painting.

4.10 The Extra Class Memory


The system maintains a WNDCLASSEX structure internally for each window class in the system. When an application
registers a window class, it can direct the system to allocate and append a number of additional bytes of memory to the
end of the WNDLCASSEX structure. This memory is called extra class memory and is shared by all windows belonging to
the class. Use the extra class memory to store any information pertaining to the class.

Because extra memory is allocated from the system's local heap, an application should use extra class memory sparingly.
The RegisterClassEx() function fails if the amount of extra class memory requested is greater than 40 bytes. If an
application requires more tha 40 bytes, it should allocate its own memory and store a pointer to the memory in the
extra class memory.

The SetClassWord() and SetClassLong() functions copy a value to the extra class memory. To retrieve a value
from the extra class memory, use the GetClassWord() and GetClassLong() functions. The cbClsExtra
member of the WNDCLASSEX structure specifies the amount of extra class memory to allocate. An application that does
not use extra class memory must initialize the cbClsExtra member to zero.

4.11 The Extra Window Memory


The system maintains an internal data structure for each window. When registering a window class, an application can
specify a number of additional bytes of memory, called extra window memory. When creating a window of the class, the
system allocates and appends the specified amount of extra window memory to the end of the window's structure. An
application can use this memory to store window-specific data.

Because extra memory is allocated from the system's local heap, an application should use extra window memory
sparingly. The RegisterClassEx() function fails if the amount of extra memory requeste is greater than 40 bytes. If
an application requires more than 40 bytes, it should allocate its own memory and store a pointer to the memory in the
extra window memory.

The SetWindowLong() function copies a value to the extra memory. The GetWindowLong() function retrieves a
value from the extra memory. The cbWndExtra member of the WNDCLASSEX structure specifies the amount of extra
window memory to allocate. An application that does not use the memory must initialize cbWndExtra to zero.

Using Window Classes


The following topic includes a code example that shows how to register a local window and use it to create a main
window.

Each process must register its own window classes. To register an application local class, use the
RegisterClassEx() function. You must define the window procedure, fill the members of the WNDCLASSEX
structure, and then pass a pointer to the structure to the RegisterClassEx() function.

The following example shows how to register a local window calss and use it to create a main window:
#include <Windows.h>

// Global variable
HINSTANCE hInst;

// Function prototypes
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

// Application entry point


INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine,
int nCmdShow) {
if (!IinitApplication(hInstance))
return FALSE;

if (!InitInstance(hInstance, nCmdShow))
return FALSE;

MSG msg = {};


while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}

BOOL InitApplication(HINSTANCE hInstance) {


WNDCLASSEX wcex = {};

// Fill in the window class structure with parameters


// that describe the main window.
wcex.cbSize = sizeof(wcex); // size of structure
wcex.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes
wcex.lpfnWndProc = MainWndProc; // points to window procedure
wcex.cbClsExtra = 0; // no extra class memory
wcex.cbWndExtra = 0; // no extra window memory
wcex.hInstance = hInstance; // handle to instance
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); // predefined app icon
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // predefined arrow
wcex.hbrBackground = GetStockObject(WHITE_BRUSH); // white background
wcex.lpszMenuName = L"MainMenu"; // name of menu resource
wcex.lpszClassName = L"MainWClass"; // name of window class
wcex.hIconSm = LoadImage(hInstance, // small class icon
MAKEINTRESOURCE(5),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);

// Register the window class.


return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {


// Save the application instance handle.
hInst = hInstance;

// Create the main window.


HWND hWnd = CreateWindow(
L"MainWClass", // name of window class
L"Sample", // title bar string
WS_OVERLAPPEDWINDOW, // top-level window
CW_USEDEFAULT, // default horizontal position
CW_USEDEFAULT, // default vertical position
CW_USEDEFAULT, // default width
CW_USEDEFAULT, // default height
(HWND) NULL, // no owner window
(HMENU) NULL, // use class menu
hInstance, // handle to application instance
(LPVOID) NULL); // no window-creation data

if (!hWnd)
return FALSE;

// Show the window and send a WM_PAINT message to the window


// procedure.
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}

Registering an application global class is similar to registering an application local class, except that the style member
of the WNDCLASSEX structure must specify the CS_GLOBALCLASS style.

Window Procedures
Every window has an associated window procedure - a function that processes all messages sent or posted to all
windows of the class. All aspects of a window's appearance and behavior depend on the window procedure's response
to these messages.

About Window Procedures


Each window is a member of a particular class. The window class determines the default window procedure that an
individual window uses to process its messages. All windows belonging to the same class use the same default window
procedure. For example, the system defines a window procedure for the combo box class ( COMBOBOX). All combo
boxes then use that window procedure.
An application typically registers at least one new window class and its associated window procedure. After registering a
class, the application can create many windows of that class, all of which use the same window procedure. Because this
means several sources could simultaneously call the same piece of code, you must be careful when modifying shared
resources from a window procedure.

Window procedures for dialog boxes (called dialog box procedures) have a similar structure and function as regular
window procedures. All points referring to window procedures apply to dialog box procedures as well.

1. Structure of a Window Procedure


A window procedure is a function that has four parameters and returns a signed value. The parameters consist of:

 A HWND window handle


 A UINT message identifier
 A WPARAM message parameter
 An LPARAM message parameter

Message parameters often contain information in both their low-order and high-order words. There are several macros
an application can use to extract information from the message parameters. The LOWORD macro, for example, extracts
the low-order word (bits 0 through 15) from a message parameter. Other macros include HIWORD, LOBYTE, HIBYTE.

The interpretation of the return value depends on the particular message. Consult the description of each message to
determine the appropriate return value.

Because it is possible to call a window procedure recursively, it is important to minimize the number of local variables
that it uses. When processing individual messages, an application should call functions outside the window procedure to
avoid excessive use of local variables, possibly causing the stack to overflow during deep recursion.

2. The Default Window Procedure


The default window procedure function, DefWindowProc(), defines certain fundamental behavior shared by all
windows. The default window procedure provides the minimal functionality for a window. An application-defined
window procedure should pass any messages that it does not process to the DefWindowProc() function for default
processing.

3. Window Procedure Subclassing


When an application creates a window, the system allocates a block of memory for storing information specific to the
window, including the address of the window procedure that processes messages for the window. When the system
needs to pass a message to the window, it searches the window-specific information for the address of the window
procedure and passes the message to that procedure.

Subclassing is a technique that allows an application to intercept and process messages sent or posted to a particular
window before the window has a chance to process them. By subclassing a window, an application can subclass a
window belonging to a system global class, such as an edit control or a list box. For example, an application could
subclass an edit control to prevent the control from accepting certain characters. However, you cannot subclass a
window or class that belongs to another application. All subclassing must be performed within the same process.

An application subclasses a window by replacing the address of the window's original window procedure with the
address of a new window procedure, called the subclass procedure. Thereafter, the subclass procedure receives any
message sent or posted to the window.

The subclass procedure can take three actions upon receiving a message:

 It can pass the message to the original window procedure.


 It can modify the message and pass it to the original window procedure.
 It can process the message and not pass it to the original window procedure.

If the subclass procedure processes a message, it can do so before, after, or both before and after it passes the message
to the original window procedure.

The system provides two types of subclassing:

 Instance subclassing - In instance subclassing, an application replaces the window procedure address of a single
instance of a window. An application must use instance subclassing to subclass an existing window.
 Global subclassing - In global subclassing, an application replaces the address of the window procedure in the
WNDCLASS (or WNDCLASSEX) structure of a window class. All subsequent windows created with the class have
the address of the subclass procedure, but existing windows of the class are not affected.

3.1 Instance Subclassing


An application subclasses an instance of a window by using the SetWindowLong() function. The application passes
the GWL_WNDPROC flag, the handle to the window to subclass, and the address of the subclass procedure to
SetWindowLong(). The subclass procedure can reside in either the application's executable or a DLL.

In this case, SetWindowLong() returns the address of the window's original window procedure. The application must
save the address, using it in subsequent calls to the CallWindowProc() function, to pass intercepted messages to
the window procedure. The application must also have the original window procedure address to remove the subclass
from the window. To remove the subclass, the application calls SetWindowLong() again, passing the address of the
original window procedure with the GWL_WNDPROC flag and the handle to the window.

The system owns the system global classes, and aspects of the controls might change from one version of the system to
the next. If the application must subclass a window that belongs to a system global class, the developer may need to
update the application when a new version of the system is released.

Because instance subclassing occurs after a window is created, you cannot add any extra bytes to the window.
Applications that subclass a window should use the window's property list to store any data needed for an instance of
the subclasses window.

When an application subclasses a subclassed window, it must remove the subclasses in the reverse order they were
performed. If the removal order is not reversed, an unrecoverable system error may occur.

3.2 Global Subclassing


To globally subclass a window class, the application must have a handle to a window of the class. The application also
needs the handle to remove the subclass. To get the handle, an application typically creates a hidden window of the
class to be subclassed. After obtaining the handle, the application calls the SetClassLong() function, specifying the
handle, the GCL_WNDPROC flag, and the address of the subclass procedure. In this case, SetClassLong() returns
the address of the original window procedure for the class.

The original window procedure address is used in global subclassing in the same way it is used in instance subclassing.
The subclass procedure passes messages to the original window procedure by calling CallWindowProc(). The
application removes the subclass from the window class by calling SetClassLong() again, specifying the address of
the original window procedure, the GCL_WNDPROC flag, and the handle to a window of the class being subclassed. An
application that globally subclasses a control class must remove the subclasses when the application terminates,
otherwise an unrecoverable system error may occur.

Global subclassing has the same limitations as instance subclassing, plus some additional restrictions. An application
should not use the extra bytes for either the class or the window instance without knowing exactly how the original
window procedure uses them. If the application must associate data with a window, it should use window properties.
4. Window Procedure Superclassing
Superclassing is a technique that allows an application to create a new window class with the basic functionality of the
existing class, plus enhancements provided by the application. A superclass is based on an existing window class called
the base class. Frequently, the base class is a system global window class such as an edit control, but it can be any
window class.

A superclass has its own window procedure, called the superclass procedure. The superclass procedure can take three
actions upon receiving a message:

 It can pass the message to the original window procedure.


 It can modify the message and pass it to the original window procedure.
 It can process the message and not pass it to the original window procedure.

If the superclass procedure processes a message, it can do so before, after, or both before and after it passes the
message to the original window procedure.

Unlike a subclass procedure, a superclass procedure can process window creation messages ( WM_NCCREATE,
WM_CREATE, and so on), but it must also pass them to the original base-class window procedure so that the base-class
window procedure can perform its initialization procedure.

To superclass a window class, an application first calls the GetClassInfo() function to retrieve information about
the base class. GetClassInfo() fills a WNDCLASS structure with the values from the WNDCLASS structure of the
base class. Next, the application copies its own instance handle into the hInstance member of the WNDCLASS structure
and copies the name of the superclass into the lpszClassName member. If the base class has a menu, the application
must provide a new menu with the same menu identifiers and copy the menu name into the lpszMenuName member.
If the superclass procedure processes the WM_COMMAND message and does not pass it to the window procedure of the
base class, the menu need not have corresponding identifiers. GetClassInfo() does not return the
lpszMenuName, lpszClassName, or hInstance member of the WNDCLASS structure.

An application must also set the lpfnWndProc member of the WNDCLASS structure. The GetClassInfo()
function fills this member with the address of the original window procedure for the class. The application must save this
address, to pass messages to the original window procedure, and then copy the address of the superclass procedure
into the lpfnWndProc member. The application can, if necessary, modify any other members of the WNDCLASS
structure. After it fills the WNDCLASS structure, the application registers the superclass by passing the address of the
structure to the RegisterClass() function. The superclass can then be used to create windows.

Because superclassing registers a new window class, an application can add to both the extra class bytes and the extra
window bytes. The superclass must not use the original extra bytes for the base class or the window for the same
reasons that an instance subclass or a global subclass should not use them. Also, if the application adds extra bytes for
its use to either the class or the window instance, it must reference the extra bytes relative to the number of extra bytes
used by the original base class. Because the number of bytes used by the base class may vary from one version of the
base class to the next, the starting offset for the superclass's own extra bytes may also vary from one version of the base
class to the next.

Using Window Procedures


1. Designing a Window Procedure
The following example shows the structure of a typical window procedure. The window procedure uses the message
argument in a switch statement with individual messages handled by separate case statements. Notice that each
case returns a specific value for each message. For messages that it does not process, the window procedure calls the
DefWindowProc() function.
LRESULT CALLBACK MainWndProc(
HWND hWnd, // handle to the window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) { // second message parameter
switch (uMsg) {
case WM_CREATE:
// Initialize the window.
return 0;
case WM_PAINT:
// Paint the window's client area.
return 0;
case WM_SIZE:
// Set the size and position of the window.
return 0;
case WM_DESTROY:
// Clean up window-specific data objects.
return 0;
// Process other messages
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}

The WM_NCCREATE message is sent just after your window is created, but if an application responds to this message by
returning FALSE, the CreateWindowEx() function fails. The WM_CREATE message is sent after your window is
already created.

The WM_DESTROY message is sent when your window is about to be destroyed. The DestroyWindow() function
takes care of destroying any child windows of the window being destroyed. The WM_NCDESTROY message is sent just
before a window is destroyed.

At the very least, a window procedure should process the WM_PAINT message to draw itself. Typically, it should handle
mouse and keyboard messages as well.

Your application can call the DefWindowProc() function as part of the processing of a message. In such a case, the
application can modify the message parameters before passing the message to DefWindowProc(), or it can continue
with the default processing after performing its own operations.

2. Associating a Window Procedure with a Window Class


You associate a window procedure with a window class when registering the class. You must fill a WNDCLASS structure
with information about the class, and the lpfnWindowProc member must specify the address of the window
procedure. To register the class, pass the address of the WNDCLASS structure to the RegisterClass() function.
After the window class has been registered, the window procedure is automatically associated with each new window
created with that class.

The following example shows how to associate the window procedure in the previous example with a window class:
INT APIENTRY WinMain(
HINSTANCE hInstance, // handle to the current instance
HINSTANCE hPrevInstance, // handle to the previous instance
LPSTR lpCmdLine, // address of the command-line string
int nCmdShow) { // show-window type
WNDCLASS wc = {};

// Register the main window class.


wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MyWindowClass";

if (!RegisterClass(&wc))
return FALSE;

// Process messages.
}

3. Subclassing a Window
To subclass an instance of a window, call the SetWindowLong() function and specify the handle to the window to
subclass, the GWL_WNDPROC flag, and a pointer to the subclass procedure. SetWindowLong() returns a pointer to
the original window procedure. Use this pointer to pass messages to the original procedure. The subclass window
procedure must use the CallWindowProc() function to call the original window procedure.

It should be noted that to write code that is compatible with both 32-bit and 64-bit versions of Windows, the
SetWindowLongPtr() function should be used instead.

The following example shows how to subclass an instance of an edit control in a dialog box. The subclass window
procedure enables the edit control to receive all keyboard input, including the ENTER and TAB keys, whenever the
control has the input focus.
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditBoxProc(
HWND hWndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) {
HWND hWndEdit;

switch (uMsg) {
case WM_INITDIALOG:
// Retrieve the handle to the edit control.
hWndEdit = GetDlgItem(hWndDlg, ID_EDIT);

// Subclass the edit control.


wpOrigEditProc = (WNDPROC) SetWindowLong(hWndEdit,
GWL_WNDPROC, (LONG) EditSubclassProc);
// Continue the initialization procedure.
return TRUE;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hWndEdit, GWL_WNDPROC,
(LONG) wpOrigEditProc);
break;
}
return FALSE;
}

// Subclass procedure
LRESULT APIENTRY EditSubclassProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) {
if (uMsg == WM_GETDLGCODE)
return DLGC_WANTALLKEYS;

return CallWindowProc(wpOrigEditProc, hWnd, uMsg, wParam, lParam);


}

About Messages and Message Queues


Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function
calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.

The system passes all input for an application to the various windows in the application. Each window has a function,
called a window procedure, that the system calls whenever it has input for the window. The window procedure
processes the input and returns control to the system.

If a top-level window stops responding to messages for more than several seconds, the system considers the window to
be not responding. In this case, the system hides the window and replaces it with a ghost window that has the same z-
order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application.
However, these are the only actions available because the application is actually not responding. When in the debugger
mode, the system does not generate a ghost window.
1. Windows Messages
The system passes input to a window in the form of a message. Messages are generated by both the system and
applications:

 The system generates a message at each input event - for example, when the user types, moves the mouse, or
clicks a control such as a scroll bar. The system also generates message in response to changes in the system
brought about by an application, such as when an application changes the pool of system font resources or
resizes one of its windows.
 An application can generate messages to direct its own windows to perform tasks or to communicate with
windows in other applications..

The system sends a message to a window procedure with a set of four parameters:

 A window handle (of type HWND)


 A message identifier (of type UINT)
 Two message parameters (of type WPARAM and LPARAM)

The window handle identifies the window for which the message is intended. The system uses it to determine which
window procedure should receive the message.

A message identifier is a named constant that identifies the purpose of a message. When a window procedure receives a
message, it uses a message identifier to determine how to process the message. For example, the message identifier
WM_PAINT tells the window procedure that the window's client area has changed and must be repainted.

Message parameters specify data or the location of data used by a window procedure when processing a message. The
meaning and value of the message parameters depend on the message. A message parameter can contain an integer,
packed bit flags, a pointer to a structure containing additional data, and so on. When a message does not use message
parameters, they are typically set to NULL. A window procedure must check the message identifier to determine how to
interpret the message parameters.

2. Message Types
There are two types of windows messages:

 System-defined messages
 Application-defined messages

2.1 System-Defined Messages


The system sends or posts a system-defined message when it communicates with an application. It uses these messages
to control the operations of applications and to provide input and other information for applications to process. An
application can also send or post system-defined messages. Applications generally use these messages to control the
operation of control windows created by using preregistered window classes.

Each system-defined message has a unique message identifier and a corresponding symbolic constant (defined in the
software development kit (SDK) header files) that states the purpose of the message. For example, the WM_PAINT
constant requests that a window paint its contents.

Symbolic constants specify the category to which system-defined messages belong. The prefix of the constant identifies
the type of window that can interpret and process the message. Following are the prefixes and their related message
categories:

Prefix Message category


ABM and ABN Application desktop toolbar
ACM and ACN Animation control
BCM, BCN, BM, and BN Button control
CB and CBN ComboBox control
CBEM and CBEN ComboBoxEx control
CCM General control
CDM Common dialog box
DFM Default context menu
DL Drag list box
DM Default push button control
DTM and DTN Date and time picker control
EM and EN Edit control
HDM and HDN Header control
HKM Hot key control
IPM and IPN IP address control
LB and LBN List box control
LM SysLink control
LVM and LVN List view control
MCM and MCN Month calendar control
PBM Progress bar
PGM and PGN Pager control
PSM and PSN Property sheet
RB and RBN Rebar control
SB and SBN Status bar window
SBM Scroll bar control
SMC Shell menu
STM and STN Static control
TB and TBN Toolbar
TBM and TRBN Trackbar control
TCM and TCN Tab control
TDM and TDN Task dialog
TTM and TTN Tooltip control
TVM and TVN Tree-view control
UDM and UDN Up-down control
WM General

General windows messages cover a wide range of information and requests, including messages for mouse keyboard
input, menu and dialog box input, window creation and management, and Dynamic Data Exchange (DDE).

2.2 Application-Defined Messages


An application can create messages to be used by its own windows or to communicate with windows in other processes.
If an application creates its own messages, the window procedure that receives them must interpret the messages and
provide appropriate processing.

Message-identifier values are used as follows:

 The system reserves message-identifier values in the range 0x0000 through 0x03FF (the value of WM_USER - 1)
for system-defined messages. Applications cannot use these values for private messages.
 Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are available for message identifiers for
private window classes.
 If your application is marked version 4.0, you can use message-identifier values in the range 0x8000 ( WM_APP)
through 0xBFFF for private messages.
 The system returns a message identifier in the range 0xC000 through 0xFFFF when an application calls the
RegisterWindowMessage() function to register a message. The message identifier returned by this
function is guaranteed to be unique throughout the system. Use of this function prevents conflicts that can arise
if other applications use the same message identifier for different purposes.

3. Message Routing
The system uses two methods to route messages to a window procedure:

 Posting messages to a first-in, first-out (FIFO) queue called a message queue (a system-defined memory object
that temporarily stores messages).
 Sending messages directly to a window procedure.

A message that is posted to a message queue is called a queued message. These are primarily the result of user input
entered through the mouse or keyboard, such as WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR
messages. Other queued messages include the timer, paint, and quit messages: WM_TIMER, WM_PAINT and WM_QUIT.
Most other messages, which are sent directly to a window procedure, are called nonqueued messages.

3.1 Queued Messages


The system can display any number of windows at a time. To route mouse and keyboard input to the appropriate
window, the system uses message queues.

The system maintains a single system message queue and one thread-specific message queue for each GUI thread. To
avoid the overhead of creating a message queue for non-GUI threads, all threads are created initially without a message
queue. The system creates a thread-specific message queue only when the thread makes its first call to one of the
specific user functions. No GUI function calls result in the creation of a message queue.

Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the
mouse or keyboard converts the input into messages and places them in the system message queue. The system
removes the messages, one at a time, from the system message queue, examines them to determine the destination
window, and then posts them to the message queue of the thread that created the destination window. A thread's
message queu receives all mouse and keyboard messages for the window created by the thread. The thread removes
messages from its queue and directs the system to send them to the appropriate window procedure for processing.

With the exception of the WM_PAINT message, the WM_TIMER message, and the WM_QUIT message, the system
always posts messages at the end of a message queue. This ensures that a window receives its input messages in the
proper first-in, first-out (FIFO) sequence. The WM_PAINT message, the WM_TIMER message, and the WM_QUIT
message, however, are kept in the queue and are forwarded to the window procedure only when the queue contains no
other messages. In addition, multiple WM_PAINT messages for the same window are combined into a single WM_PAINT
message, consolidating all invalid parts of the client area into a single area. Combining WM_PAINT messages reduces
the number of times a window must redraw the contents of its client area.

The system posts a message to a thread's message queue by filling an MSG structure and then copying it to the message
queue. Information in MSG includes:

 The handle of the window for which the message is intended


 The message identifier
 The two message parameters
 The time the message was posted
 The mouse cursor position

A thread can post a message to its own message queue or to the queue of another thread by using the
PostMessage() or PostThreadMessage() function.
An application can remove a message from its queue by using the GetMessage() function. To examine a message
without removing it from its queue, an application can use the PeekMessage() function. This function fills an MSG
object with information about the message.

After removing a message from its queue, an application can use the DispatchMessage() function to direct the
system to send the message to a window procedure for processing. DispatchMessage() takes a pointer to MSG
that was filled by a previous call to the GetMessage() or PeekMessage() function. DispatchMessage()
passes the window handle, the message identifier, and the two message parameters to the window procedure, but it
does not pass the time the message was posted or mouse cursor position. An application can retrieve this information
by calling the GetMessageTime() and GetMessagePos() functions while processing a message.

A thread can use the WaitMessage() function to yield control to other threads when it has no messages in its queue.
The function suspends the thread and does not return until a new message is placed in the thread's message queue.

You can call the SetMessageExtraInfo() function to associate a value with the current thread's message queue.
Then call the GetMessageExtraInfo() function to get the value associated with the last message retrieved by the
GetMessage() or PeekMessage() function.

3.2 Nonqueued Messages


Nonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue
and thread message queue. The system typically sends nonqueued messages to notify a window of events that affect it.
For example, when the user activates a new application window, the system sends the window a series of messages,
including WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR. These messages notify the window that it has been
activated, that keyboard input is being directed to the window, and that the mouse cursor has been moved within the
borders of the window. Nonqueued messages can also result when an application calls certain system functions. For
example, the system sends the WM_WINDOWPOSCHANGED message after an application uses the SetWindowPos()
function to move a window.

Some functions that send nonqueued messages are:

 BroadcastSystemMessage()
 BroadcastSystemMessageEx()
 SendMessage()
 SendMessageTimeout()
 SendNotifyMessage()

4. Message Handling
An application must remove and process messages posted to the message queue of its threads. A single-threaded
application usually uses a message loop in its WinMain() function to remove and send messages to the appropriate
window procedures for processing. Applications with multiple threads can include a message loop in each thread that
creates a window.

4.1 The Message Loop


A simple message loop consists of one function call to each of these three functions:

 GetMessage()
 TranslateMessage()
 DispatchMessage()

Note that if there is an error, GetMessage() returns -1, thus the need for the special testing:
MSG msg = {};
BOOL bRet;

while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {


if (bRet == -1) {
// Handle the error and possibly exit.
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

The GetMessage() function retrieves a message from the queue and copies it to a structure of type MSG. It returns a
nonzero value, unless it encounters the WM_QUIT message, in which case it returns FALSE and ends the loop. In a
single-threaded application, ending the message loop is often the first step in closing the application. An application can
end its own loop by using the PostQuitMessage() function, typically in response to the WM_DESTROY message in
the window procedure of the application's main window.

If you specify a window handle as the second parameter of GetMessage(), only messages for the specified window
are retrieved from the queue. GetMessage() can also filter messages in the queue, retrievign only those messages
that fall within a specified range.

A thread's message loop must include TranslateMessage() if the thread is to receive character input from the
keyboard. The system generates virtual-key messages (WM_KEYDOWN and WM_KEYUP) each time the user presses a
key. A virtual-key message contains a virtual-key code that identifies which key was pressed, but not its character value.
To retrieve this value, the message loop must contain TranslateMessage(), which translates the virtual-key
message into a character message (WM_CHAR) and places it back into the application message queue. The character
message can then be removed upon a subsequent iteration of the message loop and dispatched to a window procedure.

The DispatchMessage() function sends a message to the window procedure associated with the window handle
specified in the MSG structure. If the window handle is HWND_TOPMOST, DispatchMessage() sends the message
to the window procedures of all top-level windows in the system. If the window handle is NULL,
DispatchMessage() does nothing with the message.

An application's main thread starts its message loop after initializing the application and creating at least one window.
After it is started, the message loop continues to retrieve messages from the thread's message queue and to dispatch
them to the appropriate windows. The message loop ends when the GetMessage() function removes the WM_QUIT
message from the queue.

Only one message loop is needed for a message queue, even if an application contains many windows.
DispatchMessage() always dispatches the message to the proper window. This is because each message in the
queue is an MSG structure that contains the handle of the window to which the message belongs.

You can modify a message loop in a variety of ways. For example, you can retrieve messages from the queue without
dispatching them to a window. This is useful for applications that post messages not specifying a window. You can also
direct GetMessage() to search for specific messages, leaving other messages in the queue. This is useful if you must
temporarily bypass the usual FIFO order of the message queue.

An application that uses accelerator keys must be able to translate keyboard messages into command messages. To do
this, the application's message loop must include a call to the TranslateAccelerator() function.

If a thread uses a modeless dialog box, the message loop must include the IsDialogMessage() function so that the
dialog box can receive keyboard input.
4.2 The Window Procedure
A window procedure is a function that receives and processes all messages sent to the window. Every window class has
a window procedure, and every window created with that class uses the same window procedure to respond to
messages.

The system sends a message to a window procedure by passing the message data as arguments to the procedure. The
window procedure then performs an appropriate action for the message. It checks the message identifier and, while
processing the message, uses the information specified by the message parameters.

A window procedure does not usually ignore a message. If it does not process a message, it must send the message back
to the system for default processing. The window procedure does this by calling the DefWindowProc() function,
which performs a default action and returns a message result. The window procedure must then return this value as its
own message result. Most window procedures process just a few messages and pass the others on the system by calling
DefWindowProc().

Because a window procedure is shared by all windows belonging to the same class, it can process a message for several
different windows. To identify the specific window affected by the message, a window procedure can examine the
window handle passed with a message.

5. Message Filtering
An application can choose specific messages to retrieve from the message queue (while ignoring other messages) by
using the GetMessage() or PeekMessage() function to specify a message filter. The filter is a range of message
identifiers (specified by a first and last identifier), a window handle, or both. GetMessage() and PeekMessage()
use a message filter to select which messages to retrieve from the queue. Message filtering is useful if an application
must search the message queue for messages that have arrived later in the queue. It is also useful if an application must
process input (hardware) messages before processing posted messages.

The WM_KEYFIRST and WM_KEYLAST constants can be used as filter values to retrieve all keyboard messages. The
WM_MOUSEFIRST and WM_MOUSELAST constants can be used to retrieve all mouse messages.

Any application that filters messages must ensure that a message satisfying the message filter can be posted. For
example, if an application filters for a WM_CHAR message in a window that does not receive keyboard input, the
GetMessage() function does not return. This effectively "hangs" the application.

6. Posting and Sending Messages


Any application can post and send messages. Like the system, an application posts a message by copying it to a message
queue and sends a message by passing the message data as arguments to a window procedure. To post messages, an
application uses the PostMessage() function. An application can send a message by calling the SendMessage(),
BroadcastSystemMessage(), SendMessageCallback(), SendMessageTimeout(),
SendNotifyMessage(), or SendDlgItemMessage() function.

6.1 Posting Messages


An application typically posts a message to notify a specific window to perform a task. PostMessage() creates an
MSG structure for the message and copies the message to the message queue. The application's message loop
eventually retrieves the message and dispatches it to the appropriate window procedure.

An application can post a message without specifying a window. If the application supplies a NULL window handle when
calling PostMessage(), the message is posted to the queue associated with the current thread. Because no window
handle is specified, the application must process the message in the message loop. This is one way to create a message
that applies to the entire application, instead of to a specific window.
Occasionally, you may want to post a message to all top-level windows in the system. An application can post a message
to all top-level windows by caling PostMessage() and specifying HWND_TOPMOST in the hWnd parameter.

A common programming error is to assume that the PostMessage() function always posts a message. This is not
true when the message queue is full. An application should check the return value of the PostMessage() function to
determine whether the message has been posted and, if it has not been, repost it.

6.2 Sending Messages


An application typically sends a message to notify a window procedure to perform a task immediately. The
SendMessage() function sends the message to the window procedure corresponding to the given window. The
function waits until the window procedure completes processing and then returns the message result. Parent and child
windows often communicate by sending messages to each other. For example, a parent window that has an edit control
as its child window can set the text of the control by sending a message to it. The control can notify the parent window
of changes to the text that are carried out by the user by sending messages back to the parent.

The SendMessageCallback() function also sends a message to the window procedure corresponding to the given
window. However, this function returns immediately. After the window procedure processes the message, the system
calls the specified callback function. For more information about the callback function, see the SendAsyncProc()
function.

Occasionally, you may want to send a message to all top-level windows in the system. For example, if the application
changes the system time, it must notify all top-level windows about the change by sending a WM_TIMECHANGE
message. An application can send a message to all top-level windows by calling SendMessage() and specifying
HWND_TOPMOST in the hWnd parameter. You can also broadcast a message to all applications by calling the
BroadcastSystemMessage() function and specifying BSM_APPLICATIONS in the lpdwRecipients
parameter.

By using the InSendMessage() or InSendMessageEx() function, a window procedure can determine whether it
is processing a message sent by another thread. This capability is useful when message processing depends on the origin
of the message.

7. Message Deadlocks
A thread that calls the SendMessage() function to send a message to another thread cannot continue executing until
the window procedure that receives the message returns. If the receiving thread yields control while processing the
message, the sending thread cannot continue executing, because it is waiting for SendMessage() to return. If the
receiving thread is attached to the same queue as the sender, it can cause an application deadlock to occur. (Note that
journal hooks attach threads to the same queue.)

Note that the receiving thread need not yield control explicitly. Calling any of the following functions can cause a thread
to yield control implicitly:

 DialogBox()
 DialogBoxIndirect()
 DialogBoxIndirectParam()
 DialogBoxParam()
 GetMessage()
 MessageBox()
 PeekMessage()
 SendMessage()
To avoid potential deadlocks in your application, consider using the SendNotifyMessage() or
SendMessageTimeout() functions. Otherwise, a window procedure can determine whether a message it has
received was sent by another thread by calling the InSendMessage() or InSendMessageEx() function. Before
calling any of the functions in the preceding list while processing a message, the window procedure should first call
InSendMessage() or InSendMessageEx(). If this function returns TRUE, the window procedure must call the
ReplyMessage() function before any function that causes the thread to yield control.

8. Broadcasting Messages
Each message consists of a message identifier and two parameters, wParam and lParam. The message identifier is a
unique value that specifies the message purpose. The parameters provide additional information that is message-
specific, but the wParam parameter is generally a type value that provides more information about the message.

A message broadcast is simply the sending of a message to multiple recipients in the system. To broadcast a message
from an application, use the BroadcastSystemMessage() function, specifying the recipients of the message.
Rather than specifying individual recipients, you must specify one or more types of recipients. These types are
applications, installable drivers, network drivers, and system-level drivers. The system sends broadcast messages to all
members of each specified type.

The system typically broadcasts messages in response to changes that take place within system-level device drivers or
related components. The driver or related component broadcasts the message to applications and other components to
notify them of the change. For example, the component responsible for disk drives broadcasts a message whenever the
device driver for the floppy disk drive detects a change of media such as when the user inserts a disk in the drive.

The system broadcasts messages to recipients in this order:

1. System-level device drivers


2. Network drivers
3. Installable drivers
4. Applications

This means that system-level device drivers, if chosen as recipients, always get the first opportunity to respond to a
message. Within a given recipient type, no driver is guaranteed to receive a given message before any other driver. This
means that a message intended for a specific driver must have a globally-unique message identifier so that no other
driver unintentionally processes it.

You can also broadcast messages to all top-level windows by specifying HWND_BROADCAST in the SendMessage(),
SendMessageCallback(), SendMessageTimeout() or SendNotifyMessage() function.

Applications receive messages through the window procedure of their top-level windows. Messages are not sent to child
windows. Services can receive messages through a window procedure or their service control handlers.

It should be noted that system-level device drivers use a relayed, system-level function to broadcast system messages.

9. Query Messages
You can create your own custom messages and use them to coordinate activities between your applications and other
components in the system. This is especially useful if you have created your own installable drivers or system-level
device drivers. Your custom messages can carry information to and from your driver and the applications that use the
driver.

To poll recipients for permission to carry out a given action, use a query message. You can generate your own query
messages by setting the BSF_QUERY value in the dwFlags parameter when calling
BroadcastSystemMessage(). Each recipient of the query message must return TRUE for the function to send the
message to the next recipient. If any recipient returns BROADCAST_QUERY_DENY, the broadcast ends immediately
and the function returns a zero.

Using Messages and Message Queues


1. Creating a Message Loop
The system does not automatically create a message queue for each thread. Instead, the system creates a message
queue only for the threads that perform operations which require a message queue. If the thread creates one or more
windows, a message loop must be provided. This message loop retrieves messages from the thread's message queue
and dispatches them to the appropriate window procedures.

Because the system directs messages to individual windows in the application, a thread must create at least one window
before starting its message loop. Most applications contain a single thread that creates windows. A typical application
registers the window class for its main window, creates and shows the main window, and then starts its message loop -
all in the WinMain() function.

You create a message loop by using the GetMessage() and DispatchMessage() functions. If your application
must obtain character input from the user, incldue the TranslateMessage() function in the loop.
TranslateMessage() translates virtual-key messages into character messages. The following example shows the
message loop in the WinMain() function of a simple Windows-based application:
HINSTANCE hInst;
HWND hWndMain;

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpszCmdLine, int nCmdShow) {
MSG msg = {};
BOOL bRet;
WNDCLASS wc = {};

// Register the window class for the main window.


if (!hPrevInstance) {
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MyWindowClass";

if (!RegisterClass(&wc))
return FALSE;
}

hInst = hInstance; // Save the instance handle.

// Create the main window.


hWndMain = CreateWindow("MyWindowClass", "Sample",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
(HWND) NULL, (HMENU) NULL, hInst, (LPVOID) NULL);

// If the application window cannot be created, terminate


// the application.
if (!hWndMain)
return FALSE;

// Show the window and paint its contents.


ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);

// Start the message loop.


while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
// Handle the error and possibly exit.
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

// Return the exit code to the system.


return msg.wParam;
}

The following example shows a message loop for a thread that uses accelerators and displays a modeless dialog box.
When TranslateAccelerator() or IsDialogMessage() returns TRUE (indicating that the message has been
processed), TranslateMessage() and DispatchMessage() are not called. The reason for this is that
TranslateAccelerator() and IsDialogMessage() performs all necessary translating and dispatching of
messages.
HWND hWndMain;
HWND hWndDlgModeless = NULL;
MSG msg;
BOOL bRet;
HACCEL haccel;

// Perform initialization and create a main window.

while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {


if (bRet == -1) {
// Handle the error and possibly exit.
} else {
if (hWndDlgModeless == (HWND) NULL)
|| !IsDialogMessage(hWndDlgModeless, &msg)
&& !TranslateAccelerator(hWndMain, haccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

2. Examining a Message Queue


Occasionally, an application needs to examine the contents of a thread's message queue from outside the thread's
message loop. For example, if an application's window procedure performs a lengthy drawing operation, you may want
the user to be able to interrupt the operation. Unless your application periodically examines the message queue during
the operation for mouse and keyboard messages, it will not respond to user input until after the operation has
completed. The reason for this is that the DispatchMessage() function in the thread's message loop does not
return until the window procedure finishes processing a message.

You can use the PeekMessage() function to examine a message queue during a lengthy operation.
PeekMessage() is similar to the GetMessage() function - both check a message queue for a message that
matches the filter criteria and then copy the message to an MSG structure. The main difference between the two
functions is that GetMessage() does not return until a message matching the filter criteria is placed in the queue,
whereas PeekMessage() returns immediately regardless of whether a message is in the queue.

The following example shows how to use PeekMessage() to examine a message queue for mouse clicks and
keyboard input during a lengthy operation:
HWND hWnd;
BOOL fDone;
MSG msg;

// Begin the operation and continue until it is complete


// or until the user clicks the mouse or presses a key.

fDone = FALSE;
while (!fDone) {
fDone = DoLengthyOperation(); // application-defined function

// Remove any messages that may be in the queue. If the


// queue contains any mouse or keyboard messages,
// end the operation.
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) {
switch (msg.message) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_KEYDOWN:
// Perform any required cleanup.
fDone = TURE;
}
}
}

Other functions, including GetQueueStatus() and GetInputState(), also allow you to examine the contents of
a thread's message queue:

 GetQueueState() - Returns an array of flags that indicates the types of messages in the queue. Using it is
the fastest way to discover whether the queue contains any messages.
 GetInputState() - Returns TRUE if the queue contains mouse or keyboard messages. Both of these
functions can be used to determine whether the queue contains messages that need to be processed.
3. Posting a Message
You can post a message to a message queue by using the PostMessage() function. PostMessage() places a
message at the end of a thread's message queue and returns immediately, without waiting for the thread to process the
message. The function's parameters include a window handle, a message identifier, and two message parameters. The
system copies these parameters to an MSG structure, fills the time and pt members of the structure, and places the
structure in the message queue.

The system uses the window handle passed with the PostMessage() function to determine which thread message
queue should receive the message. If the handle is HWND_TOPMOST, the system posts the message to the thread
message queue of all top-level windows.

You can use the PostThreadMessage() function to post a message to a specific thread message queue.
PostThreadMessage() is similar to PostMessage(), except the first parameter is a thread identifier rather than
a window handle. You can retrieve the thread identifier by calling the GetCurrentThreadId() function.

Use the PostQuitMessage() function to exit a message loop. PostQuitMessage() posts the WM_QUIT
message to the currently executing thread. The thread's message loop terminates and returns control to the system
when it encounters the WM_QUIT message. An application usually calls PostQuitMessage() in response to the
WM_DESTROY message, as shown in the following example:
case WM_DESTROY:
// Perform cleanup tasks.
PostQuitMessage(0);
break;

4. Sending a Message
The SendMessage() function is used to send a message directly to a window procedure. SendMessage() calls a
window procedure and waits for that procedure to process the message and return a result.

A message can be sent to any window in the system. All that is required is a window handle. The system uses the handle
to determine which window procedure should receive the message.

Before processing a message that may have been sent from another thread, a window procedure should first call the
InSendMessage() function. If this function returns TRUE, the window procedure should call ReplyMessage()
before any function that causes the thread to yield control, as shown in the following example:
case WM_USER + 5:
if (InSendMessage())
ReplyMessage(TRUE);
DialogBox(hInst, "MyDialogBox", hWndMain, (DLGPROC) MyDlgProc);
break;

A number of messages can be sent to controls in a dialog box. These control messages set the appearance, behavior, and
content of controls or retrieve information about controls. For example, the CB_ADDSTRING message can add a string
to a combo box, and the BM_SETCHECK message can set the check state of a check box or radio button.

Use the SendDlgItemMessage() function to send a message to a control, specifying the identifier of the control
and the handle of the dialog box window that contains the control. The following example, taken from a dialog box
procedure, copies a string from a combo box's edit control into its list box. The example uses
SendDlgItemMessage() to send a CB_ADDSTRING message to the combo box:
HWND hWndCombo;
int cTxtLen;
PSTR pszMem;

switch (uMsg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDD_ADDCBITEM:
// Get the handle of the combo box and the
// length of the string in the edit control
// of the combo box.
hWndCombo = GetDlgItem(hWndDlg, IDD_COMBO);
cTxtLen = GetWindowTextLength(hWndCombo);

// Allocate memory for the string and copy


// the string into the memory.
pszMem = (PSTR) VirtualAlloc((LPVOID) NULL,
(DWORD) (cTxtLen + 1), MEM_COMMIT,
PAGE_READWRITE);
GetWindowText(hWndCombo, pszMem,
cTxtLen + 1);

// Add the string to the list box of the


// combo box and remove the string from the
// edit control of the combo box.
if (pszMem != NULL) {
SendDlgItemMessage(hWndDlg, IDD_COMBO,
CB_ADDSTRING, 0,
(DWORD) ((LPSTR) pszMem));
SetWindowText(hWndCombo, (LPSTR) NULL);
}

// Free the memory and return.


VirtualFree(pszMem, 0, MEM_RELEASE);
return TRUE;

// Process other dialog box commands.


}
// Process other dialog box messages.
}

Timers
A timer is an internal routine that repeatedly measures a specified interval, in milliseconds.
About Timers
An application uses a timer to schedule an event for a window after a specified time has elapsed. Each time the specified
interval (or time-out value) for a timer elapses, the system notifies the window associated with the timer. Because a
timer's accuracy depends on the system clock rate and how often the application retrieves messages from the queue,
the time-out value is only approximate.

1. Timer Operations
Applications create timers by using the SetTimer() function. A new timer starts timing the interval as soon as its
created. An application can change a timer's time-out value by using SetTimer() and can destroy a timer by using the
KillTimer() function. To use system resources efficiently, applications should destroy timers that are no longer
necessary.

Each timer has a unique identifier. When creating a timer, an application can either specify an identifier or have the
system create a unique value. The first parameter of a WM_TIMER message contains the identifier of the timer that
posted the message.

If you specify a window handle in the call to SetTimer(), the application associates the timer with that window.
Whenever the time-out value for the timer elapses, the system posts a WM_TIMER message to the window associated
with the timer. If no window handle is specified in the call to SetTimer(), the application that created the timer must
monitor its message queue for WM_TIMER messages and dispatch them to the appropriate window. If you specify a
TimerProc() callback function, the default window procedure calls the callback function when it processes
WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc()
instead of processind WM_TIMER.

If you need to be notified when a timer elapses, use a waitable timer.

2. High-Resolution Timer
A counter is a general term used in programming to refer to an incrementing variable. Some systems include a high-
resolution performance counter that provides high-resolution elapsed times.

If a high-resolution performance counter exists on the system, you can use the QueryPerformanceFrequency()
function to express the frequency, in counts per second. The value of the count is processor dependent. On some
processors, for example, the count might be the cycle rate of the processor clock.

The QueryPerformanceCounter() function retrieves the current value of the high-resolution performance counter. By
calling this function at the beginning and end of a section of code, an application essentially uses the counter as a high-
resolution timer. For example, suppose that QueryPerformanceFrequency() indicates that the frequency of the high-
resolution performance counter is 50,000 counts per second. If the application calls QueryPerformanceCounter()
immediately before and immediately after the section of code to be timed, the counter values might be 1500 counts and
3500 counts, respectively. These values would indicate that 0.04 seconds (2000 counts) elapsed while the code
executed.

Menus
A menu is a list of items that specify options or groups of options (a submenu) for an application. Clicking a menu item
opens a submenu or causes the application to carry out a command.

About Menus
1. Menu Bars and Menus
A menu is arranged in a hierarchy - at the top level of the hierarchy is the menu bar, which contains a list of menus,
which in turn can contain submenus. A menu bar is sometimes called a top-level menu, and the menus and submenus
are also known as pop-up menus.

A menu item can either carry out a command or open a submenu. An item that carries out a command is called a
command item or a command.

An item on the menu bar almost always opens a menu. Menu bars rarely contain command items. A menu opened from
the menu bar drops down from the menu bar and is sometimes called a drop-down menu. When a drop-down menu is
displayed, it is attached to the menu bar. A menu item on the menu bar that opens a drop-down menu is also called a
menu name.

The menu names on a menu bar represent the main categories of commands that an application provides. Selecting a
menu name from the menu bar typically opens a menu whose menu items correspond to the commands in a category.
For example, a menu bar might contain a File menu name that, when clicked by the user, activates a menu with menu
items such as New, Open, and Save. To get information about a menu bar, call the GetMenuBarInfo() function.

Only an overlapped or pop-up window can contain a menu bar. A child window cannot contain one. If the window has a
title bar, the system positions the menu bar just below it. A menu bar is always visible. A submenu is not visible,
however, until the user selects a menu item that activates it.

Each menu must have an owner window. The system sends messages to a menu's owner window when the user selects
the menu or chooses an item from the menu.

1.1 Shortcut Menus


The system also provides shortcut menus. A shortcut menu is not attached to the menu bar. It can appear anywhere on
the screen. An application typically associates a shortcut menu with a portion of a window, such as the client area, or
with a specific object, such as an icon. For this reason, these menus are also called context menus.

A shortcut menu remains hidden until the user activates it, typically by right-clicking a selection, a toolbar, or a taskbar
button. The menu is usually displayed at the position of the caret or mouse cursor.

1.2 The Window Menu


The Window menu (also known as the System menu or Control menu) is a pop-up menu defined and managed almost
exclusively by the operating system. The user can open the window menu by clicking the application icon on the title bar
or by right-clicking anywhere on the title bar.

The window menu provides a standard set of menu items that the user can choose to change a window's size or
position, or close the application. Items on the window menu can be added, deleted, and modified, but most
applications just use the standard set of menu items. An overlapped, pop-up, or child window can have a window menu.
It is uncommon for an overlapped or pop-up window not to include a window menu.

When the user chooses a command from the window menu, the system sends a WM_SYSCOMMAND message to the
menu's owner window. In most applications, the window procedure does not process messages from the window menu.
Instead, it simply passes the messages to the DefWindowProc() function for system-default processing of the
message. If an application adds a command to the window menu, the window procedure must process the command.
An application can use the GetSystemMetrics() function to create a copy of the default window menu to modify.
Any window that does not use the GetSystemMenu() function to make its own copy of the window receives the
standard window menu.

1.3 Help Identifier


Associated with each menu bar, menu, submenu, and shortcut menu is a help identifier. If the user presses the F1 key
while the menu is active, this value is sent to the owner window as part of a WM_HELP message.

2. Keyboard Access to Menus


The system provides a standard keyboard interface for menus. You can enhance this interface by providing mnemonic
access keys and shortcut (accelerator) keys for your menu items.

2.1 Standard Keyboard Interface


The system is designed to work with or without a mouse or other pointing device. Because the system provides a
standard keyboard interface, the user can use the keyboard to select menu items. This keyboard interface does not need
special code. An application receives a command message whether the user selects a menu item through the keyboard
or by using a mouse. The standard keyboard interface processes the following keystrokes:

Keystroke Action
Selects the first menu item with the specified character as its access key. If the selected
Alphabetical character item invokes a menu, the menu is displayed and the first item is highlighted. Otherwise,
the menu item is chosen.
ALT Toggles in and out of menu bar mode.
ALT + SPACEBAR Displays the window menu.
Activates a menu and selects the first menu item if an item has a menu associated with
ENTER it. Otherwise, this keystroke chooses the item as if the user released the mouse button
while the item was selected.
ESC Exists menu mode.
Cycles to the previous top-level menu item. Top-level menu items include menu names
LEFT ARROW and the window menu. If the selected item is in a menu, the previous column in the
menu is selected or the previous top-level menu item is selected.
Works like the LEFT ARROW key, except in the opposite direction. In menus, this
RIGHT ARROW keystroke moves forward one column. When the currently selected item is in the far-
right column, the next menu is selected.
Activates a menu when pressed in a menu name. When pressed in a menu, the UP
UP or DOWN ARROWS ARROW keystroke selects the previous item. The DOWN ARROW keystroke selects the
next item.

2.2 Menu Access Keys


The standard keyboard interface for menus can be enhanced by adding access keys (mnemonics) to menu items. An
acces key is an underlined letter in the text of a menu item. When a menu is active, the user can select a menu item by
pressing the key that corresponds to that item's underlined letter. The user makes the menu bar active by pressing the
ALT key to highlight the first item on the menu bar. A menu is active when it is displayed.

To create an access key for a menu item, precede any character in the item's text string with an ampersand (&). For
example, the text string "&Move" causes the system to underline the letter "M".

2.3 Menu Shortcut Keys


In addition to having an access key, a menu item can have a shortcut key associated with it. A shortcut key is different
from an acces key, because the menu does not have to be active for the shortcut key to work. Also, an access key is
always associated with a menu item, while a shortcut key is usually (but does not have to be) associated with a menu
item.
Text that identifies a shortcut key is added to the menu-item text string. The shortcut text appears to the right of the
menu item name, after a backslash and tab character (\t). For example, "&Close\tAlt+F4" represents a Close command
with the ALT + F4 key combination as its shortcut key and with the letter "C" as its acces key.

3. Menu Creation
You can create a menu using either a menu template or menu creation functions. Menu templates are typically defined
as resources. Menu-template resources can be loaded explicitly or assigned as the default menu for a window class. You
can also create menu-template resources dynamically in memory.

3.1 Menu Template Resources


Most applications create menus using menu-template resources. A menu template defines a menu, including the items
in the menu bar and all menus. For information about creating a menu-template resource, see the documentation
included with your development tools.

After you create a menu-template resource and add it to your application's executable (.exe) file, you can use the
LoadMenu() function to load the resource into memory. This function returns a handle to the menu, which you can
then assign to a window by using the SetMenu() function. You can assign a menu to any window that is not a child
window.

Implementing menus as resources makes an application easier to localize for use in multiple countries/regions. Only the
resource-definition file needs to be localized for each language, not the application's source code.

3.2 Menu Template in Memory


A memory can be created from a menu template that is built in memory at run time. For example, an application that
allows a user to customize its menu might create a menu template in memory based on the user's preferences. The
application could then save the template in a file or in the registry for future use. To create a menu from a template in
memory, use the LoadMenuIndirect() function.

A standard menu template consists of a MENUITEMTEMPLATEHEADER structure followed by one or more


MENUITEMTEMPLATE structures.

An extended menu template consists of a MENUEX_TEMPLATE_HEADER structure followed by one or more


MENUEX_TEMPLATE_ITEM structures.

3.3 Menu Handles


The system generates a unique handle for each menu. A menu handle is a value of the HMENU type. An application must
specify a menu handle in many of the menu functions. You receive a handle to a menu bar when you create the menu or
load a menu resource.

To retrieve a handle to the menu bar for a menu that has been created or loaded, use the GetMenu() function. To
retrieve a handle to the submenu associated with a menu item, use the GetSubMenu() or GetMenuItemInfo()
function. To retrieve a handle to a window menu, use the GetSystemMenu() function.

3.4 Menu Creation Functions


Using menu creation functions, you can create menus at run time or add menu items to existing menus. You can use the
CreateMenu() function to create an empty menu bar and the CreatePopupMenu() function to create an empty
menu. You can save certain settings information for a menu by using the MENUINFO structure. To get or retrieve the
settings of a menu, use GetMenuInfo() or SetMenuInfo(). To add items to a menu, use the
InsertMenuItem() function. The older AppendMenu() and InsertMenu() functions are still supported, but
InsertMenuItem() should be used for new applications.
3.5 Menu Display
After a menu has been loaded or created, it must be assigned to a window before the system can display it. You can
assign a menu by defining a class menu. You can also assign a menu to a window by specifying a handle to the menu as
the hMenu parameter of the CreateWindow() or CreateWindowEx() function, or by calling the SetMenu()
function.

To display a shortcut menu use the TrackPopupMenuEx() function. Shortcut menus, also called floating pop-up
menus or context menus, are typically displayed when the WM_CONTEXTMENU message is processed.

You can assign a menu to any window that is not a child window.

The older TrackPopupMenu() function is still supported, but new applications should use the
TrackPopupMenuEx() function.

3.6 Window Class Menus


You can specify a default menu, called a class menu, when you register a window class. To do so, you assign the name of
the menu-template resource to the lpszMenuName member of the WNDCLASS structure used to register the class.

By default, every window is assigned the class menu for its window class so you do not need to explicitly load the menu
and assign it to each window. You can override the class menu by specifying a different menu handle in a call to the
CreateWindowEx() function. You can also change a window's menu after it is created by using the SetMenu()
function.

4. Menu Items
4.1 Command Items and Items that Open Submenus
When the user chooses a command item, the system sends a command message to the window that owns the menu:

 If the command is on the window menu, the system sends the WM_SYSCOMMAND message.
 Otherwise, the system sends the WM_COMMAND message.

Associated with each menu item that opens a submenu is a handle to the corresponding submenu. When the user
points to such an item, the system opens the submenu. No command message is sent to the owner window. However,
the system sends a WM_INITMENUPOPUP message to the owner window before displaying the submenu. You can get
the handle to the submenu associated with an item by using the GetSubMenu() or GetMenuItemInfo() function.

A menu bar typically contains menu names, but it can also contain command items. A submenu typically contains
command items, but it can also contain items that open nested submenus. By adding such items to submenus, you can
nest menus to any depth. To provide a casual cue for the user, the system automatically displays a small arrow to the
right of the text of a menu item that opens a submenu.

4.2 Menu-Item Identifier


Associated with each menu item is a unique, application-defined integer, called a menu-item identifier. When the user
chooses a command item from a menu, the system sends the item's identifier to the owner window as part of a
WM_COMMAND message. The window procedure examines the identifier to determine the source of the message, and
processes the message accordingly. In addition, you can specify a menu item using its identifier when you call menu
functions. For example, to enable or disable a menu item.

Menu items that open submenus have identifiers just as command items do. However, the system does not send a
command message when such an item is selected from a menu. Instead, the system opens the submenu associated with
the menu item.

To retrieve the identifier of the menu item at a specified position, use the GetMenuItemID() or
GetMenuItemInfo() function.
4.3 Menu-Item Position
In addition to having a unique identifier, each menu item in a menu bar or menu has a unique position value. The
leftmost item in a menu bar, or the top item in a menu, has position zero. The position value is incremented for
subsequent menu items. The system assigns a position value to all items in a menu, including separators. The following
illustration shows the position values of items in a menu bar and in a menu:

When calling a menu function that modifies or retrieves information about a specific menu item, you can specify the
item using either its identifier or its position.

4.4 Accessing Menu Items Programatically


Most menu functions allow you to specify a menu item either by position or by command. Some functions use the
MF_BYPOSITION and MF_BYCOMMAND flags to indicate the search algorithms. Others have an explicit
fByPosition parameter. If you specify the menu item by position, the item number is a zero-based index into the
menu. If you specify the menu item by command, the menu and its submenus are searched for an item whose menu
identifier equals the item number provided. If more than one item in the menu hierarchy matches the item number, it is
unspecified which one is used. If your menus contain duplicate menu identifiers, you should use position-based menu
operations to avoid this ambiguity

4.5 Default Menu Items


A submenu can contain one default menu item. When the user opens a submenu by double-clicking, the system sends a
command message to the menu's owner window and closes the menu as if the default command item had been chosen.
If there is no default command item, the submenu remains open. To retrieve and set the default item for a submenu,
use the GetMenuDefaultItem() and SetMenuDefaultItem() functions.

4.6 Selected and Clear Menu Items


A menu item can be either selected or clear. The system displays a bitmap next to selected menu items to indicate their
selected state. The system does not display a bitmap next to clear items, unless an application-defined "clear" bitmap is
specified. Only menu items in a menu can be selected. Items in a menu bar cannot be selected.

Applications typically check or clear a menu item to indicate whether an option is in effect. For example, suppose an
application has a toolbar that the user can show or hide by using a Toolbar command on a menu. When the toolbar is
hidden, the Toolbar menu item is clear. When the user chooses the command, the application checks the menu item
and shows the toolbar.

A check mark attribute controls whether a menu item is selected. You can set a menu item's check mark attribute by
using the CheckMenuItem() function. You can use the GetMenuState() function to determine whether a menu
item is currently selected or cleared.

Instead of CheckMenuItem() and GetMenuState(), you can use the GetMenuItemInfo() and
SetMenuItemInfo() functions to retrieve and set the check state of a menu item.

Sometimes, a group of menu items corresponds to a set of mutually exclusive options. In this case, you can indicate the
selected option by using a selected radio menu item (analogous to a radio button control). Selected radio items are
displayed with a bullet bitmap instead of a check mark bitmap. To check a menu item and make it a radio item, use the
CheckMenuRadioItem() function.

By default, the system displays a check mark or bullet bitmap next to selected menu items, and no bitmap next to
cleared menu items. However, you can use the SetMenuItemBitmaps() function to associate application-defined
selected and cleared bitmaps with a menu items. The system then uses the specified bitmaps to indicate the menu
item's selected or cleared state.

Application-defined bitmaps associated with a menu item must be the same size as the default check mark bitmap, the
dimensions of which may vary depending on screen resolution. To retrieve the correct dimensions, use the
GetSystemMetrics() function. You can create multiple bitmap resources for different screen resolutions. Create
one bitmap resource and scale it, if necessary. Or create a bitmap at run time and draw an image in it. The bitmaps may
be either monochrome or color. However, because menu items are inverted when highlighted, the appearance of
certain inverted color bitmaps may be undesirable.

4.7 Enabled, Grayed, and Disabled Menu Items


A menu item can be enabled, grayed, or disabled. By default, a menu item is enabled. When the user chooses an
enabled menu item, the system sends a command message to the owner window or displays the corresponding
submenu, depending on what kind of menu item it is.

When menu items are not available to the user, they should be grayed or disabled. Grayed and disabled menu items
cannot be chosen. A disabled item looks just like an enabled item. When the user clicks on a disabled item, the item is
not selected, and nothing happens. Disabled items can be useful in, for example, a tutorial that presents a menu that
looks active but isn't.

An application grays an unavailable menu item to provide a visual cue to the user that a command is not available. You
can use a grayed item when an action is not appropriate (for example, you can gray the Print command in the File menu
when the system does not have a printer installed).

The EnableMenuItem() function enables, grays, or disables a menu item. To determine whether a menu item is
enabled, grayed, or disabled, use the GetMenuItemInfo() function.

Instead of GetMenuItemInfo() you can use the GetMenuState() function to determine whether a menu item is
enabled, grayed, or disabled.

4.8 Highlighted Menu Items


The system automatically highlights menu items on menus as the user selects them. However, highlighting can be
explicitly added or removed from a menu name on the menu bar by using the HiliteMenuItem() function. This
function has no effect on menu items on menus. When HiliteMenuItem() is used to highlight a menu name,
though, the name only appears to be selected. If the user presses the ENTER key, the highlighted item is not chosen. This
feature might be useful in, for example, a training application that demonstrates the use of menus.

4.9 Owner-Drawn Menu Items


An application can completely control the appearance of a menu item by using an owner-drawn item. Owner-drawn
items require an application to take total responsability for drawing selected (highlighted), selected, and cleared states.
For example, if an application provided a font menu, it could draw each menu item by using the corresponding font. The
item for Roman would be drawn with roman, the item for Italic would be drawn in italic, and so on.

4.10 Menu Item Separators and Line Breaks


The system provides a special type of menu item, called a separator, that appears as a horizontal line. You can use a
separator to divide a menu into groups of related items. A separator cannot be used in a menu bar, and the user cannot
select a separator.
When a menu bar contains more menu names than will fit on one line, the system wraps the menu bar by automatically
breaking it into two or more lines. You can cause a line break to occur at a specific item on a menu bar by assigning the
MFT_MENUBREAK type of flag on the item. The system places that item and all subsequent items on a new line.

When a menu contains more items than will fit in one column, the menu will be truncated. You can cause a column
break to occur at a specific item in a menu by assigning it the MFT_MENUBREAK type flag to the item or by using the
MENUBREAK option in the MENUITEM statement. The system places that item and all subsequent items in a new
column. The MFT_MENUBREAK type flag has the same effect, except that a vertical line appears between the new
column and the old.

If you use the AppendMenu(), InsertMenu(), or ModifyMenu() functions to asign line breaks, you should assign
the type flags MF_MENUBREAK or MF_MENUBARBREAK.

5. Messages Used with Menus


The system reports menu-related activity by sending messages to the window procedure of the window that owns the
menu. The system sends a series of messages when the user selects items on the menu bar or clicks the right mouse
button to display a shortcut menu.

When the user activates an item on the menu bar, the owner window first receives a WM_SYSCOMMAND message. This
message includes a flag that indicates whether the user activated the menu by using the keyboard (SC_KEYMENU) or
the mouse (SC_MOUSEMENU).

Next, before displaying any menus, the system that sends the WM_INITMENU message to the window procedure so
that an application can modify the menus before the user sees them. The system sends the WM_INITMENU message
only once per menu activation.

Each time the user moves the highlighting from one item to another, the system sends a WM_MENUSELECT message to
the window procedure of the menu's owner window. This message identifies the currently selected menu item. Many
applications provide an information area at the bottom of their main windows and use this message to display additional
information about the selected menu item.

When the user chooses a command item form a menu, the system sends a WM_COMMAND message to the window
procedure. The low-order word of the WM_COMMAND message's wParam parameter contains the identifier of the
chosen item. The window procedure should examine the identifier and process the message accordingly.

You can save information for a menu using the MENUINFO structure. If the menu is defined with a
MENUINFO.dwStyle value of MNS_NOTIFYBYPOS, the system sends WM_MENUCOMMAND instead of WM_COMMAND
when an item is selected. This allows you to access the information in the MENUINFO structure and also provides the
index of the selected item directly.

Not all menus are accessible through a window's menu bar. Many applications display shortcut menus when the user
clicks the right mouse button at a specific location. Such applications should process the WM_CONTEXTMENU message
and display a shortcut menu, if appropriate. If an application does not display a shortcut menu, it should pass the
WM_CONTEXTMENU message to the DefWindowProc() function for default processing.

The WM_MENURBUTTONUP message is sent when the user releases the right mouse button while the cursor is on a
menu item. This message is provided so that applications can display a context-sensitive or shortcut menu for a menu
item.

There are a few messages that only involve drag-and-drop menus. The WM_MENUGETOBJECT is sent to the owner of a
drag-and-drop menu when the mouse cursor enters a menu item or moves from the center of an item to the top or
bottom of an item. The WM_MENUDRAG message is sent when the user actually drags a menu item.
When a drop-down menu or a submenu has been destroyed, the system sends a WM_UNINITMENUPOPUP message.

6. Menu Destruction
If a menu is assigned to a window and that window is destroyed, the system automatically destroys the menu and its
submenus, freeing the menu's handle and the memory occupied by the menu. The system does not automatically
destroy a menu that is not assigned to a window. An application must destroy the unassigned menu by calling the
DestroyMenu() function. Otherwise, the menu continues to exist in the memory even after the application closes. To
end the calling thread's active menu, use EndMenu(). If a platform does not support EndMenu(), send the owner of
the active menu a WM_CANCELMODE message.

Windows Controls
A control is a child window that an application uses in conjunction with another window to enable user interaction.
Controls are most often used within dialog boxes, but they can also be used in other windows. Controls within dialog
boxes provide the user with a way to type text, choose options, and initiate actions. Controls in other windows provide a
variety of services, such as letting the user choose commands, view status, and view and edit text.

Support for controls is provided by User32.dll and ComCtl32.dll.

About Common Controls


The common controls form a set of windows that are implemented by the common control library, ComCtl32.dll, which
is a DLL included with the Windows operating system. Like other control windows, a common control is a child window
that an application uses in conjunction with another window to enable user interaction.

1. Common Control Versions


1.1 Common Control DLL Version Numbers
Support for comon controls is provided by ComCtl32.dll, which all 32-bit and 64-bit versions of Windows include. Each
successive version of the DLL supports the features and API of earlier versions and adds new features.

Because various versions of ComCtl32.dll were districuted with Internet Explorer, the version that is active is sometimes
different from the version that was shipped with the operating system. Therefore, your application must directly
determine which version of ComCtl32.dll is present.

In the common controls reference documentation, many programming elements specify a minimum supported DLL
version number. This version number indicates that the programming element is implemented in that version and
subsequent versions of the DLL unless otherwise specified. If no version number is specified, the programming element
is implemented in all existing versions of the DLL.

1.2 Structure Sizes for Different Common Control Versions


Ongoing enhancements to common controls have resulted in the need to extend many of the structures. For this reason,
the size of the structure has changed between different versions of Commctrl.h. Because most of the common control
structures take a structure size as one of the parameters, a message or function can fail if the size is not recognized. To
remedy this, structure size constants have been defined to aid in targetting different versions of ComCtl32.dll. This link
contains a list which defines the structure size constants.

1.3 Using DllGetVersion() to Determine the Version Number


The DllGetVersion() function can be called by an application to determine which DLL version is present on the
system.

DllGetVersion() returns a DLLVERSIONINFO2 structure. In addition to the information provided through


DLLVERSIONINFO, DLLVERSIONINFO2 also provides the hotfix number that identifies the latest installed service
pack, which provides a more robust way to compare version numbers. Because the first member of
DLLVERSIONINFO2 is a DLLVERSIONINFO structure, the later structure is backwards-compatible.

The following sample function loads a specified DLL and attempts to call its DllGetVersion() function. If successful,
it uses a macro to pack the major and minor version numbers from the DLLVERSIONINFO structure into a DWORD that
is returned to the calling application. If the DLL does not export DllGetVersion(), the function returns zero. You
can modify the function to handle the possibility that DllGetVersion() returns a DLLVERSIONINFO2 structure. If
so, use the information in that DLLVERSIONINFO2 structure's ullVersion member to compare versions, build
numbers, and service pack releases. The MAKEDLLVERULL macro simplifies the task of comparing these values to
those in ullVersion.
#include <Windows.h>
#include <Windef.h>
#include <Winbase.h>
#include <shlwapi.h>

#define PACKVERSION(major, minor) MAKELONG(minor, major)

DWORD GetVersion(LPCTSTR lpszDllName) {


HINSTANCE hInstDll;
DWORD dwVersion = 0;

// For security purposes, LoadLibrary() should be provided with a


fully
// qualified path to the DLL. The lpszDllName variable should be
tested
// to ensure that it is a fully qualified path before it is used.
hInstDll = LoadLibrary(lpszDllName);

if (hInstDll) {
DLLGETVERSIONPROC pDllGetVersion;
pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstDll,
"DllGetVersion");

// Because some DLLs might not implement this function, you must
// test for it explicitly. Depending on the particular DLL, the
// lack of the DllGetVersion() function can be a useful indicator
// of the version.
if (pDllGetVersion) {
DLLVERSIONINFO dvi;
HRESULT hr;

ZeroMemory(&dvi, sizeof(dvi));
dvi.info1.cbSize = sizeof(dvi);

hr = (*pDllGetVersion)(&dvi);

if (SUCCEEDED(hr)) {
dwVersion = PACKVERSION(dvi.info1.dwMajorVersion,
dvi.info1.dwMinorVersion);
}
}
FreeLibrary(hInstDll);
}
return dwVersion;
}

It should be noted that using LoadLibrary() incorrectly can pose security risks.

The following code example shows how you can use the GetVersion() function to test whether ComCtl32.dll is
version 6.0 or later:
LPCTSTR lpszDllName = L"C:\\Windows\\System32\\ComCtl32.dll";
DWORD dwVer = GetVersion(lpszDllName);
DWORD dwTarget = PACKVERSION(6, 0);
if (dwVer >= dwTarget) {
// This version of ComCtl32.dll is version 6.0 or later
} else {
// Proceed knowing that version 6.0 or later additions
// are not available. Use an alternate approach for the
// older DLL version.
}

1.4 Project Versions


To ensure that your application is compatible with different targeted versions of a .dll file, version macros are present in
the header files. These macros are used to define, exclude, or redefine certain definitions for different versions of the
DLL.

For example, the macro name _WIN32_IE is commonly found in older headers. You are responsible for defining the
macro as a hexadecimal number. This version number defines the target version of the application that is using the DLL.
The following table shows the available version numbers and the effect each has on your application:

Version Action
The application is compatible with ComCtl32.dll version 4.70 and later. The application
0x0300
cannot implement features that were added after version 4.70.
The application is compatible with ComCtl32.dll version 4.71 and later. The application
0x0400
cannot implement features that were added after version 4.71.
The application is compatible with ComCtl32.dll version 4.72 and later. The application
0x0401
cannot implement features that were added after version 4.72.
The application is compatible with ComCtl32.dll version 5.80 and later. The application
0x0500
cannot implement features that were added after version 5.80.
The application is compatible with ComCtl32.dll version 5.81 and later. The application
0x0501
cannot implement features that were added after version 5.81.
The application is compatible with ComCtl32.dll version 6.0 and later. The application
0x0600
cannot implement features that were added after version 6.0.
If you do not define the _WIN32_IE macro in your project, it is automatically defined as 0x0500. To define a different
value, you can add the following to the compiler directives in your make file. Substitute the desired version number for
0x0400:
/D _WIN32_IE=0x0400

Another method is to add a line similar to the following in your source code before you include the Shell header files.
Substitute the desired version number for 0x0400:
#define _WIN32_IE 0x0400
#include <commctrl.h>

2. Creating Common Controls


Most common controls belong to a window clas defined in the common control DLL. The window class and the
corresponding window procedure define the properties, appearance, and behavior of the control. To ensure that the
common control DLL is loaded, include the InitCommonControlEx() function in your application.

You create a common control by specifying the name of the window class when calling the CreateWindowEx()
function or by specifying the appropriate class name in a dialog box template.

Each type of common control has a set of control styles that you can use to vary the appearance and behavior of the
control. The common control library also includes a set of control styles that apply to two or more types of common
controls.
3. Unicode Support for Common Controls
For versions 5.80 and later of ComCtl32.dll, common controls notifications support both ANSI and Unicode formats on
Windows 95 systems or later. The system determines which format to use by sending your window a
WM_NOTIFYFORMAT message. To specify a format, return NFR_ANSI for ANSI notifications or NFR_UNICODE for
Unicode notifications. If you do not handle this message, the system calls IsWindowsUnicode() to determine the
format. Since Windows 95 and Windows 98 always return FALSE to this function call, they use ANSI notifications by
default.

Control Messages
1. Messages to Common Controls
Because common controls are windows, an application can communicate with them by using common Microsoft Win32
messages such as WM_GETFONT or WM_SETTEXT. In addition, the window class of each common control supports a set
of control-specific messages. Typically, an application uses SendMessage() or SendDlgItemMessage() to pass
messages to the control (often receiving information in the return value).

Some common controls also have a set of macros that an application can use instead of SendMessage(). The macros
are typically easier to use than the functions. The following example code retrieves the text of the selected tree-view
item, first by using the raw messages, and second by using the equivalent macros. Assume that hWnd is the handle of
the control window:
BOOL fSuccess;
WCHAR itemText[99];
TVITEM tvItem = {};
tvItem.mask = TVIF_TEXT;
tvItem.cchTextMax = ARRAYSIZE(itemText);
tvItem.pszText = itemText;

// This...
tvItem.hItem = (HTREEITEM)SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_CARET,
NULL);
fSuccess = SendMessage(hWnd, TVM_GETITEM, 0, (LPARAM)&tvItem);

// ... is equivalent to this.


tvItem.hItem = TreeView_GetSelection(hWnd);
fSuccess = TreeView_GetItem(hWnd, &tvItem);

When a change is made to the system color settings, Windows sends a WM_SYSCOLORCHANGE message to all top-level
windows. Your top-level window must forward the WM_SYSCOLORCHANGE to its common controls. Otherwise, the
controls will not be notified of the color change. Forwarding the message ensures that the colors used by your common
controls are consistent with those used by other user interface objects. For example, a toolbar control uses the "3-D
Objects" color to draw its buttons. If the user changes the 3-D Objects color but the WM_SYSCOLORCHANGE message is
not forwarded to the toolbar, the toolbar buttons will remain in their original color (or even change to a combination of
old and new colors) while the color of other buttons in the system changes.

2. Notifications from Controls


Controls are child windows that send notification messages to the parent window when events, usually triggered by
input from the user, occur in the control. The application relies on these notification messages to determine which
action the user wants to take. Except for trackbars, which use the WM_HSCROLL and WM_VSCROLL messages to notify
their parent of changes, common controls send notifications as either WM_COMMAND or WM_NOTIFY messages, as
specified in the reference topic for the notification. Typically, older notifications (those that have been in the API for a
long time) use WM_COMMAND.

The lParam parameter of WM_NOTIFY is either the address of an NMHDR structure or the address of a larger structure
that incldues NMHDR as its first member. The structure contains the notification code that identifies the common control
that sent the notification message. The meaning of the remaining structure members, if any, varies depending on the
notification code.

Each type of common control has a corresponding set of notification codes. The common control library also provides
notification codes that can be sent by more than one type of common control. See the documentation for the control of
interest to determine which notification codes it will send and what format they take.

Custom Controls
1. Creating Owner-Drawn Controls
Buttons, menus, static text controls, list boxes, and combo boxes can be created with an owner-drawn style flag. When a
control has the owner-drawn style, the system handles the user's interaction with the control as usual, performing such
tasks as detecting when a user has chosen a button and notifying the button's owner of the event. However, because the
control is owner-drawn, the parent window of the control is responsible for the visual appearance of the control. The
parent window receives a message whenever the control must be drawn.

For buttons and static text controls, the owner-drawn style affects how the system draws the entire control. For list
boxes and combo boxes, the parent window draws the items within the control, and the control draws its own outline.

Control Library
1. Buttons
A button is a control the user can click to provide input to an application.

There are several types of buttons and one or more button styles to distinguish between buttons of the same type.

The user clicks a button by using the mouse or keyboard. Clicking a button typically changes its visual appearance and
state (from checked to cleared, for example).

The system, the button, and the application cooperate in changing the button's appearance and state. A button can send
messages to its parent window, and a parent window can send messages to a button.

Some buttons are painted by the system, and some by the application.

Buttons can be used alone or in groups and can appear without application-defined text (a label).

Buttons belong to the BUTTON window class.

1.1 Button Messages


A button can send messages to its parent window, and a parent window can send messages to a button.

1.1.1 Sending Messages to Buttons


A parent window can send messages to a button in an overlapped or child window by using the SendMessage()
function, or it can send messages to a button in a dialog box by using the SendDlgItemMessage(),
CheckDlgButton(), CheckRadioButton() and IsDlgButtonClicked() functions.
An application can use the BM_GETCHECK message to retrieve the check state of a check box or radio button. An
application can also use the BM_GETSTATE message to retrieve the button's current states (the check state, push state,
and focus state). To get information about a specific state, use a bitmask on the returned state value.

The BM_SETCHECK message sets the check state of a check box or radio button (the message returns zero). The
BM_SETSTATE message sets the push state of a button (this message also returns zero). The BM_SETSTYLE message
changes the style of a button. It is designed for changing button styles within a type (for example, changing a check box
to an automatic check box). It is not designed for changing between types (for example, changing a check box to a radio
button). An application should not change a button from one type to another.

A button of the BS_BITMAP or BS_ICON style displays a bitmap or icon instead of text. The BM_SETIMAGE message
associates a handle to a bitmap or icon with a button. The BM_GETIMAGE message retrieves a handle to the bitmap or
icon associated with a button.

An application can also use the DM_GETDEFID message to retrieve the identifier or the default push button control in a
dialog box. An application can use the DM_SETDEFID message to set the default push button for a dialog box.

Calling the CheckDlgButton() or CheckRadioButton() function is equivalent to sending a BM_SETCHECK


message. Calling the IsDlgButtonCheckedFunction() is equivalent to sending a BM_GETCHECK message.

1.1.2 Handling Messages from a Button


Notifications from a button are sent as either WM_COMMAND or WM_NOTIFY messages. Information about which
message is used can be found on the reference page for each notification.

1.1.3 Notification Messages from Buttons


When the user clicks a button, its state changes, and the button sends notification coodes, in the form of WM_COMMAND
messages, to its parent window. For example, a push button sends the BN_CLICKED notification code whenever the
user chooses the button. In all cases (except for BCN_HOTITEMCHANGE), the low-order word of the wParam
parameter contains the control identifier, its high-order word contains the notification code, and the lParam
parameter contains the control window handle.

Both the message and the parent window's response depend on the type, style, and current state of the button.
Following are the button notification codes an application should monitor and process:

Notification Code Description


BCN_HOTITEMCHANGE The mouse entered or left the client area of a button.
BN_CLICKED The user clicked a button.
BN_DBLCLK or BN_DOUBLECLICKED The user double-clicked a button.
BN_DISABLE A button is disabled.
BN_PUSHED or BN_HILITE The user pushed a button.
BN_KILLFOCUS The button lost the keyboard focus.
BN_PAINT The button should be painted.
BN_SETFOCUS The button gained the keyboard focus.
BN_UNPUSHED or BN_UNHILITE The button is no longer pushed.

A button sends the BN_DISABLE, BN_PUSHED, BN_KILLFOCUS, BN_PAINT, BN_SETFOCUS, and BN_UNPUSHED
notification codes only if it has the BS_NOTIFY style. BN_DBLCLK notification codes are sent automatically for
BS_USERBUTTON, BS_RADIOBUTTON, and BS_OWNERDRAWN buttons. Other button types send BN_DBLCLK only if
they have the BS_NOTIFY style. All buttons send the BN_CLICKED notification code regardless of their button styles.

For automatic buttons, the system changes the push state and paints the button. In this case, the application typically
processes only the BN_CLICKED and BN_DBLCLK notification codes. For buttons that are not automatic, the
application typically responds to the notification code by sending a message to change the state of the button.
When the user selects an owner-drawn button, the button sends its parent window a WM_DRAWITEM message
containing the identifier of the control to be drawn and information about its dimensions and state.

1.1.4 Button Color Messages


The system provides default color values for buttons. An application can retrieve the default values for the colors by
calling the GetSysColor() function, or set the values by calling the SetSysColors() function. The following
table shows the default button-color values:

Value Element colored


COLOR_BTNFACE Button faces.
COLOR_BTNHIGHLIGHT Highlight area (the top and left edges) of a button.
COLOR_BTNSHADOW Shadow area (the bottom and right edges) of a button.
COLOR_BTNTEXT Regular (nongrayed) text in buttons.
Disabled (gray) text in buttons. The color is set to 0 if the current display driver does not
COLOR_GRAYTEXT
support a solid gray color.
COLOR_WINDOW Window backgrounds.
COLOR_WINDOWFRAME Window frames.
COLOR_WINDOWTEXT Text in windows.
However, calling SetSysColors() affects all applications, so you should not call this function to customize buttos for
your application.

The system sends a WM_CTLCOLORBTN message to a button's parent window before drawing a button. This message
contains a handle to the push button's device context and a handle to the child window. The parent window can use
these handles to change the button's text and background colors. However, only owner-drawn buttons respond to the
parent window processing the message.
The Resource Compiler
The Microsoft Windows Resource Compiler (RC) is a tool used in building Windows-based applications.

About Resource Files


To include resources in your Windows-based application with RC, do the following:

1. Create individual files for your cursors, icons, bitmaps, dialog boxes, and fonts.
2. Create a resource-definition script (.rc) file that describes the resources used by your application.
3. Compile the script with RC.
4. Link the compiled resource (.res) file into the application's executable file with your linker.

A resource file is a text file with the extension .rc. The file can use single-byte, double-byte, or Unicode characters. The
synta and semantics of the RC preprocessor are similar to those of the Microsoft C/C++ compiler. However, RC supports
a subset of the preprocessor directives, and pragmas in a script.

The script file defines resources. For a resource that exists in a separate file, such as an icon or cursor, the script specifies
the resource and the file that contains it. For some resources, such as a menu, the entire definition of the resource exists
within the script.
1. Comments
RC supports C-style syntax for both single-line comments and block comments:

 Single-line comments begin with two forward slashes (//) and run to the end of the line.
 Block comments begin with an opening delimiter (/*) and run to the closing delimiter (*/).

Comments do not nest.

2. Predefined Macros
RC does not support the ANSI C predefined macros (__DATE__, __FILE__, __LINE__, __STDC__, __TIME__,
__TIMESTAMP__). Therefore, you cannot include these macros in header files that you will include in your resource
script.

RC does define RC_INVOKED, which enables you to conditionally compile portions of your header files, depending on
whether the compiler is your C compiler or the RC compiler. This is important because the RC compiler supports only a
subset of the statements a C compiler would support.

To conditionally compile your code with the RC compiler, surround the code that RC cannot compile with #ifndef
RC_INVOKED and #endif.

3. Preprocessor Directives
You can use the directives described in the following table as needed in your resource script. They instruct RC to perform
actions or to assign values to names.

Directive Description
#define Defines a specified name by assigning it a given value.
#elif Marks an optional clause of a conditional-compilation block.
#else Marks the last optional clause of a conditional-compilation block.
#endif Marks the end of a conditional-compilation block.
#if Conditionally compiles the script if a specified expression is true.
#ifdef Conditionally compiles the script if a specified name is defined.
#ifndef Conditionally compiles the script if a specified name is not defined.
#include Copies the contents of a file into the resource-definition file.
#undef Removes the definition of the specified name.

To define symbols for your resource identifiers, use the #define directive to define them in a header file. Include this
header both in the resource script and your application source code. Similarly, you define the values for resource
attributes and styles by including Windows.h in the resource script.

RC treats files with the .c and .h extensions in a special manner. It assumes that a file with one of these extensions does
not contain resources. If a file has the .c or .h file name extension, RC ignores all lines in the file except the preprocessor
directives. Therefore, to include a file that contains resources in another resource script, give the file to be included an
extension other than .c or .h.

4. Preprocessor Operators
RC supports using the standard C preprocessing operators in macro definitions. These operators are described in the
following table:

Operator Description
# Encloses the argument in quotes
#@ Encloses the argument in single quotes.
## Concatenates tokens used as arguments to form other tokens.

5. Pragma Directives
RC does not support the pragma directives supported by the C/C++ compiler. However, RC does support the following
pragma directive for changing the code page:
#pragma code_page( [ DEFAULT | CodePageNum ] )

This pragma is not supported in an included resource file (.rc). Therefore, if you have a parent .rc file and it includes .rc
files for multiple languages, use this pragma before including another .rc file rather than using it in the included .rc file
itself.

6. Resource-Definition Statements
The resource-definition statements define the resources that the resource compiler puts in the resource ( .res) file. After
the .res file is linked to the executable file, the application can load its resources at run time as needed. All resource
statements associate an identifying name or number with a given resource.

The resource-definition statements can be divided into the following categories:

 Resources
 Controls
 Statements

The following table describes the resource-definition statements:

6.1 Resources
Operator Description
ACCELERATORS Defines menu accelerator keys.
Defines a bitmap by naming it and specifying the name of the file that contains it. (To
BITMAP
use a particular bitmap, the application requests it by name.)
Defines a cursor or animated cursor by naming it and specifying the name of the file
CURSOR
that contains it. (To use a particular cursor, the application requests it by name.)
DIALOG Defines a template that an application can use to create dialog boxes.
DIALOGEX Defines a template that an application can use to create dialog boxes.
FONT Specifies the name of a file that contains a font.
HTML Specifies an HTML file.
Defines an icon or animated icon by naming it and specifying the name of the file that
ICON
contains it. (To use a particular cursor, the application requests it by name.)
MENU Defines the appearance and function of a menu.
MENUEX Defines the appearance and function of a menu.
Defines a message table by naming it and specifying the name of the file that contains
MESSAGETABLE
it. The file is a binary resource file generated by the message compiler.
POPUP Defines a menu item that can contain menu items and submenus.
Defines data resources. Data resources let you include binary data in the executable
RCDATA
file.
STRINGTABLE Defines string resources that can be loaded from the executable file.
TEXTINCLUDE A special resource that is interpreted by Visual C++.
TYPELIB A special resource that is used with the /TLBID and /TLBOUT linker options.
User-Defined Defines a resource that contains application-specific data.
Defines a version-information resource. Contains information such as the version
VERSIONINFO
number, intended operating system, and so on.
6.2 Controls
Control Description
AUTO3STATE Creates an automatic three-state check box control.
AUTOCHECKBOX Creates an automatic check box control.
AUTORADIOBUTTON Creates an automatic radio button control.
CHECKBOX Creates a check box control.
COMBOBOX Creates a combo box control.
CONTROL Creates an application-defined control.
CTEXT Creates a centered-text control.
DEFPUSHBUTTON Creates a default pushbutton control.
EDITTEXT Creates an edit control.
GROUPBOX Creates a group box control.
ICON Creates an icon control. This control is an icon displayed in a dialog box.
LISTBOX Creates a list box control.
LTEXT Creates a left-aligned text control.
PUSHBOX Creates a push box control.
PUSHBUTTON Creates a push button control.
RADIOBUTTON Creates a radio button control.
RTEXT Creates a right-aligned text control.
SCROLLBAR Creates a scroll bar control.
STATE3 Creates a three-state check box control.

6.3 Statements
Statement Description
CAPTION Sets the title for a dialog box.
Specifies information about a resource that can be used by a tool that can read or
CHARACTERISTICS
write resource-definition files.
CLASS Sets the class of the dialog box.
EXSTYLE Sets the extended window style of the dialog box.
FONT Sets the font with which the system will draw text for the dialog box.
Sets the language for all resources up to the next LANGUAGE statement or to the end
of the file. When the LANGUAGE statement appears before the beginning of the body
LANGUAGE
of an ACCELERATORS, DIALOG, MENU, RCDATA or STRINGTABLE resource
definition, the specified language applies only to that resource.
MENU Sets the menu for the dialog box.
MENUITEM Defines a menu item.
STYLE Sets the window style for the dialog box.
Specifies version information for a resource that can be used by a tool that can read or
VERSION
write resource-definition files.

7. Sample Resource-Definition File


The following example shows a script file that defines the resources for an application:
#include "shapes.h"

ShapesCursor CURSOR SHAPES.CUR


ShapesIcon ICON SHAPES.ICO

ShapesMenu MENU
{
POPUP "&Shape"
{
MENUITEM "&Clear", ID_CLEAR
MENUITEM "&Rectangle", ID_RECT
MENUITEM "&Triangle", ID_TRIANGLE
MENUITEM "&Star", ID_STAR
MENUITEM "&Ellipse", ID_ELLIPSE
}
}

The CURSOR statement names the application's cursor resource ShapesCursor and specifies the cursor file
SHAPES.CUR, which contains the image for that cursor.

The ICON statement names the application's icon resource ShapesIcon and specifies the icon file SHAPES.ICO, which
contains the image for that icon.

The MENU statement defines an application menu named ShapesMenu, a pop-up menu with five menu items.

The body of the menu definition, enclosed by curly braces, or the BEGIN and END keywords, specifies each menu item
and the menu identifier that is returned when the user selects that item. For example, the first item on the menu, Clear,
returns the menu identifier ID_CLEAR when the user selects it. The menu identifiers are defined in the application
header file, SHAPES.H.

You might also like