Reading Messages Using a Cursor

Cursors allow you to read a message that is not at the front of the queue. The cursor always maintains its position relative to the message to which it points.

The two functions used to manage the cursor are MQCreateCursor and MQCloseCursor. MQCreateCursor returns a cursor handle that is used in MQReceiveMessage, and MQCloseCursor releases the cursor's resources.

    To find a specific message
  1. Call MQOpenQueue to open the queue with either receive access or peek access. Opening the queue for receive access allows you to peek at the messages as well as receive them.
    hr = MQOpenQueue(
        wszFormatNameBuffer,
        MQ_RECEIVE_ACCESS,
        0,
        &hQueue
        );
     
  2. Call MQCreateCursor to create the cursor.
    hr = MQCreateCursor(
       hQueue,              //Queue handle
      &hCursor 
      );
     
  3. Specify the message properties you want to retrieve.
    MQMSGPROPS MsgProps;
    MQPROPVARIANT aVariant[10];
    MSGPROPID aPropId[10];
    DWORD PropIdCount = 0;
        
    #define MSG_BODY_LEN 500
    unsigned char ucMsgBody[MSG_BODY_LEN];
    DWORD dwAppspecificIndex;
        
    // Set the PROPID_M_BODY property.
    aPropId[PropIdCount] = PROPID_M_BODY;               //PropId
    aVariant[PropIdCount].vt = VT_VECTOR|VT_UI1;        //Type
    aVariant[PropIdCount].caub.cElems = MSG_BODY_LEN;   //Value
    aVariant[PropIdCount].caub.pElems = ucMsgBody;
    PropIdCount++;
        
    //Set the PROPID_M_APPSPECIFIC property.
    aPropId[PropIdCount] = PROPID_M_APPSPECIFIC;       //PropId
    aVariant[PropIdCount].vt = VT_UI4;                 //Type
    dwAppspecificIndex = PropIdCount;
    PropIdCount++;
        
    //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. Call MQReceiveMessage until the message is found.
    DWORD dwAction = MQ_ACTION_PEEK_CURRENT;  //Peek at first msg.
    do 
     {
     hr = MQReceiveMessage(
        hQueue,             // handle to the Queue.
        5 * 60 * 1000,      // Max time (msec) to wait for msg.
        dwAction,           // Action.
        &MsgProps,          // properties to retrieve.
        NULL,               // No overlapped structure.
        NULL,               // No callback function.
        hCursor,            // Cursor handle.
        NULL                // No transaction.
     );
     if (FAILED(hr))
     {
     //  Handle failure
     }
        
     dwAction = MQ_ACTION_PEEK_NEXT;  //Peek at next message.
    } while (MsgProps.aPropVar[dwAppspecificIndex].ulVal != 1);
        
  5. Call MQCloseCursor to release the cursor handle's resources.
    hr = MQCloseCursor(
      hCursor        //Cursor handle
      );
        

Example

The following example locates a message whose application-specific property is equal to 1. It uses MQ_PEEK_CURRENT to look at the first message in the queue and uses MQ_PEEK_NEXT to look at the next message in the queue. MQ_PEEK_NEXT looks at the next message, and then moves the cursor.

HRESULT hr;
QUEUEHANDLE hQueue;


//////////////////////////////////
// Open queue with receive access.
/////////////////////////////////
hr = MQOpenQueue(
    wszFormatNameBuffer,
    MQ_RECEIVE_ACCESS,
    0,
    &hQueue
    );
if (FAILED(hr))
{
//
//  Handle failure
//
}


//////////////////////////////////
// Create the cursor.
/////////////////////////////////
HANDLE hCursor;

hr = MQCreateCursor(
   hQueue,              //Queue handle
  &hCursor 
  );
if (FAILED(hr))
{
//
//  Handle failure
//
}


////////////////////////////////////////
// Specify the message properties you 
// want to retrieve.
///////////////////////////////////////

MQMSGPROPS MsgProps;
MQPROPVARIANT aVariant[10];
MSGPROPID aPropId[10];
DWORD PropIdCount = 0;

#define MSG_BODY_LEN 500
unsigned char ucMsgBody[MSG_BODY_LEN];
DWORD dwAppspecificIndex;

// Set the PROPID_M_BODY property.
aPropId[PropIdCount] = PROPID_M_BODY;               //PropId
aVariant[PropIdCount].vt = VT_VECTOR|VT_UI1;        //Type
aVariant[PropIdCount].caub.cElems = MSG_BODY_LEN;   //Value
aVariant[PropIdCount].caub.pElems = ucMsgBody;
PropIdCount++;

//Set the PROPID_M_APPSPECIFIC property.
aPropId[PropIdCount] = PROPID_M_APPSPECIFIC;       //PropId
aVariant[PropIdCount].vt = VT_UI4;                 //Type
dwAppspecificIndex = PropIdCount;                  //Value
PropIdCount++;

//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.


///////////////////////////////////
// Peek until you find the message 
// where APPSPECIFIC = 1.
///////////////////////////////////

DWORD dwAction = MQ_ACTION_PEEK_CURRENT;  //Peek at first msg.
do 
 {
 hr = MQReceiveMessage(
    hQueue,             // handle to the Queue.
    5 * 60 * 1000,      // Max time (msec) to wait for msg.
    dwAction,           // Action.
    &MsgProps,          // properties to retrieve.
    NULL,               // No overlapped structure.
    NULL,               // No callback function.
    hCursor,            // Cursor handle.
    NULL                // No transaction.
 );
 if (FAILED(hr))
 {
 //  Handle failure
 break;
 }

 dwAction = MQ_ACTION_PEEK_NEXT;  //Peek at next message.
} while (MsgProps.aPropVar[dwAppspecificIndex].ulVal != 1);

hr = MQCloseCursor(
     hCursor
    );