Broad Network


Basics of Message Handling in Windows

Getting to know Windows – Part 5

Volume - Windows User Interface

Forward: In this part of the series we look at basics of message handling in windows.

By: Chrysanthus Date Published: 28 Aug 2012

Introduction

This is part 5 of my series, Getting to know Windows. I assume you have read all the previous tutorials before reaching here. You should be reading the tutorials in the order given. In this part of the series we look at basics of message handling in Windows.

Note: If you cannot see the code or if you think anything is missing (broken link, image absent), just contact me at forchatrans@yahoo.com. That is, contact me for the slightest problem you have about what you are reading.

Some Data Types and Predefined Functions
In this section we look at some data types and some predefined functions offered by the User Interface (Windows API) to handle messages. We are talking about the messages that are sent to the window class procedure. A message has to be removed from the queue and dispatched (sent) to a procedure. There are certain data types and functions associated with this.

The DOOL Type
The BOOL data type is for a Boolean value. A Boolean value is either the value, TRUE or FALSE. TRUE can also be a number and FALSE can also be a number.

The MSG struct
A message has four parts (parameters). The MSG is a struct like the C++ struct. It is used to hold a system message. Its members are:

{
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
}

We shall not use the last two members for most of the tutorials. The first four members are the different message parts we have been talking about. You have the windows handle, the message identifier (message) and the two parameters for the message data (or data location).

The GetMessage Function
The GetMessage function retrieves a message from the queue and places it in an MSG structure (struct), which you should have declared. When a message is retrieved, it is removed from the queue and it is no longer in the queue. The GetMessage function would normally return a nonzero number. However, if the message it retrieves is WM_QUIT, which means Quit the Application, the function will return zero. Note: messages are integers.

The simple prototype of the GetMessage function is:

BOOL WINAPI GetMessage(LPMSG lpMsg,  HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

lpMsg is the address to the MSG structure. hWnd is the handle of the window whose messages are to be retrieved from the queue. If hWnd is NULL the function retrieves message that is for any window. wMsgFilterMin and wMsgFilterMax are each an integer value. For simple programming, set these two values to zero.

The return value is a BOOL. The precise return type is BOOL WINAPI; do not worry much about that for now. The function normally returns a nonzero number. If the function retrieves the WM_QUIT message, the return value is zero. If there is an error, the returned value is – 1. Note that none of the parameters of the GetMessage function actually handles the message. The function gets the message from the queue and places it in the MSG struct; the message does not pass through the function.

The TranslateMessage Function
The TranslateMessage function deals with keyboard character inputs. Each time the user presses a key, the operating system generates virtual-key messages (WM_KEYDOWN and WM_KEYUP). As the user is pressing a key, the WM_KEYDOWN message is generated and goes into the queue. When the user releases the key, the WM_KEYUP message is generated and goes into the queue. Remember, these messages are actually integers.

A virtual-key message contains a virtual-key code that identifies which key was pressed, but not its character value. To obtain the value, you have to use the TranslateMessage function. The simplified prototype of the TranslateMessage function is:

BOOL WINAPI TranslateMessage(const MSG *lpMsg);

It has only one argument, which is the address of the MSG struct, which should be having the message that the GetMessage function got from the queue. Its return value is a BOOL (a number). If the message is translated, the return value is nonzero. If the message is not translated the return value is zero.

If the TranslateMessage function translates a message, it posts (sends) the translated message to the queue, in a different form as a new message.

Note: The return value of the function is not the character value. The TranslateMessage function translates (converts) the virtual-key message into a character message (WM_CHAR) and places it back into the application message queue. The character message will then have to be removed from the queue before being sent (dispatched) to the window class procedure. The message placed back into the queue has the character value (code).

The DispatchMessage Function
The DispatchMessage function sends the message read from the MSG struct to the window class procedure. This function knows what window the message will act on, by the window handle in the message in the MSG struct. If the window handle parameter in the MSG struct is NULL, the DispatchMessage function does nothing (does not send any message) so far as windows are concerned.

Handling Events in Windows
Any input action (keyboard or mouse) in Windows is an event. When the user clicks an item, he sees the response automatically. From a technical point of view, there is nothing like, automatically, in the handling of events. You, the application developer has to write a WHILE Loop to do that.

When an event occurs the corresponding message is sent to the system message queue and it stays there. If it is not removed and sent to the window class procedure the user will see no response. You have to write a while loop that will be iterating continuously, removing the messages from the queue and sending to their respective window class procedures. It is the window class procedure that provides the response. Since the while loop is operating naturally very fast and continuously, the user sees a very quick response to his event. So, to the user, the response is automatic.

The WHILE Loop Code for Events
The while loop works with an MSG data type. The following is classical code:

MSG msg;
BOOL bRet;
HWND hwnd;

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

In the code, first you have the identifier (msg) for an MSG struct declared. Next you have an identifier (bRet) for a BOOL type declared. You then have another identifier (hwnd) for the window handle of interest, declared, with the HWND type. We shall see more about window handles later. Then you have the while loop.

The condition in the while loop is:

        (bRet = GetMessage(&msg, hwnd, 0, 0 )) != 0

Look at the condition very well. It removes the next window message from the queue and places it in the msg struct. The return value of the GetMessage function is a BOOL (and not the message) is assigned to the identifier, bRet. If the value of bRet is zero, it means the message is WM_QUIT, which means the application should quit and the while loop should stop. If bRet is not zero is means, the GetMessage function succeeded to remove a message from the queue or an error occurred in the attempt to remove a message. That is why you have “!= 0” at the end of the while condition. If the value of bRet is –1, it means an error occurred in the message removal attempt. However, the while loop iteration will still execute, since it is “!=-0” and not “!= -1” that determines the execution of the while loop block.

If the while loop block is to execute, it means either the message removal and placing into the msg struct was successful or an error occurred. In the while loop block, there is an if-construct. The if-block of the construct handles the error if bRet were –1. The else-block of the construct has the TranslateMessage, and the DispatchMessage functions. Each of these functions uses the message in the msg struct.

The Window Class Procedure
One procedure can serve more than one window, if they are of the same class. If a message is for a particular window, the window is identified by its handle.

A window procedure should not ignore a message. If it does not process a message, it must send the message to the DefWindowProc procedure for default processing. In order to do this, the window procedure calls the default DefWindowProc procedure, which performs a default action and returns a message result. DefWindowProc is a predefined function that would give a default processing to what the window class procedure does not do.

Remark
In Windows API, the message queue is a built-in structure that I have not explain or given to you; I have not even mentioned anything about its address. The TranslateMessage and DispatchMessage functions are built-in (predefined) functions whose block code I have not explained or given to you. The DefWindowProc procedure is also a built-in function whose block code I have not explained or given to you. I have only talked to you about their purposes. The only code I have explained so far, is the WHILE loop. Now read the previous part of the series and this part again, to be sure of where you stand (in understanding the tutorials).

We have seen much in this part of the series. Read the previous part and this part again, and then continue with the next part, where you will see more code.

Chrys

Related Courses

C++ Course
Relational Database and Sybase
Windows User Interface
Computer Programmer – A Jack of all Trade – Poem
NEXT

Comments

Become the Writer's Fan
Send the Writer a Message