/******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright (C) 1999 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ // // Includes // #include #include // // Unique include file for MSMQ apps // #include // // Various defines // #define MAX_VAR 20 #define MAX_FORMAT 100 #define MAX_BUFFER 500 #define DIRECT 1 #define STANDARD 0 #define DS_ENABLED 1 #define DS_DISABLED 0 // // GUID created with the tool "GUIDGEN" // static CLSID guidMQTestType = { 0xc30e0960, 0xa2c0, 0x11cf, { 0x97, 0x85, 0x0, 0x60, 0x8c, 0xb3, 0xe8, 0xc } }; // // Prototypes // void Error(char *s, HRESULT hr); void Syntax(); char mbsMachineName[MAX_COMPUTERNAME_LENGTH + 1]; //----------------------------------------------------- // // Check if local computer is DS enabled or DS disabled // //----------------------------------------------------- int DetectDsConnection(void) { MQPRIVATEPROPS PrivateProps; QMPROPID aPropId[MAX_VAR]; MQPROPVARIANT aPropVar[MAX_VAR]; HRESULT aStatus[MAX_VAR]; DWORD cProp; HRESULT hr; // // Prepare ds-enabled property // cProp = 0; aPropId[cProp] = PROPID_PC_DS_ENABLED; aPropVar[cProp].vt = VT_NULL; ++cProp; // Create a PRIVATEPROPS structure PrivateProps.cProp = cProp; PrivateProps.aPropID = aPropId; PrivateProps.aPropVar = aPropVar; PrivateProps.aStatus = aStatus; // // Retrieve the information // hr = MQGetPrivateComputerInformation( NULL, &PrivateProps); if(FAILED(hr)) { Error("Unable to detect DS connection", hr); } if(PrivateProps.aPropVar[0].boolVal == 0) return DS_DISABLED; return DS_ENABLED; } //----------------------------------------------------- // // Allow a DS enabled client connect with a // DS disabled one. // //----------------------------------------------------- int SetConnectionMode(void) { char cDirectMode; // // In case the local computer is in a domain and not in workgroup mode, // we have two cases: // 1. Other side is a computer in a domain. // 2. Other side is a computer working in workgroup mode. // if(DetectDsConnection() == DS_ENABLED) { printf("Do you wish to connect with a DS disabled client (y or n) ? "); scanf("%c", &cDirectMode); switch(tolower(cDirectMode)) { case 'y': return DIRECT; case 'n': return STANDARD; default: printf("Bye.\n"); exit(1); } } return DIRECT; // Local computer is DS disabled } //-------------------------------------------------------- // // Receiver Mode // ------------- // The receiver side does the following: // 1. Creates a queue on its own computer' // of type "guidMQTestType". // The queue is either public or private, depending // on the connection we wish to establish // 2. Opens the queue // 3. In a Loop // Receives messages // Prints message body and message label // 4. Cleanup 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]; WCHAR wcsPathName[1000]; DWORD dwNumChars; QUEUEHANDLE qh; HRESULT hr; printf("\nReceiver Mode on Machine: %s\n\n", mbsMachineName); // // Prepare properties to create a queue on local machine // cProps = 0; // Set the PathName if(dDirectMode == DIRECT) // Private queue pathname { swprintf(wcsPathName, L"%S\\private$\\MSMQTest", mbsMachineName); } else // Public queue pathname { swprintf(wcsPathName, L"%S\\MSMQTest", mbsMachineName); } aqPropId[cProps] = PROPID_Q_PATHNAME; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = wcsPathName; cProps++; // Set the type of the queue // (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++; // Put a description to the queue // (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 (OUT) &dwNumChars); // IN/OUT: Size of format name if (FAILED(hr)) { // // API Fails, not because the queue exists // if (hr != MQ_ERROR_QUEUE_EXISTS) Error("Cannot create queue", hr); // // Queue exist, so get its format name // printf("Queue already exists. Open it anyway.\n"); if(dDirectMode == DIRECT) // It's a private queue, so we know its format name { swprintf(wcsFormat, L"DIRECT=OS:%s", wcsPathName); } else // It's a public queue, so we must get it from the DS { dwNumChars = MAX_FORMAT; hr = MQPathNameToFormatName( wcsPathName, // IN: Queue pathname wcsFormat, // OUT: Format name &dwNumChars); // IN/OUT: Size of format name if (FAILED(hr)) Error("Cannot retrieve format name", hr); } } // // Open the queue for 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 // // Little bit tricky. MQCreateQueue succeeded but, in case // it's a public queue, it does not mean that MQOpenQueue // will, because of replication delay. The queue is registered // in MQIS, but it might take a replication interval // until the replica reaches the server 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 a 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 hey, this is just a sample. // while (hr == MQ_ERROR_QUEUE_NOT_FOUND) { printf("."); // Wait a bit Sleep(500); // And retry hr = MQOpenQueue(wcsFormat, MQ_RECEIVE_ACCESS, 0, &qh); } if (FAILED(hr)) Error("Cannot open queue", hr); // // Main receiver loop // if(dDirectMode == DIRECT) { printf("\n* Working in direct mode."); } printf("\n* Waiting for messages...\n"); for(;;) { // // Prepare message properties to read // 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 = MQ_MAX_MSG_LABEL_LEN; 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: Timeout MQ_ACTION_RECEIVE, // IN: Read operation &msgprops, // IN/OUT: Message properties to receive NULL, // IN/OUT: No overlap NULL, // IN: No callback NULL, // IN: No cursor NULL); // IN: Not part of a transaction if (FAILED(hr)) Error("Receive message", hr); // // Display the received message // printf("%S : %s\n", wcsMsgLabel, Buffer); // // Check for end of app // if (stricmp(Buffer, "quit") == 0) break; } /* while (1) */ // // Cleanup - Close handle to the queue // MQCloseQueue(qh); // // Finish - Let's delete the queue from the directory service // (We don't need to do it. 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("Cannot delete queue", hr); } //----------------------------------------------------- // // Sender Mode // ----------- // The sender side does the following: // // If we work in STANDARD mode: // 1. Locates all queues of type "guidMQTestType" // 2. Opens handles to all the queues // 3. In a loop // Sends messages to all those queues // 4. Cleans up handles // // If we work in DIRECT mode: // 1. Opens a handle to a private queue labeled // "MSMQTest" on the computer specified // 2. Sends messages to that queue // 3. Cleans up handles //----------------------------------------------------- //----------------------------------------------------- // // Sender in STANDARD mode // //----------------------------------------------------- void StandardSender(void) { DWORD cProps; MQMSGPROPS msgprops; MQPROPVARIANT aPropVar[MAX_VAR]; QUEUEPROPID aqPropId[MAX_VAR]; MSGPROPID amPropId[MAX_VAR]; MQPROPERTYRESTRICTION aPropRestriction[MAX_VAR]; MQRESTRICTION Restriction; MQCOLUMNSET Column; HANDLE hEnum; WCHAR wcsFormat[MAX_FORMAT]; UCHAR Buffer[MAX_BUFFER]; WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN]; DWORD i; DWORD cQueue; DWORD dwNumChars; QUEUEHANDLE aqh[MAX_VAR]; HRESULT hr; printf("\nSender Mode on Machine: %s\n\n", mbsMachineName); // // Prepare parameters to locate a queue // // // 1. Restriction = Queues with PROPID_TYPE = MSMQTest queue type // cProps = 0; aPropRestriction[cProps].rel = PREQ; aPropRestriction[cProps].prop = PROPID_Q_TYPE; aPropRestriction[cProps].prval.vt = VT_CLSID; aPropRestriction[cProps].prval.puuid = &guidMQTestType; cProps++; Restriction.cRes = cProps; Restriction.paPropRes = aPropRestriction; // // 2. Columnset (i.e. queue properties to retrieve) = queue instance // cProps = 0; aqPropId[cProps] = PROPID_Q_INSTANCE; cProps++; Column.cCol = cProps; Column.aCol = aqPropId; // // Locate the queues. Issue the query // hr = MQLocateBegin( NULL, // IN: Context must be NULL &Restriction, // IN: Restriction &Column, // IN: Columns (properties) to return NULL, // IN: No need to sort &hEnum); // OUT: Enumeration handle if (FAILED(hr)) Error("LocateBegin", hr); // // Get the results (up to MAX_VAR) // (For more results, call MQLocateNext in a loop) // cQueue = MAX_VAR; hr = MQLocateNext( hEnum, // IN: Enumeration handle &cQueue, // IN/OUT: Count of properties aPropVar); // OUT: Properties of located queues if (FAILED(hr)) Error("LocateNext", hr); // // And that's it for locate // hr = MQLocateEnd(hEnum); if (cQueue == 0) { // // Could Not find any queue, so exit // printf("No queue registered"); exit(0); } printf("\t%d queue(s) found.\n", cQueue); // // Open a handle for each of the queues found // for (i = 0; i < cQueue; i++) { // Convert the queue instance to a format name dwNumChars = MAX_FORMAT; hr = MQInstanceToFormatName( aPropVar[i].puuid, // IN: Queue instance wcsFormat, // OUT: Format name &dwNumChars); // IN/OUT: Size of format name if (FAILED(hr)) Error("GuidToFormatName", hr); // // Open the queue for send access // hr = MQOpenQueue( wcsFormat, // IN: Queue format name MQ_SEND_ACCESS, // IN: Want to send to queue 0, // IN: Must be 0 for send access &aqh[i]); // OUT: Handle of open queue if (FAILED(hr)) Error("OpenQueue", hr); // // Free the GUID memory that was allocated during the locate. // MQFreeMemory(aPropVar[i].puuid); } printf("\nEnter \"quit\" to exit\n"); // // Build the message label property // swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName); // // Main sender loop // for(;;) { // // Get a string from the console // printf("Enter a string: "); if (gets(Buffer) == NULL) break; // // Prepare properties of message to send // cProps = 0; // Set 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++; // Set the label of the message amPropId[cProps] = PROPID_M_LABEL; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = wcsMsgLabel; cProps++; // Create a MSGPROPS structure msgprops.cProp = cProps; msgprops.aPropID = amPropId; msgprops.aPropVar = aPropVar; msgprops.aStatus = 0; // // Send the message to all the queue // for (i = 0; i < cQueue; i++) { hr = MQSendMessage( aqh[i], // IN: Queue handle &msgprops, // IN: Message properties to send NULL); // IN: Not part of a transaction if (FAILED(hr)) Error("Send message", hr); } // // Check for end of app // if (stricmp(Buffer, "quit") == 0) break; } /* for */ // // Close all the queue handles // for (i = 0; i < cQueue; i++) MQCloseQueue(aqh[i]); } //----------------------------------------------------- // // Sender in DIRECT mode // //----------------------------------------------------- void DirectSender(void) { MQMSGPROPS msgprops; MQPROPVARIANT aPropVar[MAX_VAR]; MSGPROPID amPropId[MAX_VAR]; DWORD cProps; WCHAR wcsFormat[MAX_FORMAT]; WCHAR wcsReceiverComputer[MAX_BUFFER]; UCHAR Buffer[MAX_BUFFER]; WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN]; QUEUEHANDLE qhSend; HRESULT hr; // // Get the receiver computer name // printf("Enter receiver computer name: "); wscanf(L"%s", wcsReceiverComputer); if(wcsReceiverComputer[0] == 0) { printf("You have entered an incorrect parameter. Exiting...\n"); return; } // // Open the queue for send access // swprintf(wcsFormat, L"DIRECT=OS:%s\\private$\\MSMQTest", wcsReceiverComputer); hr = MQOpenQueue( wcsFormat, // IN: Queue format name MQ_SEND_ACCESS, // IN: Want to send to queue 0, // IN: Must be 0 for send access &qhSend); // OUT: Handle of open queue if (FAILED(hr)) Error("OpenQueue", hr); printf("\nEnter \"quit\" to exit\n"); // // Build the message label property // swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName); fflush(stdin); // // Main sender loop // for(;;) { // // Get a string from the console // printf("Enter a string: "); if (gets(Buffer) == NULL) break; // // Prepare properties of message to send // cProps = 0; // Set 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++; // Set the label of the message amPropId[cProps] = PROPID_M_LABEL; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal = wcsMsgLabel; cProps++; // Create a MSGPROPS structure msgprops.cProp = cProps; msgprops.aPropID = amPropId; msgprops.aPropVar = aPropVar; msgprops.aStatus = 0; // // Send the message // hr = MQSendMessage( qhSend, // IN: Queue handle &msgprops, // IN: Message properties to send NULL); // IN: Not part of a transaction if (FAILED(hr)) Error("Send message", hr); // // Check for end of app // if (stricmp(Buffer, "quit") == 0) break; } /* for */ // // Close queue handle // MQCloseQueue(qhSend); } //------------------------------------------------------ // // Sender function // //------------------------------------------------------ void Sender(int dDirectMode) { if(dDirectMode == DIRECT) DirectSender(); else StandardSender(); } //----------------------------------------------------- // // MAIN // //----------------------------------------------------- main(int argc, char * * argv) { DWORD dwNumChars; int dDirectMode; if (argc != 2) { Syntax(); } // // Retrieve machine name // dwNumChars = MAX_COMPUTERNAME_LENGTH + 1; GetComputerName(mbsMachineName, &dwNumChars); // // Detect DS connection and working mode // dDirectMode = SetConnectionMode(); if(strcmp(argv[1], "-s") == 0) Sender(dDirectMode); else if (strcmp(argv[1], "-r") == 0) Receiver(dDirectMode); else Syntax(); printf("\nOK\n"); return(1); } void Error(char *s, HRESULT hr) { printf("Error: %s (0x%X)\n", s, hr); exit(1); } void Syntax() { printf("\n"); printf("Syntax: msmqtest -s | -r\n"); printf("\t-s: Sender\n"); printf("\t-r: Receiver\n"); exit(1); }