Reading Messages Asynchronously

Applications can use a callback function, a Windows Event mechanism, or a Microsoft® Windows NT® completion port to read messages asynchronously. When reading messages asynchronously, the application is notified if a message is available or if a timeout has occurred.

For information, see MQReceiveMessage.

Note  In the following two examples, the first uses a callback function to retrieve the messages, and the second uses a Windows Event mechanism. Both examples read the first message in the queue.

    To read a message asynchronously using a callback function
  1. Write the callback function.
    void APIENTRY ReceiveCallbackRoutine(
        HRESULT hrStatus,
        QUEUEHANDLE hSource,
        DWORD dwTimeout,
        DWORD dwAction,
        MQMSGPROPS* pMessageProps,
        LPOVERLAPPED lpOverlapped,
        HANDLE hCursor
    )
     {
       // Process message.
     }
    
  2. Open the queue with receive or peek access. If the queue is opened with receive access, the application can still peek at the messages in the queue.
    hr = MQOpenQueue(
        szwFormatNameBuffer,    // Format name of the queue.
        MQ_RECEIVE_ACCESS,      // Access rights to the queue.
        0,                      // No receive Exclusive.
        &hQueue                 // OUT: handle to the opened queue.
                   );
     
  3. Specify the message properties to be retrieved, retrieving only those properties that are needed. For example, if you only need to look at the body of the message, only specify PROPID_M_BODY.
    // Set the PROPID_M_BODY property.
    paPropId[dwPropIdCount] = PROPID_M_BODY;                //PropId
    paVariant[dwPropIdCount].vt = VT_VECTOR|VT_UI1;         //Type
    paVariant[dwPropIdCount].caub.cElems = MSG_BODY_LEN ;   //Value
    paVariant[dwPropIdCount].caub.pElems = new unsigned char[ MSG_BODY_LEN];
     
     dwPropIdCount++;
     
  4. Set the MQMSGPROPS structure.
    // Set the MQMSGPROPS structure.
    MsgProps.cProp = PropIdCount;       //Number of properties.
    MsgProps.aPropID = aPropId;         //Ids of properties.
    MsgProps.aPropVar = aVariant;       //Values of properties.
    MsgProps.aStatus  = NULL;           //No Error report.
     
  5. Read message from the queue, using ReceiveCallbackRoutine as the callback function.
    hr = MQReceiveMessage(
        hQueue,                     // handle to the Queue.
        5 * 60 * 1000,              // Max time (msec) to wait.
        MQ_ACTION_RECEIVE,          // Action.
        pMsgProps,                  // Properties to retrieve.
        NULL,                       // No overlapped structure.
        ReceiveCallbackRoutine,     // Callback function.
        NULL,                       // No Cursor.
        NULL                        // No transaction
                  );
     

Callback Function Example

The following example specifies a callback function, opens a queue with receive access, specifies the body of the message as the only message property to retrieve, and reads the first message of the queue using the callback function.

//////////////////////////////
// Receive callback function.
/////////////////////////////
 
void APIENTRY ReceiveCallbackRoutine(
   HRESULT hr,
   QUEUEHANDLE hSource,
   DWORD dwTimeout,
   DWORD dwAction,
   MQMSGPROPS* pMessageProps,
   LPOVERLAPPED lpOverlapped,
   HANDLE hCursor
  )
 {
  if (FAILED(hr))
   {
    // Error handler for Callback routine.
   }
  else
  {
   // Process message.
  }
 }

//////////////
// Open Queue
//////////////
 
HRESULT hr;
QUEUEHANDLE hQueue;
 
hr = MQOpenQueue(
     szwFormatNameBuffer,    // Format Name of the queue to be opened.
     MQ_RECEIVE_ACCESS,      // Access rights to the Queue.
     0,                      // No receive Exclusive.
     &hQueue                 // OUT: handle to the opened Queue.
);
 
if (FAILED(hr))
{
 // Error handler for MQOpenQueue.
}
 
 
MQMSGPROPS * pMsgProps;
MQPROPVARIANT *paVariant;
MSGPROPID * paPropId;
DWORD dwPropIdCount = 0;
 
//
//  The output parameters to an asynchronous call to MQReceiveMessage 
//  should be kept intact until the operation completes, you should 
//  not free or reuse them until the operation is complete.
//
pMsgProps = new MQMSGPROPS;
paVariant = new MQPROPVARIANT[ 10];
paPropId = new MSGPROPID[ 10];
 
    
//////////////////////////////////////////////////
// Prepare the message properties to be retrieved.
/////////////////////////////////////////////////
 
 
// Set the PROPID_M_BODY property.
paPropId[dwPropIdCount] = PROPID_M_BODY;                //PropId
paVariant[dwPropIdCount].vt = VT_VECTOR|VT_UI1;         //Type
paVariant[dwPropIdCount].caub.cElems = MSG_BODY_LEN ;    //Value
paVariant[dwPropIdCount].caub.pElems = new unsigned char[ MSG_BODY_LEN];
 
 dwPropIdCount++;
 
////////////////////////////////
// Set the MQMSGPROPS structure
///////////////////////////////
pMsgProps->cProp = dwPropIdCount;     //Number of properties.
pMsgProps->aPropID = paPropId;        //Ids of properties.
pMsgProps->aPropVar = paVariant;      //Values of properties.
pMsgProps->aStatus  = NULL;           //No Error report.
 
 
///////////////////////////////////////////////
//  Receive the message using callback function
//  ReceiveCallbackRoutine.
///////////////////////////////////////////////
 
hr = MQReceiveMessage(
    hQueue,                     // handle to the Queue.
    5 * 60 * 1000,              // Max time (msec) to wait.
    MQ_ACTION_RECEIVE,          // Action.
    pMsgProps,                  // properties to retrieve.
    NULL,                       // No overlapped structure.
    ReceiveCallbackRoutine,     // Callback function.
    NULL,                       // No Cursor.
    NULL                        // No transaction
              );
 
if (FAILED(hr))
   {
     //  Error handler for MQReceiveMessage.
    }
 
    To read a message asynchronously using a Windows Event mechanism
  1. Open the queue with receive or peek access. The access mode used to open the queue does not determine how the messages are read from the queue. For example, if the queue is opened with receive access, the application can still peek at the messages in the queue.
    hr = MQOpenQueue(
        szwFormatNameBuffer,    // Format name of the queue.
        MQ_RECEIVE_ACCESS,      // Access rights to the Queue.
        0,                      // No receive Exclusive.
        &hQueue                 // OUT: handle to the opened Queue.
                   );
     
  2. Specify the message properties to be retrieved. If you only need to look at the body of the message, only specify PROPID_M_BODY.
    // Set the PROPID_M_BODY property.
    paPropId[dwPropIdCount] = PROPID_M_BODY;                //PropId
    paVariant[dwPropIdCount].vt = VT_VECTOR|VT_UI1;         //Type
    paVariant[dwPropIdCount].caub.cElems = MSG_BODY_LEN ;   //Value
    paVariant[dwPropIdCount].caub.pElems = new unsigned char[ MSG_BODY_LEN];
     
     dwPropIdCount++;
     
  3. Set the MQMSGPROPS structure.
    // Set the MQMSGPROPS structure.
    MsgProps.cProp = PropIdCount;       //Number of properties.
    MsgProps.aPropID = aPropId;         //Ids of properties.
    MsgProps.aPropVar = aVariant;       //Values of properties.
    MsgProps.aStatus  = NULL;           //No Error report.
     
  4. Create the Event object using overlapped structure.
    OVERLAPPED *pov = new OVERLAPPED ;
    pov->hEvent = CreateEvent(0, TRUE, TRUE, 0);
     
  5. Read the message from the queue.
    hr = MQReceiveMessage(
        hQueue,                     // handle to the Queue.
        5 * 60 * 1000,              // Max time (msec) to wait.
        MQ_ACTION_RECEIVE,          // Action.
        pMsgProps,                  // Properties to retrieve.
        pov,                        // Overlapped structure.
        NULL,                       // Callback function.
        NULL,                       // No Cursor.
        NULL                        // No transaction
                  );
     
  6. Write Windows Event handler (typically a separate thread) and close the handle to the overlapped structure.
    if(hr == MQ_INFORMATION_OPERATION_PENDING)
    {
        WaitForSingleObject(pov->hEvent, INFINITE);
    //
    // Parse recieved results
    //
    }
     
    CloseHandle(pov->hEvent);
     

Windows Event Mechanism Example

The following example opens a queue with receive access, specifies the body of the message as the only message property to retrieve, and uses a Windows Event mechanism to read the first message of the queue.

//////////////
// Open Queue
//////////////
 
HRESULT hr;
QUEUEHANDLE hQueue;
 
hr = MQOpenQueue(
     szwFormatNameBuffer,    // Format Name of the queue to be opened.
     MQ_RECEIVE_ACCESS,      // Access rights to the Queue.
     0,                      // No receive Exclusive.
     &hQueue                 // OUT: handle to the opened Queue.
                );
 
if (FAILED(hr))
{
 // Error handler for MQOpenQueue.
}
 

MQMSGPROPS * pMsgProps;
MQPROPVARIANT *paVariant;
MSGPROPID * paPropId;
DWORD dwPropIdCount = 0;
 
//
//  The output parameters of an asynchronous call to MQReceiveMessage 
//  should be kept intact until the operation completes, you cannot
//  free them or reuse them.
//
pMsgProps = new MQMSGPROPS;
paVariant = new MQPROPVARIANT[ 10];
paPropId = new MSGPROPID[ 10];
 
 
//////////////////////////////////////////////////
// Prepare the message properties to be retrieved.
/////////////////////////////////////////////////
 
 
// Set the PROPID_M_BODY property.
paPropId[dwPropIdCount] = PROPID_M_BODY;                //PropId
paVariant[dwPropIdCount].vt = VT_VECTOR|VT_UI1;         //Type
paVariant[dwPropIdCount].caub.cElems = MSG_BODY_LEN ;    //Value
paVariant[dwPropIdCount].caub.pElems = new unsigned char[ MSG_BODY_LEN];
 
 dwPropIdCount++;
 
 
////////////////////////////////
// Set the MQMSGPROPS structure
///////////////////////////////
 
pMsgProps->cProp = dwPropIdCount;     //Number of properties.
pMsgProps->aPropID = paPropId;        //Ids of properties.
pMsgProps->aPropVar = paVariant;      //Values of properties.
pMsgProps->aStatus  = NULL;           //No Error report.
 
 
/////////////////////////////////////////
//  Create Event object using overlapped
//  structure.
/////////////////////////////////////////
 
OVERLAPPED *pov = new OVERLAPPED ;
pov->hEvent = CreateEvent(0, TRUE, TRUE, 0);
 
 
/////////////////////////////////////////
//  Retrieve the message using overlapped 
//  structure.
/////////////////////////////////////////
 
hr = MQReceiveMessage(
    hQueue,                     // handle to the Queue.
    5 * 60 * 1000,              // Max time (msec) to wait.
    MQ_ACTION_RECEIVE,          // Action.
    pMsgProps,                  // properties to retrieve.
    pov,                        // Overlapped structure.
    NULL,                       // No callback function.
    NULL,                       // No Cursor.
    NULL                        // No transaction
              );
 
if (FAILED(hr))
    {
        //  Error handler for MQReceiveMessage.
    }
 
 
//////////////////////////////
// Windows Event handler.
//////////////////////////////
 
if (hr == MQ_INFORMATION_OPERATION_PENDING)
    {
        WaitForSingleObject(pov->hEvent, INFINITE);
    //
    // Parse recieved results
    //
    }
 
CloseHandle(pov->hEvent);
delete paVariant;  //Free resources.
delete paPropId;