Из документации для MQSendMessage:
Информация об ошибках, возникающих после помещения сообщения в исходящую очередь, предоставляется сообщениями подтверждения.
API ожидает, что вы запросите подтверждающее сообщение, получите его позже и сопоставите его с оригиналом, используя свое свойство PROPID_M_CORRELATIONID
. На этой странице приведен пример:
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms700122%28v%3dvs.85%29
РЕДАКТИРОВАТЬ: По ссылке:
HRESULT MatchAck(
LPCWSTR wszAdminQueueName,
LPCWSTR wszComputerName,
UCHAR * rgucMsgID //Array of bytes
)
{
// Validate the input strings.
if (wszAdminQueueName == NULL || wszComputerName == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Define the required constants and variables.
const int NUMBEROFPROPERTIES = 3; // Number of properties
DWORD cPropId = 0; // Property counter
WCHAR wszLabelBuffer[MQ_MAX_MSG_LABEL_LEN]; // Message label buffer
// Define an MQMSGPROPS structure.
MQMSGPROPS msgprops;
MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];
PROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];
HRESULT aMsgStatus[NUMBEROFPROPERTIES];
HANDLE hQueue = NULL; // Queue handle
HANDLE hCursor = NULL; // Cursor handle
HRESULT hr = MQ_OK; // Return code
int i = 0; // Array index
// Create a buffer of unsigned characters of length
// PROPID_M_CORRELATIONID_SIZE, which is equal to 20, and specify
// PROPID_M_CORRELATIONID as a message property to be retrieved.
UCHAR rgucCorrelationID[PROPID_M_CORRELATIONID_SIZE];
aMsgPropId[cPropId] = PROPID_M_CORRELATIONID; // Property ID
aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1 ; // Type indicator
aMsgPropVar[cPropId].caub.pElems = rgucCorrelationID;
aMsgPropVar[cPropId].caub.cElems = PROPID_M_CORRELATIONID_SIZE;
cPropId++;
// Specify the message label and its length as message properties to be retrieved.
aMsgPropId[cPropId] = PROPID_M_LABEL_LEN; // Property ID
aMsgPropVar[cPropId].vt = VT_UI4; // Type indicator
aMsgPropVar[cPropId].ulVal = MQ_MAX_MSG_LABEL_LEN; // Label buffer size
cPropId++;
aMsgPropId[cPropId] = PROPID_M_LABEL; // Property ID
aMsgPropVar[cPropId].vt = VT_LPWSTR; // Type indicator
aMsgPropVar[cPropId].pwszVal = wszLabelBuffer; // Label buffer
cPropId++;
// Initialize the MQMSGPROPS structure.
msgprops.cProp = cPropId; // Number of message properties
msgprops.aPropID = aMsgPropId; // IDs of the message properties
msgprops.aPropVar = aMsgPropVar; // Values of the message properties
msgprops.aStatus = aMsgStatus; // Error reports
// Generate the format name required for opening the administration queue.
WCHAR * wszAdminFormatName = NULL;
DWORD dwFormatNameLength = 0;
dwFormatNameLength = wcslen(wszAdminQueueName) + wcslen(wszComputerName) + 12;
wszAdminFormatName = new WCHAR[dwFormatNameLength];
if (wszAdminFormatName == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(wszAdminFormatName, 0, dwFormatNameLength*sizeof(WCHAR));
// ************************************
// You must concatenate "DIRECT=OS:", wszComputerName, "\",
// and wszAdminQueueName into the wszAdminFormatName buffer.
// wszAdminFormatName = "DIRECT=OS:" + wszComputerName + "\" +
// wszAdminQueueName
// If the format name is too long for the buffer,
// return FALSE.
// ************************************
// Open the administration queue to peek at all the messages.
hr = MQOpenQueue(
wszAdminFormatName, // Format name of the administration queue
MQ_RECEIVE_ACCESS, // Access mode
MQ_DENY_RECEIVE_SHARE, // Share mode
&hQueue // OUT: Queue handle
);
// Free the memory that was allocated for the format name string.
delete [] wszAdminFormatName;
// Handle any error returned by MQOpenQueue.
if (FAILED(hr))
{
return hr;
}
// Create the cursor used to navigate through the administration queue.
hr = MQCreateCursor(
hQueue, // Queue handle
&hCursor // OUT: Cursor handle
);
if (FAILED(hr))
{
MQCloseQueue(hQueue);
return hr;
}
// Peek at the first message in the administration queue.
hr = MQReceiveMessage(
hQueue, // Queue handle
0, // Maximum time (msec)
MQ_ACTION_PEEK_CURRENT, // Receive action
&msgprops, // Message property structure
NULL, // No OVERLAPPED structure
NULL, // No callback function
hCursor, // Cursor handle
MQ_NO_TRANSACTION // Not in a transaction
);
if (FAILED(hr))
{
MQCloseCursor(hCursor);
MQCloseQueue(hQueue);
return hr;
}
// Find the matching message in the administration queue.
do
{
for (i = 0; (rgucMsgID[i] == rgucCorrelationID[i]) && (i < 20); i++);
if (i == 20) // The message and correlation IDs match.
{
// Display the label of the message.
wprintf(L"Label of the matching message: %s\n", msgprops.aPropVar[2].pwszVal);
}
//Peek at the next message in the administration queue.
hr = MQReceiveMessage(
hQueue, // Queue handle
0, // Maximum time (msec)
MQ_ACTION_PEEK_NEXT, // Receive action set to peek at the next message
&msgprops, // Message property structure
NULL, // No OVERLAPPED structure
NULL, // No callback function
hCursor, // Cursor handle
NULL // No transaction
);
if (FAILED(hr))
{
break;
}
} while (SUCCEEDED(hr));
// Close the cursor and queue to free resources.
hr = MQCloseCursor(hCursor);
if (FAILED(hr))
{
MQCloseQueue(hQueue);
return hr;
}
hr = MQCloseQueue(hQueue);
if (FAILED(hr))
{
return hr;
}
wprintf(L"Peeking completed! Label of the last message: %s\n", msgprops.aPropVar[2].pwszVal);
return hr;
}