Message Timeouts, Acknowledgements, and Administration Queues

< BACK  NEXT >
[oR]

So far, the code used to send messages has only checked to see whether the message could be added to a queue there is no check that the message could be sent to its final destination queue, possibly on a different computer. For reliable message transfer, you can specify a timeout value which, if exceeded, will result in an acknowledgement message being placed in an administration queue. You can then read messages from this administration queue to determine which messages failed to reach their destination. Administration queues are ordinary private queues you create using MQCreateQueue.

Since you may be sending many different messages, it is important that you can match up the messages in the administration queue to the original message. MSMQ creates a 20-byte unique message identifier that you can use for tracking.

First, you will need to create a message queue to be used as an administration queue. The code would be very similar to that presented in Listing 15.2. The code samples in this section use an administration queue created with the following pathname and label:

 // Queue pathname LPWSTR wszPathName =       _T(".\\PRIVATE$\\WinCEInQueueAdmin"); // Queue label LPWSTR wszQueueLabel =       _T("Admin Queue for WinCEInQueue"); 

To enable message timeouts and use message identifiers, you will need to add the following properties to the messages you send:

  • PROPID_M_ADMIN_QUEUE This property specifies the name of the administration queue in which the message will be placed if it cannot be delivered.

  • PROPID_M_TIME_TO_BE_RECEIVED A property that specifies how long MSMQ should attempt to send the message before placing it in the administration message queue.

  • PROPID_M_ACKNOWLEDGE A property that specifies the type of message acknowledgement. An application can specify either positive and negative acknowledgements, or just negative ones.

The PROPID_M_ADMIN_QUEUE property's VT_LPWSTR data value is the format name of the administration queue. The following code creates a format name for the WinCEInQueueAdmin queue and initializes the property:

 TCHAR wszAdminFormatName[1024]; DWORD dwAdminFormatNameLength = 1024; hr = MQPathNameToFormatName       (_T(".\\PRIVATE$\\WinCEInQueueAdmin"),       wszAdminFormatName,       &dwAdminFormatNameLength); if (FAILED(hr)) {     cout      _T("Failed to get format name for admin queue");   return; } aMsgPropId[cPropId] = PROPID_M_ADMIN_QUEUE; aMsgPropVar[cPropId].vt = VT_LPWSTR; aMsgPropVar[cPropId].pwszVal = wszAdminFormatName; cPropId++; 

The PROPID_M_TIME_TO_BE_RECEIVED property specifies the amount of time to elapse before the message is considered undeliverable. The timeout value is an unsigned 4-byte integer value expressed in seconds. This includes the time it spends getting to the destination queue plus the time spent waiting in the queue before it is retrieved by an application. The PROPID_M_TIME_TO_REACH_QUEUE property can be used if you are interested in specifying only the timeout for the message to reach the destination queue and are not interested in how long the message remains in the destination queue waiting to be read.

The PROPID_M_JOURNAL property can be used with a MQMSG_DEADLETTER value to specify that the message itself should be placed in the dead-letter queue. By default, undeliverable messages are deleted from the system by MSMQ.

The following code specifies that the message should timeout if not delivered and read within 30 seconds. In a production environment the timeout period would probably be substantially longer, especially if you are working with disconnected Windows CE devices.

 aMsgPropId[cPropId] = PROPID_M_TIME_TO_BE_RECEIVED; aMsgPropVar[cPropId].vt = VT_UI4; aMsgPropVar[cPropId].ulVal = 30; // seconds cPropId++; 

The PROPID_M_ACKNOWLEDGE message specifies the situations in which an acknowledgement message will be placed in the administration queue. The data value associated with this property can be a combination of the following constants:

  • MQMSG_ACKNOWLEDGEMENT_FULL_REACH_QUEUE Posts a positive or negative acknowledgement depending on whether or not the message reaches the queue. A negative acknowledgement is posted when the time-to-reach-queue timer of the message expires.

  • MQMSG_ACKNOWLEDGEMENT_NACK_REACH_QUEUE Posts a negative acknowledgement when the message cannot reach the queue.

  • MQMSG_ACKNOWLEDGEMENT_FULL_RECEIVE Posts a positive or negative acknowledgement depending on whether or not the message is retrieved from the queue before its time-to-be-received timer expires.

  • MQMSG_ACKNOWLEDGEMENT_NACK_RECEIVE Posts a negative acknowledgement when an error occurs and the message cannot be retrieved from the queue before its time-to-be-received timer expires.

  • MQMSG_ACKNOWLEDGEMENT_NONE The default. No acknowledgement messages (positive or negative) are posted.

The following code uses the PROPID_M_ACKNOWLEDGE to specify that an acknowledgement message should be placed in the administration queue if the message fails to be read within the timeout period:

 aMsgPropId[cPropId] = PROPID_M_ACKNOWLEDGE; aMsgPropVar[cPropId].vt = VT_UI1; aMsgPropVar[cPropId].bVal =         MQMSG_ACKNOWLEDGEMENT_NACK_RECEIVE; cPropId++; 

The message identifier is a 20-byte value based on a unique machine GUID and a unique message number. The PROPID_M_MSGID property can be used to retrieve the identifier. You should supply a 20-byte buffer, and this buffer will be initialized with the message identifier after calling MQSendMessage. The following code initializes the PROPID_M_MSGID property:

 BYTE bMsgID[20]; memset(bMsgID, 0, 20); aMsgPropId[cPropId] = PROPID_M_MSGID; aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1; aMsgPropVar[cPropId].caub.pElems = bMsgID; aMsgPropVar[cPropId].caub.cElems = 20; cPropId++; 

The code in Listing 15.6 shows writing a message to a queue with a request for a negative acknowledgement if the receive timeout period is exceeded using the properties described above. The acknowledgement messages will be written to the WinCEInQueueAdmin queue.

Listing 15.6 Writing a message with acknowledgement request
 void DisplayMsgId(BYTE bMsgId[]) {   for(int i = 0; i  20; i++)     cout   (int)bMsgId[i]   _T(" "); } void Listing15_6() {   HRESULT hr;   QUEUEHANDLE hq;   TCHAR wszFormatName[256];   DWORD dwFormatNameLength = 256;   hr = MQPathNameToFormatName       (_T("nickdell\\Private$\\WinCEQueue"),       wszFormatName,       &dwFormatNameLength);   hr = MQOpenQueue(wszFormatName,       MQ_SEND_ACCESS, MQ_DENY_NONE, &hq);   if(hr == MQ_OK)     cout   _T("Opened queue")   endl;   else   {     DisplayOpenError(hr);     return;   }   DWORD cPropId = 0;   MQMSGPROPS msgprops;   MSGPROPID aMsgPropId[7];   MQPROPVARIANT aMsgPropVar[7];   HRESULT aMsgStatus[7];   aMsgPropId[cPropId] = PROPID_M_LABEL;   aMsgPropVar[cPropId].vt = VT_LPWSTR;   aMsgPropVar[cPropId].pwszVal =       _T("Test Acknowledge Message");   cPropId++;   aMsgPropId[cPropId] = PROPID_M_BODY_TYPE;   aMsgPropVar[cPropId].vt = VT_UI4;   aMsgPropVar[cPropId].ulVal = VT_BSTR;   cPropId++;   BSTR bStr = SysAllocString(       _T("Body text for the message"));   aMsgPropId[cPropId] = PROPID_M_BODY;   aMsgPropVar[cPropId].vt = VT_VECTOR|VT_UI1;   aMsgPropVar[cPropId].caub.pElems = (LPBYTE)bStr;   aMsgPropVar[cPropId].caub.cElems =       SysStringByteLen(bStr);   cPropId++;   TCHAR wszAdminFormatName[1024];   DWORD dwAdminFormatNameLength = 1024;   hr = MQPathNameToFormatName       (_T(".\\Private$\\WinCEInQueueAdmin"),       wszAdminFormatName,       &dwAdminFormatNameLength);   aMsgPropId[cPropId] = PROPID_M_ADMIN_QUEUE;   aMsgPropVar[cPropId].vt = VT_LPWSTR;   aMsgPropVar[cPropId].pwszVal = wszAdminFormatName;   cPropId++;   aMsgPropId[cPropId] = PROPID_M_ACKNOWLEDGE;   aMsgPropVar[cPropId].vt = VT_UI1;   aMsgPropVar[cPropId].bVal =       MQMSG_ACKNOWLEDGEMENT_NACK_RECEIVE;   cPropId++;   aMsgPropId[cPropId] = PROPID_M_TIME_TO_BE_RECEIVED;   aMsgPropVar[cPropId].vt = VT_UI4;   aMsgPropVar[cPropId].ulVal = 30; // seconds   cPropId++;   BYTE bMsgID[20];   memset(bMsgID, 0, 20);   aMsgPropId[cPropId] = PROPID_M_MSGID;   aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1;   aMsgPropVar[cPropId].caub.pElems = bMsgID;   aMsgPropVar[cPropId].caub.cElems = 20;   cPropId++;   msgprops.cProp = cPropId;   msgprops.aPropID = aMsgPropId;   msgprops.aPropVar = aMsgPropVar;   msgprops.aStatus = aMsgStatus;   hr = MQSendMessage(hq, &msgprops, NULL);   if (FAILED(hr))     cout   _T("Could not send message")   endl;   else   {     DisplayMsgId(bMsgID);     cout   endl   _T("Message queued")   endl;   }   MQCloseQueue(hq);   // monitor administration queue   InitializeAdminQueueRead(); } 

Once the message has been added to the queue, the application will need to monitor the administration queue to see if acknowledgement messages are delivered. In the above case an acknowledgement message will only be received if the message times out. Depending on how your application operates, you could open the administration queue and read messages using a callback function, or periodically check the queue for messages. You will need to match the acknowledgement messages to the original message identifier. The PROPID_M_CORRELATIONID property in the acknowledgment message will contain the message identifier of the message that timed out. You can request that the correlation identifier is returned when the acknowledgement message is read from the administration queue by adding a property like the following:

 LPBYTE lpbMsgID = new BYTE[20]; memset(lpbMsgID, 0, 20); pMsgPropId[cPropId] = PROPID_M_CORRELATIONID; pMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1; pMsgPropVar[cPropId].caub.pElems = lpbMsgID; pMsgPropVar[cPropId].caub.cElems = 20; cPropId++; 

All the source code for creating an administration queue, adding a message with properties for creating acknowledgement messages, and reading these messages from the queue can be found on the CDROM in the source file Chapter15.cpp under Listing 15.6.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net