C-C++ Code Example: Returning Response Messages

 

Applies To: Windows 10, Windows 7, Windows 8, Windows 8.1, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server Technical Preview, Windows Vista

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.

Code Examples

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;  
}