Jump to content

PMGuide - Messages and Message Queues: Difference between revisions

From EDM2
Created page with "The OS/2 operating system uses messages and message queues to communicate with applications and the windows belonging to those applications. This chapter explains how to create and use messages and message queues in PM applications. ==About Messages and Message Queues== Unlike traditional applications that take complete control of the computer's keyboard, mouse, and screen, PM applications must share these resources with other applications that are running at the sa..."
 
No edit summary
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
The OS/2 operating system uses messages and message queues to communicate  
{{IBM-Reprint}}
with applications and the windows belonging to those applications. This chapter  
{{PMGuide}}
explains how to create and use messages and message queues in PM applications.  
The OS/2 operating system uses messages and message queues to communicate with applications and the windows belonging to those applications. This chapter explains how to create and use messages and message queues in PM applications.  


==About Messages and Message Queues==
==About Messages and Message Queues==


Unlike traditional applications that take complete control of the computer's keyboard, mouse, and screen, PM applications must share these resources with other applications that are running at the same time. All applications run  
Unlike traditional applications that take complete control of the computer's keyboard, mouse, and screen, PM applications must share these resources with other applications that are running at the same time. All applications run independently and rely on the operating system to help them manage shared resources. The operating system does this by controlling the operation of each application, communicating with each application when there is keyboard or mouse input or when an application must move and size its windows.  
independently and rely on the operating system to help them manage shared resources. The  
operating system does this by controlling the operation of each application,  
communicating with each application when there is keyboard or mouse input or when an  
application must move and size its windows.  


===Messages===
===Messages===


A <tt>:hp1.message :ehp1.</tt> is information, a request for information, or a request for an  
A ''message'' is information, a request for information, or a request for an action to be carried out by a window in an application.  
action to be carried out by a window in an application.  


The operating system, or an application, sends or posts a message to a window  
The operating system, or an application, sends or posts a message to a window so that the window can use the information or respond to the request.  
so that the window can use the information or respond to the request.  


There are three types of messages:  
There are three types of messages:  
Line 24: Line 18:
* System-initiated  
* System-initiated  


A user-initiated message is the direct result of a user action, such as  
A user-initiated message is the direct result of a user action, such as selecting a menu item or pressing a key. An application-initiated message is generated by one window in the application to communicate with another window. System-initiated messages are generated by the interface as the indirect result of a user action (for example, resizing a window) or as the direct result of a system event (such as creating a window).  
selecting a menu item or pressing a key. An application-initiated message is  
generated by one window in the application to communicate with another window. System
-initiated messages are generated by the interface as the indirect result of a  
user action (for example, resizing a window) or as the direct result of a system  
event (such as creating a window).  


A message that requires an immediate response from a window is sent directly  
A message that requires an immediate response from a window is sent directly  
Line 36: Line 25:
out default processing for the message.  
out default processing for the message.  


A message that does not require an immediate response from a window is <tt>:hp1.posted :ehp1.</tt>
A message that does not require an immediate response from a window is ''posted'' (the message data is copied) to the application's ''message queue''. The  
(the message data is copied) to the application's <tt>:hp1.message queue:ehp1.</tt>. The  
message queue is a storage area that the application creates to receive and hold its  
message queue is a storage area that the application creates to receive and hold its  
posted messages. Then, the application can retrieve a message at the appropriate  
posted messages. Then, the application can retrieve a message at the appropriate  
time, sending it to the addressed window for processing.  
time, sending it to the addressed window for processing.  


Every message contains a <tt>:hp1.message identifier:ehp1.</tt>, which is a 16-bit integer that  
Every message contains a ''message identifier'', which is a 16-bit integer that  
indicates the purpose of the message. When a window processes a message, it uses the  
indicates the purpose of the message. When a window processes a message, it uses the  
message identifier to determine what to do.  
message identifier to determine what to do.  


Every message contains a <tt>:hp1.window handle:ehp1.</tt>, which identifies the window the  
Every message contains a ''window handle'', which identifies the window the  
message is for. The window handle is important because most message queues and  
message is for. The window handle is important because most message queues and  
window procedures serve more than one window. The window handle ensures that the  
window procedures serve more than one window. The window handle ensures that the  
application forwards the message to the proper window.  
application forwards the message to the proper window.  


A message contains two <tt>:hp1.message parameters:ehp1.</tt>—32-bit values that specify data or  
A message contains two ''message parameters''—32-bit values that specify data or  
the location of data that a window uses when processing the message. The  
the location of data that a window uses when processing the message. The  
meaning and value of a message parameter depend on the message. A message parameter  
meaning and value of a message parameter depend on the message. A message parameter  
Line 59: Line 47:
identifier to determine how to interpret the message parameters.  
identifier to determine how to interpret the message parameters.  


A <tt>:hp1.queue message :ehp1.</tt> is a QMSG data structure that contains six data items,  
A ''queue message'' is a QMSG data structure that contains six data items,  
representing the window handle, message identifier, two message parameters, message time,  
representing the window handle, message identifier, two message parameters, message time,  
and mouse-pointer position. The time and position are included because most  
and mouse-pointer position. The time and position are included because most  
Line 67: Line 55:
and copying it to a message queue.  
and copying it to a message queue.  


A <tt>:hp1.window message :ehp1.</tt> consists of the window handle, the message identifier, and  
A ''window message'' consists of the window handle, the message identifier, and  
two message parameters. A window message does not include the message time and  
two message parameters. A window message does not include the message time and  
mouse-pointer position, because most window messages are requests to perform a task  
mouse-pointer position, because most window messages are requests to perform a task  
that is not related to the current time or mouse-pointer position. The operating  
that is not related to the current time or mouse-pointer position. The operating  
system sends a window message by passing these values, as individual arguments, to a  
system sends a window message by passing these values, as individual arguments, to a  
window procedure.  
window procedure.


===Message Queues===
===Message Queues===


Every PM application must have a <tt>:hp1.message queue:ehp1.</tt>. A message queue is the  
Every PM application must have a ''message queue''. A message queue is the  
only means an application has to receive input from the keyboard or mouse. <tt>:hp1.Only  
only means an application has to receive input from the keyboard or mouse. ''Only  
applications that create message queues can create windows:ehp1.</tt>.  
applications that create message queues can create windows''.  


An application creates a message queue by using the WinCreateMsgQueue  
An application creates a message queue by using the WinCreateMsgQueue  
Line 102: Line 90:
subsequent messages intended for that window to that queue.  
subsequent messages intended for that window to that queue.  


<tt>:hp2.Note: :ehp2.</tt> The recommended way to structure PM applications is to have at  
;Note: The recommended way to structure PM applications is to have at least two threads and two message queues. The first thread and message queue control all the user-interface windows, and the second thread and message queue control all the object windows.  
least two threads and two message queues. The first thread and message queue  
control all the user-interface windows, and the second thread and message queue control  
all the object windows.  


Several windows can use one message queue; it is important that the message  
Several windows can use one message queue; it is important that the message  
Line 113: Line 98:
of messages is 10.  
of messages is 10.  


To minimize queue size, several types of posted messages are not actually  
To minimize queue size, several types of posted messages are not actually stored in a message queue. Instead, the operating system keeps a record in the queue of the message being posted and combines any information contained in the message with information from previous messages. Timer, semaphore, and paint messages are handled this way. For example, if more than one WM_PAINT message is posted, the operating system combines the ''update regions'' for each into a single update region. Although there is no actual WM_PAINT message in the queue, the operating system constructs one WM_PAINT message with the single update region when an application uses the WinGetMsg function.  
stored in a message queue. Instead, the operating system keeps a record in the  
queue of the message being posted and combines any information contained in the  
message with information from previous messages. Timer, semaphore, and paint  
messages are handled this way. For example, if more than one WM_PAINT message is  
posted, the operating system combines the <tt>:hp1.update regions :ehp1.</tt> for each into a single update  
region. Although there is no actual WM_PAINT message in the queue, the operating  
system constructs one WM_PAINT message with the single update region when an  
application uses the WinGetMsg function.  


The operating system handles mouse and keyboard input messages differently  
The operating system handles mouse and keyboard input messages differently  
Line 133: Line 110:
The operating system message queue usually is large enough to hold all input  
The operating system message queue usually is large enough to hold all input  
messages, even if the user types or moves the mouse very quickly. If the operating  
messages, even if the user types or moves the mouse very quickly. If the operating  
system message queue does run out of space, the system <tt>:hp1.ignores :ehp1.</tt> the most recent  
system message queue does run out of space, the system ''ignores'' the most recent  
keyboard input (usually by beeping to indicate the input is ignored) and collects mouse  
keyboard input (usually by beeping to indicate the input is ignored) and collects mouse  
motions into a WM_MOUSEMOVE message.  
motions into a WM_MOUSEMOVE message.  
Line 147: Line 124:
WinPeekMsg function to examine the contents of a message queue. WinPeekMsg checks for  
WinPeekMsg function to examine the contents of a message queue. WinPeekMsg checks for  
a specific message or range of messages in the queue and gives the application  
a specific message or range of messages in the queue and gives the application  
the option of removing messages from the queue. An application <tt>:hp1.can :ehp1.</tt> call the  
the option of removing messages from the queue. An application ''can'' call the  
WinQueryQueueStatus function to determine the contents of the queue before calling the WinPeekMsg  
WinQueryQueueStatus function to determine the contents of the queue before calling the WinPeekMsg  
or WinGetMsg function to remove a message from the queue.  
or WinGetMsg function to remove a message from the queue.  
Line 153: Line 130:
===Message Handling===
===Message Handling===


To handle and process messages, an application can use a <tt>:hp1.message loop :ehp1.</tt> and the <tt>:hp1.
To handle and process messages, an application can use a ''message loop '' and the ''window procedure''. These terms are explained in the following two sections.  
window procedure:ehp1.</tt>. These terms are explained in the following two sections.  


==== Message Loops ====
==== Message Loops ====
Line 183: Line 159:
<pre>
<pre>
             Mouse ───┐  ┌─── Keystrokes
             Mouse ───┐  ┌─── Keystrokes
                      
                     |   |
                   ┌─┴───┴─┐
                   ┌─┴───┴─┐
                   ├───────┤ System
                   ├───────┤ System
Line 190: Line 166:
                   └───┬───┘
                   └───┬───┘
                       │
                       │
                      
                       |
                   ┌────┴───┐
                   ┌────┴───┐
                   │ Input  │ Scancode
                   │ Input  │ Scancode
           ┌�─────┤ Router │ Translation
           ┌-─────┤ Router │ Translation
           │      └────────┘
           │      └────────┘
          
           |
   ┌───────┴──────┐
   ┌───────┴──────┐
   │ Message      │ Accelerator
   │ Message      │ Accelerator
Line 209: Line 185:
                      
                      
  │          ┌────── ┴─WinGetMsgQ          │
  │          ┌────── ┴─WinGetMsgQ          │
                       WinDispatchMsg
             |           WinDispatchMsg
  │          │              │            │
  │          │              │            │
     App's  │             
     App's  │              |
  │  Message │        Window Procedure    │
  │  Message │        Window Procedure    │
     Loop    │              │
     Loop    │              │
  │          │                          │
  │          │              |             │
             └�───────────return;
             └-───────────return;
  └─  ──  ──  ──  ──  ──  ──  ──  ──  ──  ─┘
  └─  ──  ──  ──  ──  ──  ──  ──  ──  ──  ─┘
</pre>
</pre>
Line 245: Line 221:
is useful for applications that temporarily need to bypass the usual FIFO order of  
is useful for applications that temporarily need to bypass the usual FIFO order of  
the message queue.
the message queue.
==== Window Procedures ====
A ''window procedure'' is a function that receives and processes all input and
requests for action sent to the windows. Every window class has a window procedure;
every window created using that class uses that window procedure to respond to
messages.
The system sends a message to the window procedure by passing the message
data as arguments. The window procedure takes the appropriate action for the
given message. Most window procedures check the message identifier, then use the
information specified by the message parameters to carry out the request. When it has
completed processing the message, the window procedure returns a message result. Each
message has a particular set of possible return values. The window procedure must
return the appropriate value for the processing it performed.
A window procedure cannot ignore a message. If it does not process a
message, it must pass the message back to the operating system for default processing.
The window procedure does this by calling the WinDefWindowProc function to
carry out a default action and return the message result. Then, the window
procedure must return this value as its own message result.
A window procedure commonly processes messages for several windows. It
uses the window handle specified in the message to identify the appropriate window.
Most window procedures process just a few types of messages and pass the others
on to the operating system by calling WinDefWindowProc.
=== Posting and Sending Messages ===
Any application can post and send messages. Like the operating system, an
application ''posts'' a message by copying it to a message queue. It ''sends'' a message by
passing the message data as arguments to a window procedure. To post and send
messages, an application uses the WinPostMsg and WinSendMsg functions.
An application posts a message to notify a specific window to perform a task.
The WinPostMsg function creates a QMSG structure for the message and copies the
message to the message queue corresponding to the given window. The application's message loop eventually retrieves the message and dispatches it to the
appropriate window procedure. For example, one message commonly posted is WM_QUIT.
This message terminates the application by terminating the message loop.
An application sends a message to cause a specific window procedure to carry
out a task immediately. The WinSendMsg function passes 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 entry-field control as its child window can set
the text of the control by sending a message to the child window. The control
can notify the parent window of changes to the text (carried out by the user) by
sending messages back to the parent window.
Occasionally, an application might need to send or post a message to all
windows in the system. For example, if the application changes a system value, it
must notify all windows about the change by sending a WM_SYSVALUECHANGED message.
An application can send or post messages to any number of windows by using the
WinBroadcastMsg function. The options in WinBroadcastMsg determine whether the message is
sent or posted and specify the windows that will receive the message.
Any thread in the application can post a message to a message queue, even if
the thread has no message queue of its own. However, only a thread that has a
message queue can send a message. Sending a message between threads is relatively
uncommon. For one reason, sending a message is costly in terms of system performance.
If an application posts a message between threads, it is likely to be a
semaphore message, which permits window procedures to manage a shared resource jointly.
An application can post a message without specifying a window. If the
application supplies a NULL window handle when it calls the WinPostMsg function, the
function posts the message to the queue associated with the current thread. 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.
A window procedure can determine whether it is processing a message sent by
another thread by using the WinInSendMsg function. This is useful when message
processing depends on the origin of the message.
A common programming error is to assume that the WinPostMsg function always
succeeds. It fails when the message queue is full. An application should check
the return value of the WinPostMsg function to see whether the message was posted.
In general, if an application intends to post many messages to the queue, it
should set the message queue to an appropriate size when it creates the queue. The
default message-queue size is 10 messages.
=== Message Types ===
This section describes the three types of OS/2 messages:
* System-defined
* Application-defined
* Semaphore
==== System-Defined Messages ====
There are many ''system-defined '' messages that are used to control the
operations of applications and to provide input and other information for applications to
process. The system sends or posts a system-defined message when it communicates
with an application. An application also can send or post system-defined
messages. Usually, applications use these messages to control the operation of
control windows created by using preregistered window classes.
Each system message has a unique message identifier and a corresponding
symbolic constant. The symbolic constant, defined in the system header files, states
the purpose of the message. For example, the WM_PAINT constant represents the
paint message, which requests that a window paint its contents.
The symbolic constants also specify the ''message category''. System-defined
messages can belong to several categories; the prefix identifies the type of window that
can interpret and process the messages. The following table lists the prefixes
and their related message categories:
{| class="wikitable"
|+
! Prefix !! Message category
|-
| BKM_ || Notebook control
|-
| BM_ || Button control
|-
| CBM_ || Combination-box control
|-
| CM_ || Container control
|-
| EM_ || Entry-field control
|-
| LM_ || List-box control
|-
| MLM_ || Multiple-line entry field control
|-
| MM_ || Menu control
|-
| SBM_ || Scroll-bar control
|-
| SLM_ || Slider control
|-
| SM_ || Static control
|-
| TBM_ || Title-bar control
|-
| VM_ || Value set control
|-
| WM_ || General window
|}
General window messages cover a wide range of information and requests,
including:
* Mouse and keyboard-input
* Menu- and dialog-input
* Window creation and management
* Dynamic data exchange (DDE)
==== Application-Defined Messages ====
An application can create messages to use in its own windows. If an
application does create messages, the window procedure that receives the messages must
interpret them and provide the appropriate processing.
The operating system reserves the message-identifier values in the range ''0x0000 '' through ''0x0FFF'' (the value of WM_USER - 1) for system-defined messages.
Applications cannot use these values for their private messages.
In addition, the operating system uses certain message values higher than '''WM_USER'''. Applications should not use these message values. A partial listing of these messages is in the following figure:
<pre>
From PMSTDDLG.H:
#define FDM_FILTER    WM_USER+40
#define FDM_VALIDATE  WM_USER+41
#define FDM_ERROR      WM_USER+42
#define FNTM_FACENAMECHANGED  WM_USER+50
#define FNTM_POINTSIZECHANGED  WM_USER+51
#define FNTM_STYLECHANGED    WM_USER+52
#define FNTM_COLORCHANGED    WM_USER+53
#define FNTM_UPDATEPREVIEW  WM_USER+54
#define FNTM_FILTERLIST      WM_USER+55
</pre>
You should scan your header files to see if other messages have been defined
with values higher than WM_USER.
Aside from the message values used by the operating system, values in the
range ''0x1000'' (the value of WM_USER) through ''0xBFFF'' are available for message
identifiers, defined by an application, for use in that application.
;Warning:It is very important that applications do not broadcast messages in the ''0x1000'' through ''0xBFFF'' range due to the risk of misinterpretation by other applications.
Values in the range ''0xC000'' through ''0xFFFF'' are reserved for message identifiers that an application defines and registers with the system atom table; these can be used in any application. Values above ''0xFFFF'' (0x00010000 through 0xFFFFFFFF) are reserved for future use; applications must not use messages in this range.
==== Semaphore Messages ====
A ''semaphore message'' provides a way of signaling, through the message queue,
the end of an event. An application uses a semaphore message the same way it
uses system semaphore functions—to coordinate events by passing signals. A
semaphore message often is used in conjunction with system semaphores.
There are four semaphore messages:
* WM_SEM1
* WM_SEM2
* WM_SEM3
* WM_SEM4.
An application posts one of these messages to signal the end of a given event.
The window that is waiting for the given event receives the semaphore message
when the message loop retrieves and dispatches the message.
Each semaphore message includes a bit flag that an application can use to
uniquely identify the 32 possible semaphores for each semaphore message. The
application passes the bit flag (with the appropriate bit set) as a message parameter with
the message. The window procedure that receives the message then uses the bit
flag to identify the semaphore.
To save space, the system does not store semaphore messages in the message
queue. Instead, it sets a record in the queue, indicating that the semaphore
message has been received, and then combines the bit flag for the message with the bit
flags from previous messages. When the window procedure eventually receives the
message, the bit flag specifies each semaphore message posted since the last message
was retrieved.
=== Message Priorities ===
The WinGetMsg function retrieves messages from the message queue based on
message priority. WinGetMsg retrieves messages with higher priority first. If
it finds more than one message at a particular priority level, it retrieves the
oldest message first. Messages have the following priorities:
{| class="wikitable"
|+
! Priority !! Message
|-
| '''1''' || WM_SEM1
|-
| '''2''' || Messages posted using WinPostMsg
|-
| '''3''' || Input messages from the keyboard or mouse
|-
| '''4''' || WM_SEM2
|-
| '''5''' || WM_PAINT
|-
| '''6''' || WM_SEM3
|-
| '''7''' || WM_TIMER
|-
| '''8''' || WM_SEM4
|}
=== Message Filtering ===
An application can choose specific messages to retrieve from the message queue (and ignore other messages) by specifying a message filter with the WinGetMsg or WinPeekMsg functions. The message filter is a range of message identifiers (specified by a first and last identifier), a window handle, or both. The WinGetMsg and WinPeekMsg functions use the ''message filter'' to select the messages to
retrieve from the queue. Message filtering is useful if an application needs to search ahead in the message queue for messages that have a lower priority or that arrived in the queue later than other less important messages.
Any application that filters messages must ensure that a message satisfying
the message filter can be posted. For example, filtering for a WM_CHAR message
in a window that does not receive keyboard input prevents the WinGetMsg function
from returning. Some messages, such as WM_COMMAND, are generated from other
messages; filtering for them also can prevent WinGetMsg from returning.
To filter for mouse, button, and DDE messages, an application can use the
following constants:
* WM_MOUSEFIRST and WM_MOUSELAST
* WM_BUTTONCLICKFIRST and WM_BUTTONCLICKLAST
* WM_DDE_FIRST and WM_DDE_LAST.
== Using Messages ==
This section explains how to perform the following tasks:
* Create a message queue and message loop
* Examine the message queue
* Post and send messages between windows
* Broadcast a message to multiple windows
* Use message macros
=== Creating a Message Queue and Message Loop ===
An application needs a message queue and message loop to process messages for
its windows. An application creates a message queue by using the
WinCreateMsgQueue function. An application creates a message loop by using the WinGetMsg and
WinDispatchMsg functions. The application must create and show at least one window after
creating the queue but before starting the message loop. The following code fragment
shows how to create a message queue and message loop:
<pre>
MRESULT EXPENTRY ClientWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2);
HAB hab;
int main(VOID)
{
    HMQ hmq;
    QMSG qmsg;
    HWND hwndFrame, hwndClient;
    ULONG flFrameFlags = FCF_TITLEBAR    | FCF_SYSMENU |
                          FCF_SIZEBORDER    | FCF_MINMAX  |
                          FCF_SHELLPOSITION | FCF_TASKLIST;
                                        /* Initialize the application for
                                            Presentation Manager interface.        */
    hab = WinInitialize(0);
                                        /* Create the application
                                            message queue.                  */
    hmq = WinCreateMsgQueue(hab, 0);
                                        /* Register the window class for your
                                            client window.                  */
    WinRegisterClass(hab,                /* Anchor block handle            */
                    "MyClientClass",      /* Class name                      */
                    (PFNWP) ClientWndProc,/* Window procedure                */
                    CS_SIZEREDRAW,        /* Class style                    */
                    0);                  /* Extra bytes to reserve          */
                                        /* Create a main window.          */
    hwndFrame = WinCreateStdWindow(
                    HWND_DESKTOP,        /* Parent window handle            */
                    WS_VISIBLE,          /* Style of frame window          */
                    &flFrameFlags,        /* Frame controls                  */
                    "MyClientClass",      /* Window class for client        */
                    (PSZ) NULL,          /* No title-bar text              */
                    WS_VISIBLE,          /* Style of client window          */
                    (HMODULE) NULL,      /* Module handle for resources    */
                    0,                    /* No resource identifier          */
                    &hwndClient);        /* Pointer to client handle        */
                                        /* Start the message loop.        */
    while (WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0))
        WinDispatchMsg(hab, &qmsg);
                                        /*. Destroy the main window.      */
    WinDestroyWindow(hwndFrame);
                                        /* Destroy the message queue.    */
    WinDestroyMsgQueue(hmq);
                                        /* Terminate the application.    */
    WinTerminate(hab);
}
</pre>
Both the WinGetMsg and WinDispatchMsg functions take a pointer to a QMSG
structure as a parameter. If a message is available, WinGetMsg copies it to the QMSG
structure; WinDispatchMsg then uses the data in the structure as arguments for the window
procedure.
Occasionally, an application might need to process a message before
dispatching it. For example, if a message is posted but the destination window is not
specified (that is, the message contains a NULL window handle), the application must
process the message to determine which window should receive the message. Then the
WinDispatchMsg function can forward the message to the proper window. The following code
fragment shows how the message loop can process messages that have NULL window handles
:
<pre>
HAB hab;
QMSG qmsg;
while (WinGetMsg (hab, &qmsg, (HWND) NULL, 0, 0)) {
    if (qmsg.hwnd == NULL) {
        .
        . /* Process the message. */
        .
    }
    else
        WinDispatchMsg (hab, &qmsg);
    }
</pre>
=== Examining the Message Queue ===
An application can examine the contents of the message queue by using the
WinPeekMsg or WinQueryQueueStatus function. It is useful to examine the queue if the
application starts a lengthy operation that additional user input might affect, or if the
application needs to look ahead in the queue to anticipate a response to user input.
An application can use WinPeekMsg to check for specific messages in the
message queue. This function is useful for extracting messages for a specific
window from the queue. It returns immediately if there is no message in the queue.
An application can use WinPeekMsg in a loop without requiring the loop to wait
for a message to arrive. The following code fragment checks the queue for WM_
CHAR messages:
<pre>
HAB hab;
QMSG qmsg;
if (WinPeekMsg(hab, &qmsg, (HWND) NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE)){
            .
            . /* Process the message. */
            .
}
</pre>
An application also can use the WinQueryQueueStatus function to check for
messages in the queue. This function is very fast and returns information about the
kinds of messages available in the queue and which messages have been posted recently.
Most applications use this function in message loops that need to be as fast as
possible.
=== Posting a Message to a Window ===
An application can use the WinPostMsg function to post a message to a window.
The message goes to the window's message queue. The following code
fragment posts the WM_QUIT message.
<pre>
HWND hwnd;
if (!WinPostMsg(hwnd, WM_QUIT, NULL, NULL)){
    /* Message was not posted. */
}
</pre>
The WinPostMsg function returns FALSE if the queue is full, and the message
cannot be posted.
=== Sending a Message to a Window ===
An application can use the WinSendMsg function to send a message directly to
a window. An application uses this function to send messages to child windows.
For example, the following code fragment sends an LM_INSERTITEM message to
direct a list-box control to add an item to the end of its list:
<pre>
HWND hwndListBox;
static CHAR szWeekday[] = "Tuesday";
WinSendMsg(hwndListBox,
          LM_INSERTITEM,
          (MPARAM)LIT_END,
          MPFROMP(szWeekday));
</pre>
WinSendMsg calls the window's window procedure and waits for it to
handle the message and return a result. An application can send a message to any
window in the system, as long as the application has the handle of the target window.
The message queue does not store the message; however, the thread making the
call must have a message queue.
=== Broadcasting a Message ===
An application can send a message to multiple windows by using the
WinBroadcastMsg function. Often this function is used to broadcast the WM_SYSVALUECHANGED
message after an application changes a system value. The following code fragment
shows how to broadcast this message to all frame windows in all applications:
<pre>
HWND hwnd;
WinBroadcastMsg(
    hwnd,                                    /* Window handle            */
    WM_SYSVALUECHANGED,                      /* Message identifier        */
    NULL,                                    /* No message parameters    */
    NULL,
    BMSG_FRAMEONLY | BMSG_POSTQUEUE);        /* All frame windows        */
</pre>
An application can broadcast messages to all windows, just frame windows, or
just the windows in the application.
=== Using Message Macros ===
The system header files define several macros that help create and interpret
message parameters.
One set of macros helps you construct message parameters. These macros
are useful for sending and posting messages. For example, the following code
fragment uses the MPFROMSHORT macro to convert a 16-bit integer into the 32-bit message
parameter:
<pre>
HWND hwndButton;
WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), NULL);
</pre>
A second set of macros helps you extract values from a message parameter.
These macros are useful for handling messages in a window procedure. The
following code fragment determines whether the window receiving the WM_FOCUSCHANGE
message is gaining or losing the keyboard focus. The fragment uses the SHORT1FROMMP
macro to extract the focus-change flag, the SHORT2FROMMP macro to extract the focus
flag, and the HWNDFROMMP macro to extract the window handle.
<pre>
USHORT fsFocusChange;
MPARAM mp1, mp2;
HWND hwndGainFocus;
case WM_FOCUSCHANGE:
    fsFocusChange = SHORT2FROMMP(mp2);    /* Gets focus-change flags  */
    if (SHORT1FROMMP(mp2))                /* Gaining or losing focus? */
        hwndGainFocus = HWNDFROMMP(mp1);
</pre>
A third set of macros helps you construct a message result. These macros
are useful for returning message results in a window procedure, as the following
code fragment illustrates:
<pre>
return (MRFROM2SHORT(1, 2));
</pre>

Latest revision as of 04:16, 11 May 2025

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

Presentation Manager Programming Guide and Reference
  1. How to Use this Book
  2. Device Functions
  3. Direct Manipulation Functions
  4. Dynamic Data Formatting Functions
  5. Hooks and Procedures
  6. Profile Functions
  7. Spooler Functions
  8. Window Functions
  9. Message Processing
  10. Data Types
  11. Errors
  12. Atom Tables
  13. Button Controls
  14. Clipboards
  15. Combination Box
  16. Container Controls
  17. Control Windows
  18. Cursors
  19. Dialog Windows
  20. Direct Manipulation
  21. Drawing in Windows
  22. Dynamic Data Exchange
  23. Entry-Field Controls
  24. File Dialog Controls
  25. Font Dialog Controls
  26. Frame Windows
  27. Hooks
  28. Initialization Files
  29. Keyboard Accelerators
  30. List-Box Controls
  31. Menus
  32. Messages and Message Queues
  33. Multiple-Line Entry Field Controls
  34. Mouse and Keyboard Input
  35. Mouse Pointers and Icons
  36. Notebook Controls
  37. Painting and Drawing
  38. Presentation Parameters
  39. Resource Files
  40. Scroll-Bar Controls
  41. Slider Controls
  42. Spin Button Controls
  43. Static Controls
  44. Title-Bar Controls
  45. Value Set Controls
  46. Windows
  47. Window Classes
  48. Window Procedures
  49. Window Timers
  50. Appendices
  51. Notices
  52. Glossary

The OS/2 operating system uses messages and message queues to communicate with applications and the windows belonging to those applications. This chapter explains how to create and use messages and message queues in PM applications.

About Messages and Message Queues

Unlike traditional applications that take complete control of the computer's keyboard, mouse, and screen, PM applications must share these resources with other applications that are running at the same time. All applications run independently and rely on the operating system to help them manage shared resources. The operating system does this by controlling the operation of each application, communicating with each application when there is keyboard or mouse input or when an application must move and size its windows.

Messages

A message is information, a request for information, or a request for an action to be carried out by a window in an application.

The operating system, or an application, sends or posts a message to a window so that the window can use the information or respond to the request.

There are three types of messages:

  • User-initiated
  • Application-initiated
  • System-initiated

A user-initiated message is the direct result of a user action, such as selecting a menu item or pressing a key. An application-initiated message is generated by one window in the application to communicate with another window. System-initiated messages are generated by the interface as the indirect result of a user action (for example, resizing a window) or as the direct result of a system event (such as creating a window).

A message that requires an immediate response from a window is sent directly to the window by passing the message data as arguments to the window procedure. The window procedure carries out the request or lets the operating system carry out default processing for the message.

A message that does not require an immediate response from a window is posted (the message data is copied) to the application's message queue. The message queue is a storage area that the application creates to receive and hold its posted messages. Then, the application can retrieve a message at the appropriate time, sending it to the addressed window for processing.

Every message contains a message identifier, which is a 16-bit integer that indicates the purpose of the message. When a window processes a message, it uses the message identifier to determine what to do.

Every message contains a window handle, which identifies the window the message is for. The window handle is important because most message queues and window procedures serve more than one window. The window handle ensures that the application forwards the message to the proper window.

A message contains two message parameters—32-bit values that specify data or the location of data that a window uses when processing the message. The meaning and value of a message parameter depend on the message. A message parameter can contain an integer, packed bit flags, a pointer to a structure that contains additional data, and so forth. Some messages do not use message parameters and, typically, set the parameters to NULL. An application always checks the message identifier to determine how to interpret the message parameters.

A queue message is a QMSG data structure that contains six data items, representing the window handle, message identifier, two message parameters, message time, and mouse-pointer position. The time and position are included because most queue messages are input messages, representing keyboard or mouse input from the user. The time and position also help the application identify the context of the message. The operating system posts a queue message by filling the QMSG structure and copying it to a message queue.

A window message consists of the window handle, the message identifier, and two message parameters. A window message does not include the message time and mouse-pointer position, because most window messages are requests to perform a task that is not related to the current time or mouse-pointer position. The operating system sends a window message by passing these values, as individual arguments, to a window procedure.

Message Queues

Every PM application must have a message queue. A message queue is the only means an application has to receive input from the keyboard or mouse. Only applications that create message queues can create windows.

An application creates a message queue by using the WinCreateMsgQueue function. This function returns a handle that the application can use to access the message queue. After an application creates a message queue, the system posts messages intended for windows in the application to that queue. The application can retrieve queue messages by specifying the message-queue handle in the WinGetMsg function. It also can examine messages, without retrieving them, by using the WinPeekMsg function. When an application no longer needs the message queue, it can destroy the queue by using the WinDestroyMsgQueue function.

One message queue serves all the windows in a thread. This means a queue can hold messages for several windows. A message specifies the handle of the window to which it belongs so the application can forward a message easily to the appropriate window. The message loop recognizes a NULL window handle and the message is processed within the message loop rather than passed to WinDispatchMessage. See the following figure for an example of an input-message processing loop.

An application that has more than one thread can create more than one message queue. The system allows one message queue for each thread. A message queue created by a thread belongs to that thread and has no connection to other queues in the application. When an application creates a window in a given thread, the system associates the window with the message queue in that thread. The system then posts all subsequent messages intended for that window to that queue.

Note
The recommended way to structure PM applications is to have at least two threads and two message queues. The first thread and message queue control all the user-interface windows, and the second thread and message queue control all the object windows.

Several windows can use one message queue; it is important that the message queue be large enough to hold all messages that possibly can be posted to it. An application can set the size of the message queue when it creates the queue by specifying the maximum number of messages the queue can hold. The default maximum number of messages is 10.

To minimize queue size, several types of posted messages are not actually stored in a message queue. Instead, the operating system keeps a record in the queue of the message being posted and combines any information contained in the message with information from previous messages. Timer, semaphore, and paint messages are handled this way. For example, if more than one WM_PAINT message is posted, the operating system combines the update regions for each into a single update region. Although there is no actual WM_PAINT message in the queue, the operating system constructs one WM_PAINT message with the single update region when an application uses the WinGetMsg function.

The operating system handles mouse and keyboard input messages differently from the way it handles other types of messages. The operating system receives all keyboard and mouse events, such as keystrokes and mouse movements, into the system message queue. The operating system converts these events into messages and posts them, one at a time, to the appropriate application message queue. The application retrieves the messages from its queue and dispatches them to the appropriate window, which processes the messages.

The operating system message queue usually is large enough to hold all input messages, even if the user types or moves the mouse very quickly. If the operating system message queue does run out of space, the system ignores the most recent keyboard input (usually by beeping to indicate the input is ignored) and collects mouse motions into a WM_MOUSEMOVE message.

Every message queue has a corresponding MQINFO data structure that specifies the identifiers of the process and thread that own the message queue and gives a count of the maximum number of messages the queue can receive. An application can retrieve the structure by using the WinQueryQueueInfo function.

A message queue also has a current status that indicates the types of messages currently in the queue. An application can retrieve the queue status by using the WinQueryQueueStatus function. An application also can use the WinPeekMsg function to examine the contents of a message queue. WinPeekMsg checks for a specific message or range of messages in the queue and gives the application the option of removing messages from the queue. An application can call the WinQueryQueueStatus function to determine the contents of the queue before calling the WinPeekMsg or WinGetMsg function to remove a message from the queue.

Message Handling

To handle and process messages, an application can use a message loop and the window procedure. These terms are explained in the following two sections.

Message Loops

Every application with a message queue is responsible for retrieving the messages from that queue. An application can do this by using a message loop, usually in the application's main function, that retrieves messages from the message queue and dispatches them to the appropriate windows. The message loop consists of two calls: one to the WinGetMsg function; the other to the WinDispatchMsg function. The message loop has the following form:

HAB hab;
QMSG qmsg;

while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
    WinDispatchMsg(hab, &qmsg);

An application starts the message loop after creating the message queue and at least one application window. Once started, the message loop continues to retrieve messages from the message queue and to dispatch (send) them to the appropriate windows. WinDispatchMsg sends each message to the window specified by the window handle in the message.

The following figure illustrates the typical routing of an input message through the operating system's and application's message loops.

            Mouse ───┐   ┌─── Keystrokes
                     |   |
                   ┌─┴───┴─┐
                   ├───────┤ System
                   ├───────┤ Event (time ordered)
                   ├───────┤ Queue
                   └───┬───┘
                       │
                       |
                  ┌────┴───┐
                  │ Input  │ Scancode
           ┌-─────┤ Router │ Translation
           │      └────────┘
           |
   ┌───────┴──────┐
   │ Message      │ Accelerator
   │ Preprocessor │ Key Translation
   └───────┬──────┘
 ┌─  ──  ─  ──  ──  ──  ──  ──  ──  ──  ─┐
       ┌───┴───┐
 │     ├───────┤ Appl    Priority         │
       ├───────┤ MssgQ   Ordered
 │     ├───────┤                          │
       └───┬───┘
 │         └────────┐                     │
                    
 │          ┌────── ┴─WinGetMsgQ          │
            |            WinDispatchMsg
 │          │               │             │
    App's   │               |
 │  Message │         Window Procedure    │
    Loop    │               │
 │          │               |             │
            └-───────────return;
 └─  ──  ──  ──  ──  ──  ──  ──  ──  ──  ─┘

Input Message Processing Loop Only one message loop is needed for a message queue, even if the queue contains messages for more than one window. Each queue message is a QMSG structure that contains the handle of the window to which the message belongs. WinDispatchMsg always dispatches the message to the proper window. WinGetMsg retrieves messages from the queue in first-in, first-out (FIFO) order, so the messages are dispatched to windows in the same order they are received.

If there are no messages in the queue, the operating system temporarily stops processing the WinGetMsg function until a message arrives. This means that processor time that, otherwise, would be spent waiting for a message can be given to the applications (or threads) that do have messages in their queues.

The message loop continues to retrieve and dispatch messages until WinGetMsg retrieves a WM_QUIT message. This message causes the function to return FALSE, terminating the loop. In most cases, terminating the message loop is the first step in terminating the application. An application can terminate its own loop by posting the WM_QUIT message in its own queue.

An application can modify its message loop in a variety of ways. For example, it can retrieve messages from the queue without dispatching them to a window. This is useful for applications that post messages without specifying a window. (These messages apply to the application rather than a specific window; they have NULL window handles.) Also, an application can direct the WinGetMsg function to search for specific messages, leaving other messages in the queue. This is useful for applications that temporarily need to bypass the usual FIFO order of the message queue.

Window Procedures

A window procedure is a function that receives and processes all input and requests for action sent to the windows. Every window class has a window procedure; every window created using that class uses that window procedure to respond to messages.

The system sends a message to the window procedure by passing the message data as arguments. The window procedure takes the appropriate action for the given message. Most window procedures check the message identifier, then use the information specified by the message parameters to carry out the request. When it has completed processing the message, the window procedure returns a message result. Each message has a particular set of possible return values. The window procedure must return the appropriate value for the processing it performed.

A window procedure cannot ignore a message. If it does not process a message, it must pass the message back to the operating system for default processing. The window procedure does this by calling the WinDefWindowProc function to carry out a default action and return the message result. Then, the window procedure must return this value as its own message result.

A window procedure commonly processes messages for several windows. It uses the window handle specified in the message to identify the appropriate window. Most window procedures process just a few types of messages and pass the others on to the operating system by calling WinDefWindowProc.

Posting and Sending Messages

Any application can post and send messages. Like the operating system, an application posts a message by copying it to a message queue. It sends a message by passing the message data as arguments to a window procedure. To post and send messages, an application uses the WinPostMsg and WinSendMsg functions.

An application posts a message to notify a specific window to perform a task. The WinPostMsg function creates a QMSG structure for the message and copies the message to the message queue corresponding to the given window. The application's message loop eventually retrieves the message and dispatches it to the appropriate window procedure. For example, one message commonly posted is WM_QUIT. This message terminates the application by terminating the message loop.

An application sends a message to cause a specific window procedure to carry out a task immediately. The WinSendMsg function passes 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 entry-field control as its child window can set the text of the control by sending a message to the child window. The control can notify the parent window of changes to the text (carried out by the user) by sending messages back to the parent window.

Occasionally, an application might need to send or post a message to all windows in the system. For example, if the application changes a system value, it must notify all windows about the change by sending a WM_SYSVALUECHANGED message. An application can send or post messages to any number of windows by using the WinBroadcastMsg function. The options in WinBroadcastMsg determine whether the message is sent or posted and specify the windows that will receive the message.

Any thread in the application can post a message to a message queue, even if the thread has no message queue of its own. However, only a thread that has a message queue can send a message. Sending a message between threads is relatively uncommon. For one reason, sending a message is costly in terms of system performance. If an application posts a message between threads, it is likely to be a semaphore message, which permits window procedures to manage a shared resource jointly.

An application can post a message without specifying a window. If the application supplies a NULL window handle when it calls the WinPostMsg function, the function posts the message to the queue associated with the current thread. 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.

A window procedure can determine whether it is processing a message sent by another thread by using the WinInSendMsg function. This is useful when message processing depends on the origin of the message.

A common programming error is to assume that the WinPostMsg function always succeeds. It fails when the message queue is full. An application should check the return value of the WinPostMsg function to see whether the message was posted. In general, if an application intends to post many messages to the queue, it should set the message queue to an appropriate size when it creates the queue. The default message-queue size is 10 messages.

Message Types

This section describes the three types of OS/2 messages:

  • System-defined
  • Application-defined
  • Semaphore

System-Defined Messages

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

Each system message has a unique message identifier and a corresponding symbolic constant. The symbolic constant, defined in the system header files, states the purpose of the message. For example, the WM_PAINT constant represents the paint message, which requests that a window paint its contents.

The symbolic constants also specify the message category. System-defined messages can belong to several categories; the prefix identifies the type of window that can interpret and process the messages. The following table lists the prefixes and their related message categories:

Prefix Message category
BKM_ Notebook control
BM_ Button control
CBM_ Combination-box control
CM_ Container control
EM_ Entry-field control
LM_ List-box control
MLM_ Multiple-line entry field control
MM_ Menu control
SBM_ Scroll-bar control
SLM_ Slider control
SM_ Static control
TBM_ Title-bar control
VM_ Value set control
WM_ General window

General window messages cover a wide range of information and requests, including:

  • Mouse and keyboard-input
  • Menu- and dialog-input
  • Window creation and management
  • Dynamic data exchange (DDE)

Application-Defined Messages

An application can create messages to use in its own windows. If an application does create messages, the window procedure that receives the messages must interpret them and provide the appropriate processing.

The operating system reserves the message-identifier values in the range 0x0000 through 0x0FFF (the value of WM_USER - 1) for system-defined messages.

Applications cannot use these values for their private messages.

In addition, the operating system uses certain message values higher than WM_USER. Applications should not use these message values. A partial listing of these messages is in the following figure:

From PMSTDDLG.H:

#define FDM_FILTER     WM_USER+40
#define FDM_VALIDATE   WM_USER+41
#define FDM_ERROR      WM_USER+42

#define FNTM_FACENAMECHANGED   WM_USER+50
#define FNTM_POINTSIZECHANGED  WM_USER+51
#define FNTM_STYLECHANGED    WM_USER+52
#define FNTM_COLORCHANGED    WM_USER+53
#define FNTM_UPDATEPREVIEW   WM_USER+54
#define FNTM_FILTERLIST      WM_USER+55

You should scan your header files to see if other messages have been defined with values higher than WM_USER.

Aside from the message values used by the operating system, values in the range 0x1000 (the value of WM_USER) through 0xBFFF are available for message identifiers, defined by an application, for use in that application.

Warning
It is very important that applications do not broadcast messages in the 0x1000 through 0xBFFF range due to the risk of misinterpretation by other applications.

Values in the range 0xC000 through 0xFFFF are reserved for message identifiers that an application defines and registers with the system atom table; these can be used in any application. Values above 0xFFFF (0x00010000 through 0xFFFFFFFF) are reserved for future use; applications must not use messages in this range.

Semaphore Messages

A semaphore message provides a way of signaling, through the message queue, the end of an event. An application uses a semaphore message the same way it uses system semaphore functions—to coordinate events by passing signals. A semaphore message often is used in conjunction with system semaphores.

There are four semaphore messages:

  • WM_SEM1
  • WM_SEM2
  • WM_SEM3
  • WM_SEM4.

An application posts one of these messages to signal the end of a given event. The window that is waiting for the given event receives the semaphore message when the message loop retrieves and dispatches the message.

Each semaphore message includes a bit flag that an application can use to uniquely identify the 32 possible semaphores for each semaphore message. The application passes the bit flag (with the appropriate bit set) as a message parameter with the message. The window procedure that receives the message then uses the bit flag to identify the semaphore.

To save space, the system does not store semaphore messages in the message queue. Instead, it sets a record in the queue, indicating that the semaphore message has been received, and then combines the bit flag for the message with the bit flags from previous messages. When the window procedure eventually receives the message, the bit flag specifies each semaphore message posted since the last message was retrieved.

Message Priorities

The WinGetMsg function retrieves messages from the message queue based on message priority. WinGetMsg retrieves messages with higher priority first. If it finds more than one message at a particular priority level, it retrieves the oldest message first. Messages have the following priorities:

Priority Message
1 WM_SEM1
2 Messages posted using WinPostMsg
3 Input messages from the keyboard or mouse
4 WM_SEM2
5 WM_PAINT
6 WM_SEM3
7 WM_TIMER
8 WM_SEM4

Message Filtering

An application can choose specific messages to retrieve from the message queue (and ignore other messages) by specifying a message filter with the WinGetMsg or WinPeekMsg functions. The message filter is a range of message identifiers (specified by a first and last identifier), a window handle, or both. The WinGetMsg and WinPeekMsg functions use the message filter to select the messages to retrieve from the queue. Message filtering is useful if an application needs to search ahead in the message queue for messages that have a lower priority or that arrived in the queue later than other less important messages.

Any application that filters messages must ensure that a message satisfying the message filter can be posted. For example, filtering for a WM_CHAR message in a window that does not receive keyboard input prevents the WinGetMsg function from returning. Some messages, such as WM_COMMAND, are generated from other messages; filtering for them also can prevent WinGetMsg from returning.

To filter for mouse, button, and DDE messages, an application can use the following constants:

  • WM_MOUSEFIRST and WM_MOUSELAST
  • WM_BUTTONCLICKFIRST and WM_BUTTONCLICKLAST
  • WM_DDE_FIRST and WM_DDE_LAST.

Using Messages

This section explains how to perform the following tasks:

  • Create a message queue and message loop
  • Examine the message queue
  • Post and send messages between windows
  • Broadcast a message to multiple windows
  • Use message macros

Creating a Message Queue and Message Loop

An application needs a message queue and message loop to process messages for its windows. An application creates a message queue by using the WinCreateMsgQueue function. An application creates a message loop by using the WinGetMsg and WinDispatchMsg functions. The application must create and show at least one window after creating the queue but before starting the message loop. The following code fragment shows how to create a message queue and message loop:

MRESULT EXPENTRY ClientWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2);

HAB hab;

int main(VOID)
{
    HMQ hmq;
    QMSG qmsg;
    HWND hwndFrame, hwndClient;
    ULONG flFrameFlags = FCF_TITLEBAR    | FCF_SYSMENU |
                           FCF_SIZEBORDER    | FCF_MINMAX  |
                           FCF_SHELLPOSITION | FCF_TASKLIST;

                                         /* Initialize the application for
                                            Presentation Manager interface.         */

    hab = WinInitialize(0);

                                         /* Create the application
                                            message queue.                   */
    hmq = WinCreateMsgQueue(hab, 0);

                                         /* Register the window class for your
                                            client window.                   */
    WinRegisterClass(hab,                 /* Anchor block handle             */
                     "MyClientClass",      /* Class name                      */
                     (PFNWP) ClientWndProc,/* Window procedure                */
                     CS_SIZEREDRAW,        /* Class style                     */
                     0);                   /* Extra bytes to reserve          */

                                         /* Create a main window.          */
    hwndFrame = WinCreateStdWindow(
                    HWND_DESKTOP,         /* Parent window handle            */
                    WS_VISIBLE,           /* Style of frame window           */
                    &flFrameFlags,        /* Frame controls                  */
                    "MyClientClass",      /* Window class for client         */
                    (PSZ) NULL,           /* No title-bar text               */
                    WS_VISIBLE,           /* Style of client window          */
                    (HMODULE) NULL,       /* Module handle for resources     */
                    0,                    /* No resource identifier          */
                    &hwndClient);         /* Pointer to client handle        */

                                         /* Start the message loop.        */
    while (WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0))
        WinDispatchMsg(hab, &qmsg);

                                         /*. Destroy the main window.       */
    WinDestroyWindow(hwndFrame);

                                         /* Destroy the message queue.     */
    WinDestroyMsgQueue(hmq);

                                         /* Terminate the application.     */
    WinTerminate(hab);
}

Both the WinGetMsg and WinDispatchMsg functions take a pointer to a QMSG structure as a parameter. If a message is available, WinGetMsg copies it to the QMSG structure; WinDispatchMsg then uses the data in the structure as arguments for the window procedure.

Occasionally, an application might need to process a message before dispatching it. For example, if a message is posted but the destination window is not specified (that is, the message contains a NULL window handle), the application must process the message to determine which window should receive the message. Then the WinDispatchMsg function can forward the message to the proper window. The following code fragment shows how the message loop can process messages that have NULL window handles

HAB hab;
QMSG qmsg;

while (WinGetMsg (hab, &qmsg, (HWND) NULL, 0, 0)) {
    if (qmsg.hwnd == NULL) {
        .
        . /* Process the message. */
        .
    }
    else
        WinDispatchMsg (hab, &qmsg);
    }

Examining the Message Queue

An application can examine the contents of the message queue by using the WinPeekMsg or WinQueryQueueStatus function. It is useful to examine the queue if the application starts a lengthy operation that additional user input might affect, or if the application needs to look ahead in the queue to anticipate a response to user input.

An application can use WinPeekMsg to check for specific messages in the message queue. This function is useful for extracting messages for a specific window from the queue. It returns immediately if there is no message in the queue. An application can use WinPeekMsg in a loop without requiring the loop to wait for a message to arrive. The following code fragment checks the queue for WM_ CHAR messages:

HAB hab;
QMSG qmsg;

if (WinPeekMsg(hab, &qmsg, (HWND) NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE)){
            .
            . /* Process the message. */
            .
}

An application also can use the WinQueryQueueStatus function to check for messages in the queue. This function is very fast and returns information about the kinds of messages available in the queue and which messages have been posted recently. Most applications use this function in message loops that need to be as fast as possible.

Posting a Message to a Window

An application can use the WinPostMsg function to post a message to a window. The message goes to the window's message queue. The following code fragment posts the WM_QUIT message.

HWND hwnd;

if (!WinPostMsg(hwnd, WM_QUIT, NULL, NULL)){

    /* Message was not posted. */
}

The WinPostMsg function returns FALSE if the queue is full, and the message cannot be posted.

Sending a Message to a Window

An application can use the WinSendMsg function to send a message directly to a window. An application uses this function to send messages to child windows. For example, the following code fragment sends an LM_INSERTITEM message to direct a list-box control to add an item to the end of its list:

HWND hwndListBox;
static CHAR szWeekday[] = "Tuesday";

WinSendMsg(hwndListBox,
           LM_INSERTITEM,
           (MPARAM)LIT_END,
           MPFROMP(szWeekday));

WinSendMsg calls the window's window procedure and waits for it to handle the message and return a result. An application can send a message to any window in the system, as long as the application has the handle of the target window. The message queue does not store the message; however, the thread making the call must have a message queue.

Broadcasting a Message

An application can send a message to multiple windows by using the WinBroadcastMsg function. Often this function is used to broadcast the WM_SYSVALUECHANGED message after an application changes a system value. The following code fragment shows how to broadcast this message to all frame windows in all applications:

HWND hwnd;

WinBroadcastMsg(
    hwnd,                                     /* Window handle             */
    WM_SYSVALUECHANGED,                       /* Message identifier        */
    NULL,                                     /* No message parameters     */
    NULL,
    BMSG_FRAMEONLY | BMSG_POSTQUEUE);         /* All frame windows         */

An application can broadcast messages to all windows, just frame windows, or just the windows in the application.

Using Message Macros

The system header files define several macros that help create and interpret message parameters.

One set of macros helps you construct message parameters. These macros are useful for sending and posting messages. For example, the following code fragment uses the MPFROMSHORT macro to convert a 16-bit integer into the 32-bit message parameter:

HWND hwndButton;

WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), NULL);

A second set of macros helps you extract values from a message parameter. These macros are useful for handling messages in a window procedure. The following code fragment determines whether the window receiving the WM_FOCUSCHANGE message is gaining or losing the keyboard focus. The fragment uses the SHORT1FROMMP macro to extract the focus-change flag, the SHORT2FROMMP macro to extract the focus flag, and the HWNDFROMMP macro to extract the window handle.

USHORT fsFocusChange;
MPARAM mp1, mp2;
HWND hwndGainFocus;


case WM_FOCUSCHANGE:
    fsFocusChange = SHORT2FROMMP(mp2);    /* Gets focus-change flags  */
    if (SHORT1FROMMP(mp2))                /* Gaining or losing focus? */
        hwndGainFocus = HWNDFROMMP(mp1);

A third set of macros helps you construct a message result. These macros are useful for returning message results in a window procedure, as the following code fragment illustrates:

return (MRFROM2SHORT(1, 2));