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
Define the required constants and variables.
Define an MQMSGPROPS structure.
Specify the response queue format name, its length, and the message identifier as message properties to be retrieved.
Call MQOpenQueue to open the destination queue for peeking at messages.
Call MQReceiveMessage to read the first message in the destination queue.
If a response message is requested, send a response message to the response queue specified.
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.
Send the response message and close the response queue.
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;
}