Returning an Acknowledgment Message by a Connector Application

Acknowledgment messages returned by the connector application must be sent to the administration queue specified by the original message. Several properties must be set to the acknowledgment message values shown below, and others should be set to the values specified by the original message.

The following properties must be set to acknowledgment message values shown below.

Property Setting
PROPID_M_ACKNOWLEDGE MQMSG_ACKNOWLEDGMENT_NONE
PROPID_M_AUTH_LEVEL MQMSG_AUTH_LEVEL_NONE
PROPID_M_BODY For positive acknowledgments set to NULL. For negative acknowledgments (with the exception of encrypted message bodies), set to the body of the original message.
PROPID_M_CORRELATIONID Message identifier of original message.
PROPID_M_CLASS Appropriate acknowledgment class.
PROPID_M_JOURNAL MQMSG_JOURNAL_NONE
PROPID_M_RESP_QUEUE Destination queue of the original message.
PROPID_M_TIME_TO_BE_RECEIVED INFINITE
PROPID_M_TIME_TO_REACH_QUEUE INFINITE

All the other properties are set to the same values as the original message.

    To send an acknowledgment message
  1. Open the administration queue specified by the original application.
    hr = MQOpenQueue(lpstrAdminQueue,MQ_SEND_ACCESS,0, &hQueue);
    if (FAILED(hr))
    {
    // Handle failure
    // Return hr;
    }
    
  2. Set the acknowledgment default value required by MSMQ.
    aPropID[cProp] = PROPID_M_CLASS;
    aPropVar[cProp].vt = VT_UI2;
    aPropVar[cProp].uiVal = AckValue;
    cProp++;
    
    aPropID[cProp] = PROPID_M_ACKNOWLEDGE;
    aPropVar[cProp].vt = VT_UI1;
    aPropVar[cProp].bVal = MQMSG_ACKNOWLEDGMENT_NONE;
    cProp++;
    
    aPropID[cProp] = PROPID_M_TIME_TO_BE_RECEIVED;
    aPropVar[cProp].vt = VT_UI4;
    aPropVar[cProp].ulVal = INFINITE;
    cProp++;
    
    aPropID[cProp] = PROPID_M_TIME_TO_REACH_QUEUE;
    aPropVar[cProp].vt = VT_UI4;
    aPropVar[cProp].ulVal = INFINITE;
    cProp++;
    
    aPropID[cProp] = MQMSG_JOURNAL_NONE;
    aPropVar[cProp].vt = VT_UI1;
    aPropVar[cProp].bVal = pMsgProps->aPropVar[i].bVal;
    cProp++;
    
  3. Set the remaining message properties. Set PROPID_M_BODY, PROPID_M_CORRELATIONID, PROPID_M_CLASS, and PROPID_M_RESP_QUEUE to the values specified above.
  4. Set PROPID_M_CONNECTION_TYPE. This tells the application reading the acknowledgment message that the message was not created by MSMQ.
    aPropID[cProp] = PROPID_M_CONNECTOR_TYPE;
    aPropVar[cProp].vt = VT_CLSID;
    aPropVar[cProp].puuid = &g_gConnectorType;
    cProp++;
     
  5. Call MQSendMessage to send the message.
    hr = MQSendMessage(hQueue, &SendMsgProp, NULL);
    

Example

The following example creates an acknowledgment message and sends it back to the administration queue specified by the original message. It assumes that the format name of the administration queue (lpstrAdimQueue), all original message properties (pMsgProps), and the value of the acknowledgment (ackValue) are all available.

HRESULT CreateAck(LPWSTR lpstrAdminQueue,
                 USHORT AckValue,
                 MQMSGPROPS* pMsgProps
                 )

{
MQMSGPROPS SendMsgProp;
MSGPROPID     aPropID[40];
MQPROPVARIANT  aPropVar[40];
HRESULT        aStatus[40];
HRESULT        hr;
HANDLE hQueue = NULL;
DWORD cProp = 0;
 
//////////////////////////////////
// Open the administration queue 
// specified by the original message.
/////////////////////////////////
hr = MQOpenQueue(lpstrAdminQueue,MQ_SEND_ACCESS,0, &hQueue);
if (FAILED(hr))
{
// Handle failure
// Return hr;
}

DWORD dwExtensionMsgSize = 0;
DWORD dwSenderidLen = 0;
DWORD dwBodySize = 0;
BOOL fEncrypted = FALSE;
DWORD i;


//////////////////////////////////////////////////
// Set the acknowledgment message default values.
//////////////////////////////////////////////////
aPropID[cProp] = PROPID_M_CLASS;
aPropVar[cProp].vt = VT_UI2;
aPropVar[cProp].uiVal = AckValue;
cProp++;

aPropID[cProp] = PROPID_M_ACKNOWLEDGE;
aPropVar[cProp].vt = VT_UI1;
aPropVar[cProp].bVal = MQMSG_ACKNOWLEDGMENT_NONE;
cProp++;

aPropID[cProp] = PROPID_M_TIME_TO_BE_RECEIVED;
aPropVar[cProp].vt = VT_UI4;
aPropVar[cProp].ulVal = INFINITE;
cProp++;

aPropID[cProp] = PROPID_M_TIME_TO_REACH_QUEUE;
aPropVar[cProp].vt = VT_UI4;
aPropVar[cProp].ulVal = INFINITE;
cProp++;

aPropID[cProp] = MQMSG_JOURNAL_NONE;
aPropVar[cProp].vt = VT_UI1;
aPropVar[cProp].bVal = pMsgProps->aPropVar[i].bVal;
cProp++;


//////////////////////////////////////
// Set all other message properties to 
// the values of the original message.
//////////////////////////////////////


// Get size and length of properties.

for (i = 0; i < pMsgProps->cProp ; i++)
{
switch(pMsgProps->aPropID[i])
{
    case PROPID_M_EXTENSION:
         dwExtensionMsgSize = pMsgProps->aPropVar[i].ulVal;    
         break;
         
    case PROPID_M_SENDERID_LEN:
         dwSenderidLen = pMsgProps->aPropVar[i].ulVal;
         break;
         
    case PROPID_M_BODY_SIZE:
         dwBodySize = pMsgProps->aPropVar[i].ulVal;
         break;
         
    case PROPID_M_PRIV_LEVEL:
         fEncrypted = (pMsgProps->aPropVar[i].ulVal == MQMSG_PRIV_LEVEL_BODY);
            break;
             
             default:
             break;
   }
}

for (i = 0; i < pMsgProps->cProp ; i++)
{
switch (pMsgProps->aPropID[i])
{

         // Set correlation identifier 
        case PROPID_M_MSGID:
            aPropID[cProp] = PROPID_M_CORRELATIONID;
            aPropVar[cProp].vt = VT_UI1|VT_VECTOR;
            aPropVar[cProp].caub.cElems = pMsgProps->aPropVar[i].caub.cElems;
            aPropVar[cProp].caub.pElems = pMsgProps->aPropVar[i].caub.pElems;
            cProp++;
            break;
        
        // Set message priority.
        case PROPID_M_PRIORITY:
            aPropID[cProp] = PROPID_M_PRIORITY;
            aPropVar[cProp].vt = VT_UI1;
            aPropVar[cProp].bVal = pMsgProps->aPropVar[i].bVal;
            cProp++;
            break;
        
        // Set delivery mode.
        case PROPID_M_DELIVERY:
            aPropID[cProp] = PROPID_M_DELIVERY;
            aPropVar[cProp].vt = VT_UI1;
            aPropVar[cProp].bVal = pMsgProps->aPropVar[i].bVal;
            cProp++;
            break;
        
        // Set application specific information
       case PROPID_M_APPSPECIFIC:
            aPropID[cProp] = PROPID_M_APPSPECIFIC;
            aPropVar[cProp].vt = VT_UI4;
            aPropVar[cProp].ulVal = pMsgProps->aPropVar[i].ulVal;
            cProp++;
            break;
        
        // Set message label to the same 
        case PROPID_M_LABEL:
            aPropID[cProp] = PROPID_M_LABEL;
            aPropVar[cProp].vt = VT_LPWSTR;
            aPropVar[cProp].pwszVal = pMsgProps->aPropVar[i].pwszVal;
                cProp++;
                break;
            //
            
        // Set extension information.
        case PROPID_M_EXTENSION:
            aPropID[cProp] = PROPID_M_EXTENSION;
            aPropVar[cProp].vt = VT_UI1|VT_VECTOR;
            aPropVar[cProp].caub.cElems = dwExtensionMsgSize;
            aPropVar[cProp].caub.pElems = pMsgProps->aPropVar[i].caub.pElems;
                cProp++;
                break;
        
        // Set acknowledge message response queue to 
        // the destination queue of the original message.
        case PROPID_M_DEST_QUEUE:
            aPropID[cProp] = PROPID_M_RESP_QUEUE;
            aPropVar[cProp].vt = VT_LPWSTR;
            aPropVar[cProp].pwszVal = pMsgProps->aPropVar[i].pwszVal;
            cProp++;           
            break;
        
        //////////////////////////////////////////////
        // Set message body. If acknowledge is negative 
        // and the original message isn't encrypted, add 
        // message body of original message.
        //////////////////////////////////////////////
        case PROPID_M_BODY:
            if (MQCLASS_NACK(AckValue) && ! fEncrypted)
            {
                aPropID[cProp] = PROPID_M_BODY;
                aPropVar[cProp].vt = VT_UI1|VT_VECTOR;
                aPropVar[cProp].caub.cElems = dwBodySize;
                aPropVar[cProp].caub.pElems = pMsgProps->aPropVar[i].caub.pElems;
                cProp++;
            }
            break;

        default:
            break;
    }
}


//////////////////////////////////////////////////
// Set the connector type identifier (GUID) to 
// indicate who generated the acknowledge message.
//////////////////////////////////////////////////
aPropID[cProp] = PROPID_M_CONNECTOR_TYPE;
aPropVar[cProp].vt = VT_CLSID;
aPropVar[cProp].puuid = &g_gConnectorType;
cProp++;

SendMsgProp.aStatus = aStatus;
SendMsgProp.aPropID = aPropID;
SendMsgProp.aPropVar = aPropVar;
SendMsgProp.cProp =cProp;


////////////////////////////////////////////////
// Send the acknowledge message back to the 
// administration queue specified by the 
// original message.
/////////////////////////////////////////////////
hr = MQSendMessage(hQueue, &SendMsgProp, NULL);

MQCloseQueue(hQueue);

return hr;
}