<Previous Lesson

Visual Programming

Next Lesson>

Lesson#12

Window Classes

12.1 SYSTEM CLASSES 2
12.2 STYLES OF SYSTEM CLASSES 3
12.3 CREATING BUTTON WINDOW CLASS (EXAMPLE) 5
12.4 GET AND SET WINDOW LONG 6
12.5 SUB-CLASSING 7
THE BASICS 7
TYPES OF SUBCLASSING 8
WIN32 SUBCLASSING RULES 8
INSTANCE SUBCLASSING 9
12.6 GET OR SET CLASSLONG 10
DIFFERENCE BETWEEN SETWINDOWLONG AND SETCLASSLONG 11
12.7 SUB-CLASSING (ELABORATION) 12
12.8 SUPPER-CLASSING 12
SUPER-CLASSING (EXAMPLE) 13

NEW WINDOW PROCEDURE 14

SUMMARY 14
Window Classes 2

12.1 System classes

Up till now, we have been registering window classes before creating a window. A number
of window classes are pre-registered / pre-coded in Windows, and their window procedures
are also pre-written.
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.
Microsoft Windows NT/Windows 2000/Windows XP: The system registers the system
classes for a process, the first time one of its threads calls a User or a Windows Graphics
Device Interface (GDI) function.
There are two types of System Window Classes.
1. Those which can be used by the user processes.
2. Those which can only be used by the system
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 Windows NT/Windows 2000/Windows XP: The class for Dynamic Data
Exchange Management (DDEML) events.
Message Windows 2000/Windows XP: The class for a message-only window.
#32768 The class for a menu.
#32769 The class for the desktop window.
Window Classes 3
#32770 The class for a dialog box.
#32771 The class for the task switch window.
#32772 Windows NT/Windows 2000/Windows XP: The class for icon titles.
Because these classes are pre-registered, that’s why we do not call RegisterClass or do not
need to register the window class before creating such a window.

12.2 Styles of System Classes

The Following are the styles of some of the system window classes
Button Styles
BS_3STATE
This style creates a button that is the same as a check box, except that the check box can be
grayed, as well as, checked or cleared. Use the grayed state to show that the state of the
check box is not determined.

BS_AUTO3STATE

This style creates a button that is the same as a three-state check box, except that the box
changes its state when the user selects it. The state cycles through checked, grayed, and
cleared.

BS_AUTOCHECKBOX

This style creates a button that is the same as a check box, except that the check state
automatically toggles between checked and cleared, each time the user selects the check
box.

BS_AUTORADIOBUTTON

This style creates a button that is the same as a radio button, except that when the user
selects it, the system automatically sets the button's check state to checked and
automatically sets the check state for all other buttons in the same group to cleared.

BS_CHECKBOX

This style creates a small, empty check box with text. By default, the text is displayed to
the right of the check box. To display the text to the left of the check box, combine this flag
with the BS_LEFTTEXT style (or with the equivalent BS_RIGHTBUTTON style).

BS_DEFPUSHBUTTON

This style creates a push button that behaves like a BS_PUSHBUTTON style, but it has
also a heavy black border. If the button is in a dialog box, the user can select the button by
pressing the ENTER key, even when the button does not have the input focus. This style is
useful for enabling the user to quickly select the most likely (default) option.

BS_GROUPBOX

This style creates a rectangle in which other controls can be grouped. Any text associated
with this style is displayed in the rectangle's upper left corner.
Window Classes 4

BS_LEFTTEXT

This style places text on the left side of the radio button or check box when combined with
a radio button or check box style. This style is same as the BS_RIGHTBUTTON style.

BS_OWNERDRAW

This style creates an owner-drawn button. The owner window receives a
WM_DRAWITEM message when a visual aspect of the button has changed. Do not
combine the BS_OWNERDRAW style with any other button styles.

BS_PUSHBUTTON

This style creates a push button that posts a WM_COMMAND message to the owner
window when the user selects the button.

BS_RADIOBUTTON

This style creates a small circle with text. By default, the text is displayed to the right of the
circle. To display the text to the left of the circle, combine this flag with the
BS_LEFTTEXT style (or with the equivalent BS_RIGHTBUTTON style). Use radio
buttons for groups of related, but mutually exclusive choices.

BS_USERBUTTON

This style has become obsolete, but provided for compatibility with 16-bit versions of
Windows. Applications should use BS_OWNERDRAW instead.

BS_BITMAP

This style specifies that the button displays a bitmap.

BS_BOTTOM

This style places text at the bottom of the button rectangle.

BS_CENTER

This style centers text horizontally in the button rectangle.

BS_ICON

This style specifies that the button displays an icon.

BS_FLAT

This style specifies that the button is two-dimensional; it does not use the default shading
to create a 3-D image.

BS_LEFT

This style Left-justifies the text in the button rectangle. However, if the button is a check
box or radio button that does not have the BS_RIGHTBUTTON style, the text is left
justified on the right side of the check box or radio button.

BS_MULTILINE

This style wraps the button text to multiple lines if the text string is too long to fit on a
single line in the button rectangle.
Window Classes 5

BS_NOTIFY

This style enables a button to send BN_KILLFOCUS and BN_SETFOCUS to help
notification messages to its parent window.
Note that buttons send the BN_CLICKED notification message regardless of whether it has
this style. To get BN_DBLCLK notification messages, the button must have the
BS_RADIOBUTTON or BS_OWNERDRAW style.

BS_PUSHLIKE

This style makes a button (such as a check box, three-state check box, or radio button) and
look and act like a push button. The button looks raised when it isn't pushed or checked,
and sunken when it is pushed or checked.

BS_RIGHT

This style right-justifies text in the button rectangle. However, if the button is a check box
or radio button that does not have the BS_RIGHTBUTTON style, the text is right justified
on the right side of the check box or radio button.

BS_RIGHTBUTTON

This style positions a radio button's circle or a check box's square on the right side of the
button rectangle. This is same as the BS_LEFTTEXT style.

BS_TEXT

This style specifies that the button displays text.

BS_TOP

This style places text at the top of the button rectangle.

BS_TYPEMASK

Microsoft Windows 2000: A composite style bit that results from using the OR operator on
BS_* style bits. It can be used to mask out valid BS_* bits from a given bitmask. Note that
this is out of date and does not correctly include all valid styles. Thus, you should not use
this style.

BS_VCENTER

This style places text in the middle (vertically) of the button rectangle.
12.3 Creating Button Window Class (Example)
For button, we will use our well known API CreateWindow to create a button.
hWnd = CreateWindow( "BUTTON", "Virtual University", BS_RADIOBUTTON |
WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CAPTION, 50, 50, 200, 100,
NULL, NULL, hInstance, NULL);
This button has no parent. If you want to place this button on any window, you should
provide hWndParent member with parent Window handle and add WS_CHILD style in its
dwStyle member.
Window Classes 6

12.4 Get and Set Window Long

The SetWindowLong function changes an attribute of the specified window. The function
also sets the 32-bit (long) value at the specified offset into the extra window memory.
LONG SetWindowLong(
HWND hWnd, // handle to window
int nIndex, // offset of value to set
LONG dwNewLong // new value
);
hWnd
Handle to the window and, indirectly, the class to which the Window
belongs.
nIndex
This member specifies the zero-based offset to the value to be set. Valid
values are in the range zero through the number of bytes of extra window
memory, minus the size of an integer. To set any other value, specify one
of the following values.
GWL_EXSTYLE, Sets a new extended window style.
GWL_STYLE, Sets a new Window Style
GWL_WNDPROC :Sets a new address for the window procedure.
In Windows NT/2000/XP, You cannot change this attribute if the window
does not belong to the same process as the calling thread.
GWL_HINSTANCE: Sets a new application instance handle.
GWL_ID, Sets a new identifier of the window.
GWL_USERDATA: Sets the user data associated with the window. This
data is intended for use by the application that created the window. Its
value is initially zero.
The following values are also available when the hWnd parameter
identifies a dialog box.
DWL_DLGPROC: Sets the new address of the dialog box procedure.
DWL_MSGRESULT: Sets the return value of a message processed in the
dialog box procedure.
DWL_USER: Sets new extra information that is private to the application,
such as handles or pointers.
dwNewLong
This style specifies the replacement value.
LONG GetWindowLong(
HWND hWnd, // handle to window
int nIndex // offset of value to retrieve
);
Window Classes 7
Certain window data is cached, so changes you make using SetWindowLong will not take
effect until you call the SetWindowPos function. Specifically, if you change any of the
frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for
the cache to be updated properly.
If you use SetWindowLong with the GWL_WNDPROC index to replace the window
procedure, the window procedure must conform to the guidelines specified in the
description of the WindowProc callback function.
If you use SetWindowLong with the DWL_MSGRESULT index to set the return value for
a message processed by a dialog procedure, you should return TRUE directly afterwards.
Otherwise, if you call any function that results in your dialog procedure receiving a
window message, the nested window message could overwrite the return value you set
using DWL_MSGRESULT.
Calling SetWindowLong with the GWL_WNDPROC index creates a subclass of the
window class used to create the window. An application can subclass a system class, but
should not subclass a window class, created by another process. The SetWindowLongfunction creates the window subclass by changing the window procedure associated with a
particular window class, causing the system to call the new window procedure instead of
the previous one. An application must pass any messages not processed by the new
window procedure to the previous window procedure by calling CallWindowProc. This
allows the application to create a chain of window procedures.
Reserve extra window memory by specifying a nonzero value in the cbWndExtra member
of the WNDCLASSEX structure used with the RegisterClassEx function.

12.5 Sub-Classing

Sub-classing allows you to change the behavior of an existing window, typically a control,
by inserting a message map to intercept the window's messages. For example, suppose you
have a dialog box with an edit control that you want to accept only non-numeric characters.
You could do this by intercepting WM_CHAR messages destined for the edit control and
discarding any messages indicating that a numeric character has been entered.
Subclassing is a technique that allows an application to intercept messages destined for
another window. An application can augment, monitor, or modify the default behavior of a
window by intercepting messages meant for another window. Sub-classing is an effective
way to change or extend the behavior of a window without redeveloping the window.
Subclassing the default control window classes (button controls, edit controls, list controls,
combo box controls, static controls, and scroll bar controls) is a convenient way to obtain
the functionality of the control and to modify its behavior. For example, if a multi-line edit
control is included in a dialog box and the user presses the ENTER key, the dialog box
closes. By subclassing the edit control, an application can have the edit control insert a
carriage return and line feed into the text without exiting the dialog box. An edit control
does not have to be developed specifically for the needs of the application

The Basics

The first step in creating a window is registering a window class by filling a WNDCLASS structure and calling RegisterClass. One element of the WNDCLASS structure is the
address of the window procedure for this window class. When a window is created, the 32-
bit versions of the Microsoft Windows operating system take the address of the window
procedure in the WNDCLASS structure and copy it to the new window's information
structure. When a message is sent to the window, Windows calls the window procedure
through the address in the window's information structure. To subclass a window, you
substitute a new window procedure that receives all the messages meant for the original
Window Classes 8
window by substituting the window procedure address with the new window procedure
address.
When an application subclasses a window, it can take three actions with the message: (1)
pass the message to the original window procedure; (2) modify the message and pass it to
the original window procedure; (3) not pass the message.
The application subclassing a window can decide when to react to the messages it receives.
The application can process the message before, after, or both before and after passing the
message to the original window procedure.

Types of Subclassing

The two types of subclassing are instance subclassing and global subclassing.
Instance subclassing is subclassing an individual window's information structure. With
instance subclassing, only the messages of a particular window instance are sent to the new
window procedure.
Global subclassing is replacing the address of the window procedure in the WNDCLASS

structure of a window class. All subsequent windows created with this class have the
substituted window procedure's address. Global subclassing affects only windows created
after the subclass has occurred. At the time of the subclass, if any windows of the window
class that is being globally subclassed exist, the existing windows are not affected by the
global subclass. If the application needs to affect the behavior of the existing windows, the
application must subclass each existing instance of the window class.

Win32 Subclassing Rules

Two sub-classing rules apply to instance and global sub-classing in Win32.
Subclassing is allowed only within a process. An application cannot subclass a window or
class that belongs to another process.
The reason for this rule is simple: Win32 processes have separate address spaces. A
window procedure has an address in a particular process. In a different process, that
address does not contain the same window procedure. As a result, substituting an address
from one process with an address from another process does not provide the desired result,
so the 32-bit versions of Windows do not allow this substitution (that is, subclassing from a
different process) to take place. The SetWindowLong and SetClassLong functions prevent
this type of subclassing. You can not subclass a window or class that is in another process.
End of story.
One way to add subclassing code into another process is much more complicated: It
involves using the OpenProcess, WriteProcessMemory, and CreateRemoteThread
functions to inject code into the other process. I don't recommend this method and won't go
into any details on how to do it. For developers who insist on using this method,
The subclassing process may not use the original window procedure address directly.
In Win16, an application could use the window procedure address returned from
SetWindowLong or SetClassLong to call the procedure directly. After all, the return value is
simply a pointer to a function, so why not just call it? In Win32, this is a definitive no-no.
The value returned from SetWindowLong and GetClassLong may not be a pointer to the
previous window procedure at all. Win32 may return a pointer to a data structure that it can
use to call the actual window procedure. This occurs in Windows NT when an application
subclasses a Unicode window with a non-Unicode window procedure, or a non-Unicode
window with a Unicode window procedure. In this case, the operating system must
perform a translation between Unicode and ANSI for the messages the window receives. If
an application uses the pointer to this structure to directly call the window procedure, the
Window Classes 9
application will immediately generate an exception. The only way to use the window
procedure address returned from SetWindowLong or SetClassLong is as a parameter to
CallWindowProc.

Instance Subclassing

The SetWindowLong function is used to subclass an instance of a window. The application
must have the address of the subclass function. The subclass function is the function that
receives the messages from Windows and passes the messages to the original window
procedure. The subclass function must be exported in the application's or the DLL's module
definition file.
The application subclassing the window calls SetWindowLong with the handle to the
window the application wants to subclass, the GWL_WNDPROC option (defined in
WINDOWS.H), and the address of the new subclass function. SetWindowLong returns a
DWORD, which is the address of the original window procedure for the window. The
application must save this address to pass the intercepted messages to the original window
procedure and to remove the subclass from the window. The application passes the
messages to the original window procedure by calling CallWindowProc with the address of
the original window procedure and the hWnd, Message, wParam, and lParam parameters
used in Windows messaging. Usually, the application simply passes the arguments it
receives from Windows to CallWindowProc.
The application also needs the original window procedure address for removing the
subclass from the window. The application removes the subclass from the window by
calling SetWindowLong again. The application passes the address of the original window
procedure with the GWL_WNDPROC option and the handle to the window being
subclassed.
The following code subclasses and removes a subclass to an edit control:
LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT Message,WPARAM wParam,
LONG lParam);
FARPROC lpfnOldWndProc;
HWND hEditWnd;
//
// Create an edit control and subclass it.
// The details of this particular edit control are not important.
//
hEditWnd = CreateWindow("EDIT", "EDIT Test",
WS_CHILD | WS_VISIBLE | WS_BORDER ,
0, 0, 50, 50,
hWndMain,
NULL,
hInst,
NULL);
//
// Now subclass the window that was just created.
//
lpfnOldWndProc = (FARPROC)SetWindowLong(hEditWnd,
GWL_WNDPROC, (DWORD) SubClassFunc);
.
.
.
//
// Remove the subclass for the edit control.
Window Classes 10
//
SetWindowLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldWndProc);
//
// Here is a sample subclass function.
//
LONG FAR PASCAL SubClassFunc( HWND hWnd,
UINT Message,
WPARAM wParam,
LONG lParam)
{
//
// When the focus is in an edit control inside a dialog box, the
// default ENTER key action will not occur.
//
if ( Message == WM_GETDLGCODE )
return DLGC_WANTALLKEYS;
return CallWindowProc(lpfnOldWndProc, hWnd, Message, wParam,
lParam);
}

12.6 Get or Set ClassLong

The GetClassLong() function retrieves the specified 32-bit (LONG) value from the
WNDCLASS structure associated with the specified window. This will can be back ground
brush, handle to instance, handle to windows procedure and handle to Icon etc.
LONG SetClassLong(
HWND hWnd, // handle to window
int nIndex, // offset of value to set n LONG dwNewLong // new value
);

Parameters

hWnd
Handle to the window and, indirectly, the class to which the window
belongs.
nIndex
This member specifies the 32-bit value to replace. To set a 32-bit value in
the extra class memory, specify the positive, zero-based byte offset of the
value to be set. Valid values are in the range zero through the number of
bytes of extra class memory, minus four; for example, if you specified 12
or more bytes of extra class memory, a value of 8 would be an index to the
third 32-bit integer. To set any other value from the WNDCLASSEX

structure, specify one of the following values.
GCL_CBCLSEXTRA: Sets the size, in bytes, of the extra memory
associated with the class. Setting this value does not change the number of
extra bytes already allocated.
Window Classes 11
GCL_CBWNDEXTRA: Sets the size, in bytes, of the extra window
memory associated with each window in the class. Setting this value does
not change the number of extra bytes already allocated.
GCL_HBRBACKGROUND: Replaces a handle to the background brush
associated with the class.
GCL_HCURSOR: Replaces a handle to the cursor associated with the
class.
GCL_HICON: Replaces a handle to the icon associated with the class.
GCL_HICONSM: Replace a handle to the small icon associated with the
class.
GCL_HMODULE: Replaces a handle to the module that registered the
class.
GCL_MENUNAME: Replaces the address of the menu name string. The
string identifies the menu resource associated with the class.
GCL_STYLE: Replaces the window-class style bits.
GCL_WNDPROC: Replaces the address of the window procedure
associated with the class.
dwNewLong
This member specifies the replacement value.

Return Value

If the function succeeds, the return value is the previous value of the specified 32-
bit integer. If the value was not previously set, the return value is zero.
If the function fails, the return value is zero. To get extended error information, call
GetLastError.
LONG GetClassLong(
HWND hWnd, // handle to window
int nIndex // offset of value to retrieve
);
If you use the SetClassLong function and the GCL_WNDPROC index to replace the
window procedure, the window procedure must conform to the guidelines specified in the
description of the WindowProc callback function.
Calling SetClassLong with the GCL_WNDPROC index creates a subclass of the window
class that affects all windows subsequently created with the class. An application can
subclass a system class, but should not subclass a window class created by another process.
Reserve extra class memory by specifying a nonzero value in the cbClsExtra member of
the WNDCLASSEX structure used with the RegisterClass function.
Use the SetClassLong function with care. For example, it is possible to change the
background color for a class by using SetClassLong, but this change does not immediately
repaint all windows belonging to the class.

Difference between SetWindowLong and SetClassLong

In SetWindowLong(), behavior of a single window is modified.
In SetClassLong(), behavior of the window class is modified.
Window Classes 12
12.7 Sub-Classing (Elaboration)
We elaborate sub-classing by using following examples.
DLGPROC oldWindowProc;
hWnd = CreateWindow("BUTTON", "Virtual University", BS_AUTOCHECKBOX |
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
50, 50, 200, 100,
NULL, NULL, hInstance, NULL);
oldWindowProc = (WNDPROC) SetWindowLong ( hWnd,
GWL_WNDPROC, (LONG) myWindowProc);
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
DispatchMessage(&msg);
}
return msg.wParam;

New Window Procedure

LRESULT CALLBACK myWindowProc(HWND hWnd, UINT message, WPARAM
wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
MessageBox(hWnd, "Left mouse button pressed.", "Message", MB_OK);
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return CallWindowProc(oldWindowProc, hWnd, message,
wParam, lParam);
}
return 0;
}

12.8 Supper-Classing

Super-classing defines a class that adds new functionality to a predefined window class,
such as the button or list box controls.
Window Classes 13
Superclassing involves creating a new class that uses the window procedure of an existing
class for basic functionality.
Super-Classing (Example)
Super-classing defines a class that adds new functionality to a predefined window class,
such as the button or list box controls.
The following example defines a new class with partly or wholly modified behavior of a
pre-defined window class.
DLGPROC oldWindowProc; // Global variable
WNDCLASS wndClass;
GetClassInfo(hInstance, “BUTTON”, &wndClass);
GetClassInfo API gets the information about class. Information includes windows style,
procedure, background brush, icon and cursors.
WndClass.hInstance = hInstance;
wndClass.lpszClassName = “BEEPBUTTON”;
OldWindowProc = wndClas.lpfnWndProc;
wndClas.lpfnWndProc = myWindowProc;
After getting class information we fill the new window class and register it again by using
RegisterClass API
if(! RegisterClass( &wndClass ) )
{
return 0;
}
After registering new window class with the new procedure, create a window with the new
register class name. This registered class name will be different from the old registered
class name.
hWnd = CreateWindow(“BEEPBUTTON", "Virtual University", WS_VISIBLE |
WS_OVERLAPPEDWINDOW,
50, 50, 200, 100,
NULL, NULL, hInstance, NULL);
noldWindowProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
(LONG)myWindowProc);
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
if(msg.message == WM_LBUTTONUP)
DispatchMessage(&msg);
Window Classes 14
}
return msg.wParam

New Window Procedure

This new windows procedure myWindowProc will call the old window procedure after its
normal message processing.
LRESULT CALLBACK myWindowProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
MessageBeep(0xFFFFFFFF);
Break;
default:
return CallWindowProc(oldWindowProc, hWnd, message, wParam, lParam);
}
return 0;
}
Tips: After implementation of Sub-classing or Super Classing don’t forget to call window
procedure function.

Summary

In this lecture, we learnt about system windows classes. System window classes include
buttons, combo boxes, list box, etc. We studied about Button System Window class. We
discussed how to change windows attributes by using SetWindowLong and
GetWindowLong APIs. Using SetWindowLong and GetWindowLong, we can also make a
new procedure and change the message behavior of a window. Using SetClassLong and
GetClassLong, we can change one of the attributes of a registered class. Changing class
values will effect the change for every window that is using this class. This is called subclassing.
We also knew about Super-classing in which we register new window class by
using the properties of previous window class.

<Previous Lesson

Visual Programming

Next Lesson>

Home

Lesson Plan

Topics

Go to Top

Next Lesson
Previous Lesson
Lesson Plan
Topics
Home
Go to Top