Home

Windows Messages

 

Introduction to Messages

 

Microsoft Window as a Messaging Center

The computer is a machine that only follows instructions. It almost doesn't know anything. Because of this, the computer cannot predict what a user wants to do with the computer. In fact, a great deal of the responsibility is left to the programmer who must decide what can and cannot or should not be done on an application. To help the users with computer interaction, the operating system provides a series of objects called Windows controls. The programmer decides what objects are necessary for a given application.

Each computer application is equipped with Windows controls that allow the user to interact with the computer. Because the computer cannot and would not predict what the user wants to do when using the computer, the operating system lets each object tell it when it needs something from Windows. To do this, a control sends a message to the operating system every time something is new. Because there can be so many messages a control can send and because many controls can send various messages, there is a formula each message or almost every one of them must follow, just like there are rules the post office wants you to follow in order to send a letter.

A message to Windows must provide four pieces of information:

  • WHO sent the message? Every object you will need in your program, just like everything in the computer, must have a name. The operating system needs this name to identify every object, for any reason. An object in Microsoft Windows is identified as a Handle. For Windows controls, the handle is called HWND
  • WHAT message? The object that sends a message must let the operating system know what message it is sending. As we will learn, there are various types of messages for different circumstances. Nevertheless, to make matters a little easier, each message is a constant positive natural number (unsigned int) identified with a particular name. Therefore, the message identifier is passed as UINT
  • Accompanying items: Because there are so many types of messages, you must provide two additional pieces of information to help process the message. These two items depend on the type of message and could be anything. The first accompanying item is a 32-bit type (unsigned int) called WPARAM (stands for WORD Parameter; in other words, it is a WORD (unsigned int) argument). The second accompanying item is a 32-bit type of value (long) calle LPARAM (stands for LONG Parameter; in other words, it is a LONG (long in C/C++) argument). Remember that these two can be different things for different messages.

To manage the messages sent to Windows, they are communicated through a function pointer called a Windows procedure. The name of the function is not important but it must return a 32-bit integer, in fact a C/C++ long or Win32 LONG. Therefore, it is declared as LRESULT (LONG Result). Because this is a function pointer, it must be declared and defined as CALLBACK. The messages can be carried in a function defined as follows:

LRESULT CALLBACK MessageProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

To process the messages, and because there can be so many of them, this function typically uses a switch control to list all necessary messages and process each one in turn. After processing a message, its case must return a value indicating that the message was successfully processed or not.

No matter how many messages you processed, there will still be messages that you did not deal with. It could be because they were not sent even though they are part of the Windows controls used on an application. If you didn't process some messages, you should/must let the operating system know so it can take over. What happens is that the operating system is aware of all messages and it has a default behavior or processing for each one of them. Therefore, you should/must return a value for this to happen. The value returned can be placed in the default section of the switch condition and must simply be a DefWindowProc() function. Its syntax is:

LRESULT DefWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

This function is returned to Windows, saying "There are messages I couldn't process. Do what you want with them". The operating system would simply apply a default processing to them. The values returned by the DefWindowProc() function should be the same passed to the procedure.

The most basic message you can process is to make sure a user can close a window after using it. This can be done with a function called PostQuitMessage(). Its syntax is:

VOID PostQuitMessage(int nExitCode)

This function takes one argument which is the value of the LPARAM argument. To close a window, you can pass the argument as WM_QUIT.

Based on this, a simple Windows procedure can be defined as follows:

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}

 

A basic program with one message can be written as follows:

//---------------------------------------------------------------------------
#include <windows.h>

//---------------------------------------------------------------------------
HWND hWnd;
LPCTSTR ClsName = L"WndMsg";
LPCTSTR WindowCaption = L"Windows and Controls Messages";
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    MSG         Msg;
    WNDCLASSEX  WndClsEx;

    WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    WndClsEx.lpfnWndProc   = WndProc;
    WndClsEx.cbClsExtra    = NULL;
    WndClsEx.cbWndExtra    = NULL;
    WndClsEx.hInstance     = hInstance;
    WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClsEx.lpszMenuName  = NULL;
    WndClsEx.lpszClassName = ClsName;
    WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&WndClsEx);

    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                          ClsName,
                          WindowCaption,
                          WS_OVERLAPPEDWINDOW,
                          100,
                          120,
                          640,
                          480,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while( GetMessage(&Msg, NULL, 0, 0) )
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return Msg.wParam;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------

Windows Messages

 

Window Creation

WM_CREATE: Once you have decided to create a message, you send a message to Windows. Actually, when you are creating a window, a message called WM_CREATE is sent to Windows. This is the favorite message you can use to perform any early processing that you want to make sure happens before most other things show up. For example, you can use this message to initialize anything in your application. Therefore, this message is the first sent to the operating system. Here is an example:

//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_CREATE:
	MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK);
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------
 

Window Display

WM_SHOWWINDOW: After a window has been created, it needs to be displayed, that is, the window needs to be shown. Also, if the window was previously hidden, you can decide to show it. On the other hand, if a window is displaying, you may want to hide it, for any reason you judge necessary. To take any of these actions, that is, to show or hide a window, you must send the WM_SHOWWINDOW message. The syntax of this message is:

OnCreate(HWND hWnd, WM_SHOWWINDOW, WPARAM wParam, LPARAM lParam);

hWnd is the window that sends the message.

wParam is a Boolean value. If you want to display or show the hWnd window, set the wParam value to TRUE. If you want to hide the hWnd window, set this value to FALSE.

lParam specifies the status of the window.

//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_CREATE:
	MessageBox(NULL, "The window is being created", WindowCaption, MB_OK);
	break;
    case WM_SHOWWINDOW:
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------
 

Window Activation

WM_ACTIVATE: When two or more windows are running on the computer, only one can receive input from the user, that is, only one can actually be directly used at one particular time. Such a window has a title bar with the color identified in Control Panel as Active Window. The other window(s), if any, display(s) its/their title bar with a color called Inactive Window:

Display Properties

To manage this setting, the windows are organized in a 3-dimensional coordinate system and they are incrementally positioned on the Z coordinate, which defines the (0, 0, 0) origin on the screen (actually on the top-left corner of your monitor) with Z coordinate coming from the screen towards you.

In order to use a window other than the one that is active, you must activate it. To do this, you can send a message called WM_ACTIVATE.

The syntax of this message is:

OnActivate(HWND hWnd, WM_ACTIVATE, WPARAM wParam, LPARAM lParam);

Actually, this message is sent to two objects: the window that is being activated and the one that is being deactivated.

hWnd identifies a window involved in this message and is related to the wParam parameter.

The wParam parameter specifies the action to take. It is a constant value that can be one of the following:

 
Value Description
WA_ACTIVE Used to activate the window
WA_INACTIVE Used to deactivate the window without using the mouse, for example by pressing Alt+Tab
WA_CLICKACTIVE Used to activate the window using the mouse
//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_CREATE:
	MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK);
	break;
    case WM_ACTIVATE:
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------
 

Window Painting

WM_PAINT: Whenever Microsoft Windows is asked to display (whether it must unhide or activate) a window, it must use its location (measure from left and top) and size (width and height). It must give it the Active Window color and it must restore its other active colors. To do this, the operating system must paint the window. When doing this, a message called WM_PAINT is sent. The syntax of this message is:

OnPaint(HWND hWnd, WM_PAINT, WPARAM wParam, LPARAM lParam);

The only thing Windows needs to know is the window that needs to be painted or repainted, which is specified as the hWnd value.

//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_CREATE:
	MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK);
	break;
    case WM_SHOWWINDOW:
	break;
    case WM_ACTIVATE:
	break;
    case WM_PAINT:
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------
 

Window Sizing

WM_SIZE: When using an application, one of the actions a user may perform is to change its size. Whenever the size of a window has changed, the window receives the WM_SIZE message. Its syntax is:

OnSize(HWND hWnd, WM_SIZE, WPARAM wParam, LPARAM lParam);

hWnd is the window that was resized.

wParam determines how the sizing action should be performed. It can be one of the following values

 
Value Description
SIZE_MAXHIDE Sent to this window if it was maximized from being previously hidden
SIZE_MAXIMIZED Sent to this window if it was maximized
SIZE_MAXSHOW Sent if the window was restored
SIZE_MINIMIZED Sent if the window was minimized
SIZE_RESTORED Sent if the window was resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies


lParam specifies the dimensions of the window (the width and the height

//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_CREATE:
	break;
    case WM_SHOWWINDOW:
	break;
    case WM_ACTIVATE:
	break;
    case WM_PAINT:
	break;
    case WM_SIZE:
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------

WM_SIZING: This message is sent to a window that is being resized with the above WM_SIZE message. Its syntax is:

OnSizing(HWND hWnd, WM_SIZING, WPARAM wParam, LPARAM lParam);

hWnd is the window that is being resized.

To resize a window, the user usually grabs one of the four corners or one of the four borders. The lParam parameter specifies what border or corner the user is moving. It can be one of the following values:

 
Value Border or Corner
WMSZ_BOTTOM Bottom edge
WMSZ_BOTTOMLEFT Bottom-left corner
WMSZ_BOTTOMRIGHT Bottom-right corner
WMSZ_LEFT Left edge
WMSZ_RIGHT Right edge
WMSZ_TOP Top edge
WMSZ_TOPLEFT Top-left corner
WMSZ_TOPRIGHT Top-right corner

lParam is actually the rectangular dimensions of the window that is being resized. It is a RECT object.

 

Window Moving

WM_MOVE: When a window has been moved, the operating system needs to update its location. Therefore, the window sends a message called WM_MOVE. Its syntax is:

OnMove(HWND hWnd, WM_MOVE, WPARAM wParam, LPARAM lParam);

hWnd is the window that needs to be moved. The wParam and lParam values are not used.

WN_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it and reclaim the memory space it was using. The message is called WN_DESTROY and its syntax is:

OnDestroy(HWND hWnd, WN_DESTROY, WPARAM wParam, LPARAM lParam);

hWnd is the window that needs to be destroyed. The wParam and lParam values are not used.

 

Window Destruction

 

WM_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it. The message sent is called WN_DESTROY and its syntax is:

OnDestroy(HWND hwnd, WM_DESTROY, WPARAM wParam, LPARAM lParam);

hWWnd is the window that is being destroyed. The wParam and lParam values are not used.

Anytime  Messages

 

Introduction

The messages we have used so far belong to specific events generated at a particular time by a window. Sometimes in the middle of doing something, you may want to send a message regardless of what is going on. This is made possible by a function called SendMessage(). The syntax of the SendMessage() function is as follows:

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

The hWnd argument is the object or control that is sending the message.
The Msg argument is the message to be sent.
The wParam and the lParam values depend on the message that is being sent.

Sending Messages

The advantage of using the SendMessage() function is that, when sending this message, it would target the procedure that can perform the task and this function would return only after its message has been processed. Because this (member) function can sometimes universally be used, that is by any control or object, the application cannot predict the type of message that SendMessage() is carrying. Therefore, (the probable disadvantage is that) you must know the (name or identity of the) message you are sending and you must provide accurate accompanying items (like sending a letter with the right stamp; imagine you send a sexy letter to your grand-mother in Australia about her already dead grand grand-father who is celebrating his first job while he has just become 5 years old).

In order to send a message using the SendMessage() function, you must know what message you are sending and what that message needs in order to be complete. For example, to change the caption of a window at any time, you can use the WM_SETTEXT message. The syntax to use would be:

SendMessage(hWnd, WM_SETTEXT, wParam, lParam);

Obviously you would need to provide the text for the caption you are trying to change. This string is carried by the lParam argument as a null-terminated string. For this message, the wParam is ignored.

LPCTSTR strMsg = L"This message was sent";
SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)strMsg);
 

Previous Copyright © 2003-2015, FunctionX Next