HRESULT MsmqQueue::read( char *szMessageBody, int *iMessageBodySize, int *iMessageBodyType, char *szLabel, char *szCorrelationID, bool isTransactional, int iTimeout, bool isPeekOnly ) { const int NUMBEROFPROPERTIES = 8; DWORD i = 0; HRESULT hr = MQ_OK; DWORD dwAction= isPeekOnly ? MQ_ACTION_PEEK_CURRENT : MQ_ACTION_RECEIVE; ITransaction* pTransaction = isTransactional ? MQ_SINGLE_MESSAGE : MQ_NO_TRANSACTION; MQMSGPROPS msgprops; MSGPROPID aMsgPropId[NUMBEROFPROPERTIES]; PROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES]; // Message Body Buffer if (szMessageBody!=NULL) { memset(szMessageBody, 0, *iMessageBodySize); aMsgPropId[i] = PROPID_M_BODY; aMsgPropVar[i].vt = VT_VECTOR | VT_UI1; aMsgPropVar[i].caub.pElems = (LPBYTE)szMessageBody; aMsgPropVar[i].caub.cElems = *iMessageBodySize; i++; } // Message Body Size aMsgPropId[i] = PROPID_M_BODY_SIZE; aMsgPropVar[i].vt = VT_NULL; i++; // Message Body Type aMsgPropId[i] = PROPID_M_BODY_TYPE; aMsgPropVar[i].vt = VT_NULL; i++; // Correlation ID aMsgPropId[i] = PROPID_M_CORRELATIONID; aMsgPropVar[i].vt = VT_VECTOR | VT_UI1; aMsgPropVar[i].caub.pElems = (LPBYTE)szCorrelationID; aMsgPropVar[i].caub.cElems = PROPID_M_CORRELATIONID_SIZE; memset(szCorrelationID, 0, PROPID_M_CORRELATIONID_SIZE); i++; // Label Size aMsgPropId[i] = PROPID_M_LABEL_LEN; // Property ID aMsgPropVar[i].vt =VT_UI4; // Type indicator aMsgPropVar[i].ulVal = MQ_MAX_MSG_LABEL_LEN; // Label buffer size i++; // Label Buffer WCHAR wszLabelBuffer[MQ_MAX_MSG_LABEL_LEN] = {0}; aMsgPropId[i] = PROPID_M_LABEL; aMsgPropVar[i].vt = VT_LPWSTR; aMsgPropVar[i].pwszVal = wszLabelBuffer; i++; // NB: if you want to get PROPID_M_RESP_QUEUE, you must also request PROPID_M_RESP_QUEUE_LEN. // that implies 2 additional properties to request. // see http://msdn.microsoft.com/library/en-us/msmq/html/ea8cfb28-43e0-4041-9add-11080375690c.asp msgprops.cProp = i; // Number of message properties msgprops.aPropID = aMsgPropId; // IDs of the message properties msgprops.aPropVar = aMsgPropVar; // Values of the message properties msgprops.aStatus = 0; // Error reports hr = MQReceiveMessage( hQueue, // Handle to the destination queue iTimeout, // Time out interval dwAction, // Peek? or Dequeue. Receive action &msgprops, // Pointer to the MQMSGPROPS structure NULL, NULL, NULL, // No OVERLAPPED structure etc. pTransaction // MQ_SINGLE_MESSAGE | MQ_MTS_TRANSACTION | // MQ_XA_TRANSACTION ); // http://msdn.microsoft.com/library/en-us/intl/unicode_2bj9.asp memset(szLabel, 0, MQ_MAX_MSG_LABEL_LEN); if (0 != WideCharToMultiByte( CP_ACP, // code page 0, // conversion flags wszLabelBuffer, // wide-character string to convert (int) wcslen(wszLabelBuffer), // number of chars in string. szLabel, // buffer for new string MQ_MAX_MSG_LABEL_LEN, // size of buffer NULL, // (LPCSTR) default for unmappable chars NULL // (LPBOOL) set when default char used )) { // actually converted, so... we are happy... } for(ULONG prop = 0 ; prop < msgprops.cProp; ++prop) { if (msgprops.aPropID[prop]==PROPID_M_BODY_SIZE) *iMessageBodySize = msgprops.aPropVar[prop].ulVal; if (msgprops.aPropID[prop]==PROPID_M_BODY_TYPE) *iMessageBodyType = msgprops.aPropVar[prop].ulVal; } return hr; };
//-------------------------------------------------------- // // Receiver Mode // ------------- // The receiver side does the following: // 1. Creates a queue on the local computer // of type "guidMQTestType". // The queue is either public or private, depending // on the connection we want to establish. // 2. Opens the queue. // 3. In a loop, // receives messages // and prints the message body and message label. // 4. Cleans up handles. // 5. Deletes the queue from the directory service. // //-------------------------------------------------------- void Receiver(int dDirectMode) { MQQUEUEPROPS qprops; MQMSGPROPS msgprops; MQPROPVARIANT aPropVar[MAX_VAR]; QUEUEPROPID aqPropId[MAX_VAR]; MSGPROPID amPropId[MAX_VAR]; DWORD cProps; WCHAR wcsFormat[MAX_FORMAT]; UCHAR Buffer[MAX_BUFFER]; WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN+1]; WCHAR wcsPathName[MAX_FORMAT]; DWORD dwNumChars; QUEUEHANDLE qh; HRESULT hr; int nPos; printf("\nReceiver Mode on Machine: %s\n\n", mbsMachineName); // // Set properties to create a queue on the local computer. // cProps = 0; // Set the path name. if(dDirectMode == DIRECT) // Private queue path name { nPos = _snwprintf_s( wcsPathName, sizeof(wcsPathName)/sizeof(wcsPathName[0]), sizeof(wcsPathName)/sizeof(wcsPathName[0]) - 1, L"%S\\private$\\MSMQTest", mbsMachineName ); if(nPos < 0) { printf("The path name is too long for the buffer. Exiting...\n"); exit(1); } } else // Public queue path name { nPos = _snwprintf_s( wcsPathName, sizeof(wcsPathName)/sizeof(wcsPathName[0]), sizeof(wcsPathName)/sizeof(wcsPathName[0]) - 1, L"%S\\MSMQTest", mbsMachineName ); if(nPos < 0) { printf("The path name is too long for the buffer. Exiting...\n"); exit(1); } } aqPropId[cProps] = PROPID_Q_PATHNAME; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = wcsPathName; cProps++; // Specify the service type GUID of the queue. // (This property will be used to locate all the queues of this type.) aqPropId[cProps] = PROPID_Q_TYPE; aPropVar[cProps].vt = VT_CLSID; aPropVar[cProps].puuid = &guidMQTestType; cProps++; // Add a descriptive label to the queue. // (A label is useful for administration through the MSMQ admin tools.) aqPropId[cProps] = PROPID_Q_LABEL; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = L"Sample application of MSMQ SDK"; cProps++; // Create a QUEUEPROPS structure. qprops.cProp = cProps; qprops.aPropID = aqPropId; qprops.aPropVar = aPropVar; qprops.aStatus = 0; // // Create the queue. // dwNumChars = MAX_FORMAT; hr = MQCreateQueue( NULL, // IN: Default security &qprops, // IN/OUT: Queue properties wcsFormat, // OUT: Format name &dwNumChars); // IN/OUT: Size of the format name if (FAILED(hr)) { // // API failed, but not because the queue exists. // if (hr != MQ_ERROR_QUEUE_EXISTS) Error("MQCreateQueue failed", hr); // // The queue exist, so get its format name. // printf("The queue already exists. Open it anyway.\n"); if(dDirectMode == DIRECT) // It's a private queue, so we know its direct format name. { int n = _snwprintf_s( wcsFormat, sizeof(wcsFormat)/sizeof(wcsFormat[0]), sizeof(wcsFormat)/sizeof(wcsFormat[0]) - 1, L"DIRECT=OS:%s", wcsPathName); if(n < 0) { printf("The format name is too long for the buffer. Exiting...\n"); exit(1); } } else // It's a public queue, so we must get its format name from the DS. { dwNumChars = sizeof(wcsFormat)/sizeof(wcsFormat[0]); hr = MQPathNameToFormatName( wcsPathName, // IN: Queue path name wcsFormat, // OUT: Format name &dwNumChars); // IN/OUT: Size of the format name if (FAILED(hr)) Error("The format name cannot be retrieved", hr); } } // // Open the queue with receive access. // hr = MQOpenQueue( wcsFormat, // IN: Queue format name MQ_RECEIVE_ACCESS, // IN: Want to receive from queue 0, // IN: Allow sharing &qh); // OUT: Handle of open queue // // Things are a little bit tricky. MQCreateQueue succeeded, but in the // case of a public queue, this does not mean that MQOpenQueue // will succeed, because replication delays are possible. The queue is // registered in the DS, but it might take a replication interval // until the replica reaches the server that I am connected to. // To overcome this, open the queue in a loop. // // In this specific case, this can happen only if this program // is run on an MSMQ 1.0 backup server controller (BSC) or on // a client connected to a BSC. // To be totally on the safe side, we should have put some code // to exit the loop after a few retries, but this is just a sample. // while (hr == MQ_ERROR_QUEUE_NOT_FOUND) { printf("."); // Wait a bit. Sleep(500); // Retry. hr = MQOpenQueue(wcsFormat, MQ_RECEIVE_ACCESS, 0, &qh); } if (FAILED(hr)) Error("The queue cannot be opened", hr); // // Main receiver loop // if(dDirectMode == DIRECT) { printf("\n* Working in workgroup (direct) mode.\n"); } printf("\n* Waiting for messages...\n"); for(;;) { // // Set the message properties for reading messages. // cProps = 0; // Ask for the body of the message. amPropId[cProps] = PROPID_M_BODY; aPropVar[cProps].vt = VT_UI1 | VT_VECTOR; aPropVar[cProps].caub.cElems = sizeof(Buffer); aPropVar[cProps].caub.pElems = Buffer; cProps++; // Ask for the label of the message. amPropId[cProps] = PROPID_M_LABEL; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = wcsMsgLabel; cProps++; // Ask for the length of the label of the message. amPropId[cProps] = PROPID_M_LABEL_LEN; aPropVar[cProps].vt = VT_UI4; aPropVar[cProps].ulVal = sizeof(wcsMsgLabel); cProps++; // Create a MSGPROPS structure. msgprops.cProp = cProps; msgprops.aPropID = amPropId; msgprops.aPropVar = aPropVar; msgprops.aStatus = 0; // // Receive the message. // hr = MQReceiveMessage( qh, // IN: Queue handle INFINITE, // IN: Time-out MQ_ACTION_RECEIVE, // IN: Read operation &msgprops, // IN/OUT: Message properties to retrieve NULL, // IN/OUT: No OVERLAPPED structure NULL, // IN: No callback NULL, // IN: No cursor NULL); // IN: Not part of a transaction if (FAILED(hr)) Error("MQReceiveMessage failed", hr); // // Display the received message. // printf("%S : %s\n", wcsMsgLabel, Buffer); // // Check for a request to end the application. // if (_stricmp(Buffer, "quit") == 0) break; } /* while (1) */ // // Cleanup: Close the handle to the queue. // MQCloseQueue(qh); // // In the concluding stage, we delete the queue from the directory // service. (We don't need to do this. In case of a public queue, // leaving it in the DS enables sender applications to send messages // even if the receiver is not available.) // hr = MQDeleteQueue(wcsFormat); if (FAILED(hr)) Error("The queue cannot be deleted", hr); }
DWORD ReceiveUpdates(CDisdrawDlg *pDrawDlg) { // // Prepare the message properties to receive. // DWORD cProps = 0; MQMSGPROPS propsMessage; MQPROPVARIANT aPropVar[2]; MSGPROPID aPropId[2]; WCHAR wcsBody[MAX_MSG_BODY_LEN+1]; aPropId[cProps] = PROPID_M_BODY; aPropVar[cProps].vt = VT_UI1 | VT_VECTOR; aPropVar[cProps].caub.cElems = sizeof(wcsBody); aPropVar[cProps].caub.pElems = (UCHAR *)wcsBody; cProps++; aPropId[cProps] = PROPID_M_BODY_SIZE; aPropVar[cProps].vt = VT_UI4; cProps++; propsMessage.cProp = cProps; propsMessage.aPropID = aPropId; propsMessage.aPropVar = aPropVar; propsMessage.aStatus = NULL; // // Keep receiving updates sent to the incoming queue. // HRESULT hr; LINE line; char mbsBody[MAX_MSG_BODY_LEN + 1]; while (TRUE) { // // Synchronously receive a message from the incoming queue. // hr = MQReceiveMessage(pDrawDlg->m_hqIncoming, INFINITE, MQ_ACTION_RECEIVE, &propsMessage, NULL, NULL, NULL, NULL); // // Determine if the message contains a keystroke or a line. // if (!FAILED(hr)) { // // Convert the body to a multibyte null-terminated string. // UINT uNumChars = aPropVar[1].ulVal/sizeof(WCHAR); size_t nResultedStringLength=0; wcstombs_s( &nResultedStringLength, mbsBody, sizeof(mbsBody), wcsBody, uNumChars ); // // Add the keystroke to the drawing. // if (uNumChars == 1) { pDrawDlg->m_drawScribble.AddKeystroke(mbsBody); } // // Add the line received to the drawing. // else { sscanf_s(mbsBody, "%07ld%07ld%07ld%07ld", &line.ptStart.x, &line.ptStart.y, &line.ptEnd.x, &line.ptEnd.y); pDrawDlg->m_drawScribble.AddLine(line); } } } return 0; }