C/C++ Code Example: Returning Response Messages

C/C++ Code Example: Returning Response Messages

 

The following example provides an application defined function that peeks at the PROPID_M_RESP_FORMAT_NAME property of a message and returns a response message if a response queue was specified.

For information on responding to sent messages, see Response Messages.

This example uses the PROPID_M_RESP_FORMAT_NAME property (introduced in MSMQ 3.0) to determine if the sending application requested response messages. This property can be set to any of the following format name types.

  • A single public, private, or direct format name. These format names are used to specify a single response queue.

    For information about these format names, see Public Format Names, Private Format Names, and Direct Format Names.

  • A multiple-element format name. This format name is used to specify multiple response queues.

    For information about multiple-element format names, see Multiple-Element Format Names.

  • A distribution list format name. This format name is used to specify multiple response queues.

    For information about distribution list format names, see Distribution List Format Names.

  • A multicast address format name. This format name is used to specify multiple response queues.

    For information about multicast address format names, see Multicast Address Format Names.

This example also demonstrates how to allocate the exact amount of memory needed for a format name buffer.

To return a response message

  1. Define the required constants and variables.

  2. Define an MQMSGPROPS structure.

  3. Specify the response queue format name, its length, and the message identifier as message properties to be retrieved.

  4. Call MQOpenQueue to open the destination queue for peeking at messages.

  5. Call MQReceiveMessage to read the first message in the destination queue.

  6. If a response message is requested, send a response message to the response queue specified.

  7. Set the properties of the response message. This example returns the destination format name and the message identifier of the original message in the response message.

  8. Send the response message and close the response queue.

  9. Free the memory allocated for the format name buffer.

The following code example requires MSMQ 3.0.

HRESULT ReturnResp(
                   LPCWSTR wszDestQueueFormatName
                   )
{

  // Validate the input string.
  if (wszDestQueueFormatName == NULL)
  {
    return MQ_ERROR_INVALID_PARAMETER;
  }


  // Define the required constants and variables.
  const int NUMBEROFPROPERTIES = 5;       // Total number of properties
  DWORD cPropId = 0;                      // Property counter
  HRESULT hr = MQ_OK;                     // Return code
  HANDLE hQueue = NULL;                   // Queue handle
  ULONG ulBufferLength = 1;               // Initial buffer length (number of wide characters)


  // Define an MQMSGPROPS structure.
  MQMSGPROPS msgprops;
  MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];
  MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES]; 
  HRESULT aMsgStatus[NUMBEROFPROPERTIES];


  // Specify the response queue format name and its length
  // as message properties to be retrieved.
  WCHAR * wszRespQueueFormatName = NULL;
  wszRespQueueFormatName = (WCHAR*)malloc(ulBufferLength*sizeof(WCHAR));
  if (wszRespQueueFormatName == NULL)
  {
    return MQ_ERROR_INSUFFICIENT_RESOURCES;
  }
  memset(wszRespQueueFormatName, 0, ulBufferLength*sizeof(WCHAR));

  aMsgPropId[cPropId] = PROPID_M_RESP_FORMAT_NAME_LEN;    // Property ID
  aMsgPropVar[cPropId].vt = VT_UI4;                       // Type indicator
  aMsgPropVar[cPropId].ulVal = ulBufferLength;            // Format name buffer size
  cPropId++;

  aMsgPropId[cPropId] = PROPID_M_RESP_FORMAT_NAME;        // Property ID
  aMsgPropVar[cPropId].vt = VT_LPWSTR;                    // Type indicator
  aMsgPropVar[cPropId].pwszVal = wszRespQueueFormatName;  // Format name buffer
  cPropId++;


  // Specify the destination format name and its length
  // as message properties to be retrieved.
  WCHAR * wszDestFormatName = NULL;
  wszDestFormatName = (WCHAR*)malloc(ulBufferLength*sizeof(WCHAR)); 
  if (wszDestFormatName == NULL)
  {
    return MQ_ERROR_INSUFFICIENT_RESOURCES;
  }
  memset(wszDestFormatName, 0, ulBufferLength*sizeof(WCHAR));
  aMsgPropId[cPropId] = PROPID_M_DEST_FORMAT_NAME_LEN;    // Property ID
  aMsgPropVar[cPropId].vt = VT_UI4;                       // Type indicator
  aMsgPropVar[cPropId].ulVal = ulBufferLength;            // Format name buffer size
  cPropId++;

  aMsgPropId[cPropId] = PROPID_M_DEST_FORMAT_NAME;        // Property ID
  aMsgPropVar[cPropId].vt = VT_LPWSTR;                    // Type indicator
  aMsgPropVar[cPropId].pwszVal = wszDestFormatName;       // Destination format name buffer
  cPropId++;

  // Specify PROPID_M_MSGID as a message property to be retrieved.
  UCHAR rgucMsgID[PROPID_M_MSGID_SIZE];
  aMsgPropId[cPropId] = PROPID_M_MSGID;                   // Property ID
  aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1 ;          // Type indicator
  aMsgPropVar[cPropId].caub.pElems = rgucMsgID;
  aMsgPropVar[cPropId].caub.cElems = PROPID_M_MSGID_SIZE;
  cPropId++;


  // Initialize the MQMSGPROPS structure.
  msgprops.cProp = cPropId;                               // Number of message properties
  msgprops.aPropID = aMsgPropId;                          // IDs of message properties
  msgprops.aPropVar = aMsgPropVar;                        // Values of message properties
  msgprops.aStatus  = aMsgStatus;                         // Error reports


  // Open the destination queue to read the first message.
  hr = MQOpenQueue(
                   wszDestQueueFormatName,                // Format name of the queue
                   MQ_RECEIVE_ACCESS,                     // Access mode
                   MQ_DENY_NONE,                          // Share mode
                   &hQueue                                // OUT: Queue handle
                   );

  if (FAILED(hr))
  {
    free(wszRespQueueFormatName);
    free(wszDestFormatName);
    return hr;
  }

  // Peek at the first messages in the destination queue.
  do
  {
    hr = MQReceiveMessage(
                          hQueue,                        // Queue handle
                          1000,                          // Maximum time (msec) to receive a message
                          MQ_ACTION_PEEK_CURRENT,        // Only peeking
                          &msgprops,                     // Message property structure
                          NULL,                          // No OVERLAPPED structure
                          NULL,                          // No callback function
                          NULL,                          // Cursor handle
                          MQ_NO_TRANSACTION              // Not in a transaction
                         );
    if (hr == MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL)
    {


      // Reallocate the response queue format name and the destination 
      // format name buffers.
      wszRespQueueFormatName = (WCHAR*)realloc(wszRespQueueFormatName, aMsgPropVar[0].ulVal*sizeof(WCHAR));
      if (wszRespQueueFormatName == NULL)
      {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
      }
      memset(wszRespQueueFormatName, 0, aMsgPropVar[0].ulVal*sizeof(WCHAR));
      msgprops.aPropVar[1].pwszVal = wszRespQueueFormatName;
      wszDestFormatName = (WCHAR*)realloc(wszDestFormatName, aMsgPropVar[2].ulVal*sizeof(WCHAR));
      if (wszDestFormatName == NULL)
      {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
      }
      memset(wszDestFormatName, 0, aMsgPropVar[2].ulVal*sizeof(WCHAR));
      msgprops.aPropVar[3].pwszVal = wszDestFormatName;
    }
  }while (hr == MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL);

  if (FAILED(hr))
  {
    free(wszRespQueueFormatName);
    free(wszDestFormatName);
    hr = MQCloseQueue(hQueue);
    return hr;
  }


  // Close the destination queue.
  hr = MQCloseQueue(hQueue);
  if (FAILED(hr))
  {
    free(wszRespQueueFormatName);
    free(wszDestFormatName);
    return hr;
  }

  if (aMsgPropVar[0].ulVal)                              // Response message requested
  {


    // Return the destination format name of the original message
    // as the destination for returning response messages.
    cPropId = 0;
    aMsgPropId[cPropId] = PROPID_M_RESP_FORMAT_NAME;
    aMsgPropVar[cPropId].vt = VT_LPWSTR;
    aMsgPropVar[cPropId].pwszVal = wszDestFormatName;
    cPropId++;


    // Return the message identifier of the original message
    // as the correlation identifier.
    aMsgPropId[cPropId] = PROPID_M_CORRELATIONID;       // Property ID
    aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1 ;      // Type indicator
    aMsgPropVar[cPropId].caub.pElems = rgucMsgID;
    aMsgPropVar[cPropId].caub.cElems = PROPID_M_CORRELATIONID_SIZE;
    cPropId++;


    // Initialize the MQMSGPROPS structure.
    msgprops.cProp = cPropId;
    msgprops.aPropID = aMsgPropId;
    msgprops.aPropVar = aMsgPropVar;
    msgprops.aStatus = aMsgStatus;


    // Call MQOpenQueue to open the response queue.
    hr = MQOpenQueue(wszRespQueueFormatName,
                     MQ_SEND_ACCESS,
                     MQ_DENY_NONE,
                     &hQueue);
    if (FAILED(hr))
    {
      free(wszRespQueueFormatName);
      free(wszDestFormatName);
      return hr;
    }


    // Call MQSendMessage to send the response message.
    hr = MQSendMessage(
                       hQueue,
                       &msgprops,
                       MQ_NO_TRANSACTION
                       );
    if (FAILED(hr))
    {
      free(wszRespQueueFormatName);
      free(wszDestFormatName);
      MQCloseQueue(hQueue);
      return hr;
    }


    // Call MQCloseQueue to close the response queue.
    hr = MQCloseQueue(hQueue);
  }

  free(wszRespQueueFormatName);
  free(wszDestFormatName);
  return hr;
}

Community Additions

ADD
Show:
© 2016 Microsoft