home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / msmqocm.cab / mqtestoa.cpp < prev    next >
C/C++ Source or Header  |  1997-10-06  |  16KB  |  573 lines

  1. /******************************************************************************\
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1996 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. \******************************************************************************/
  10.  
  11.  
  12. //
  13. // Includes
  14. //
  15. #include <stdio.h>
  16. #include <windows.h>
  17.  
  18. //
  19. // Unique include file for ActiveX MSMQ apps
  20. //
  21. #include "mqoai.h"
  22.  
  23. //
  24. // Various defines
  25. //
  26. #define MAX_VAR       20
  27. #define MAX_BUFFER   500
  28.  
  29.  
  30. //
  31. // GUID created with the tool "GUIDGEN"
  32. //
  33. static WCHAR strGuidMQTestType[] =
  34.   L"{c30e0960-a2c0-11cf-9785-00608cb3e80c}";
  35. //
  36. // Prototypes
  37. //
  38. void PrintError(char *s, HRESULT hr);
  39. HRESULT Syntax();
  40.  
  41. char mbsMachineName[MAX_COMPUTERNAME_LENGTH + 1];
  42.  
  43. // Some useful macros
  44. #define RELEASE(punk) if (punk) { (punk)->Release(); (punk) = NULL; }
  45. #define ADDREF(punk) ((punk) ? (punk)->AddRef() : 0)
  46. #define PRINTERROR(s, hr) { PrintError(s, hr); goto Cleanup; }
  47.  
  48.  
  49. //-----------------------------------------------------
  50. //
  51. // Receiver Mode
  52. // -------------
  53. // The receiver side does the following:
  54. //    1. Creates a public queue on its own machine
  55. //       of type "strGuidMQTestType"
  56. //    2. Opens the queue
  57. //    3. In a Loop
  58. //          Receives messages
  59. //          Prints message body and message label
  60. //    4. Cleanup handles
  61. //    5. Deletes the queue from the directory service
  62. //
  63. //-----------------------------------------------------
  64. HRESULT Receiver()
  65. {
  66.     IMSMQMessage *pmessageReceive = NULL;
  67.     IMSMQQueue *pqReceive = NULL;
  68.     IMSMQQueueInfo  *pqinfo = NULL;
  69.     BSTR bstrPathName = NULL;
  70.     BSTR bstrServiceType = NULL;
  71.     BSTR bstrLabel = NULL;
  72.     BSTR bstrMsgLabel = NULL;
  73.     VARIANT varIsTransactional, varIsWorldReadable, varBody, varBody2, varWantDestQueue, varWantBody, varReceiveTimeout;
  74.     WCHAR wcsPathName[1000];
  75.     BOOL fQuit = FALSE;
  76.     HRESULT hresult = NOERROR;
  77.  
  78.     printf("\nReceiver Mode on Machine: %s\n\n", mbsMachineName);
  79.  
  80.     //
  81.     // Create MSMQQueueInfo object
  82.     //
  83.     hresult = CoCreateInstance(
  84.                    CLSID_MSMQQueueInfo,
  85.                    NULL,      // punkOuter
  86.                    CLSCTX_SERVER,
  87.                    IID_IMSMQQueueInfo,
  88.                    (LPVOID *)&pqinfo);
  89.     if (FAILED(hresult)) {
  90.       PRINTERROR("Cannot create queue", hresult);
  91.     }
  92.  
  93.     //
  94.     // Prepare properties to create a queue on local machine
  95.     //
  96.  
  97.     // Set the PathName
  98.     swprintf(wcsPathName, L"%S\\MSMQTest", mbsMachineName);
  99.     bstrPathName = SysAllocString(wcsPathName);
  100.     if (bstrPathName == NULL) {
  101.       PRINTERROR("OOM: pathname", E_OUTOFMEMORY);
  102.     }
  103.     pqinfo->put_PathName(bstrPathName);
  104.  
  105.     //
  106.     // Set the type of the queue
  107.     // (Will be used to locate all the queues of this type)
  108.     //
  109.     bstrServiceType = SysAllocString(strGuidMQTestType);
  110.     if (bstrServiceType == NULL) {
  111.       PRINTERROR("OOM: ServiceType", E_OUTOFMEMORY);
  112.     }
  113.     pqinfo->put_ServiceTypeGuid(bstrServiceType);
  114.  
  115.     //
  116.     // Put a description to the queue
  117.     // (Useful for administration through the MSMQ admin tools)
  118.     //
  119.     bstrLabel =
  120.       SysAllocString(L"Sample ActiveX application of MSMQ SDK");
  121.     if (bstrLabel == NULL) {
  122.       PRINTERROR("OOM: label ", E_OUTOFMEMORY);
  123.     }
  124.     pqinfo->put_Label(bstrLabel);
  125.  
  126.     //
  127.     // specify if transactional
  128.     //
  129.     VariantInit(&varIsTransactional);
  130.     varIsTransactional.vt = VT_BOOL;
  131.     varIsTransactional.boolVal = MQ_TRANSACTIONAL_NONE;
  132.     VariantInit(&varIsWorldReadable);
  133.     varIsWorldReadable.vt = VT_BOOL;
  134.     varIsWorldReadable.boolVal = FALSE;
  135.     //
  136.     // create the queue
  137.     //
  138.     hresult = pqinfo->Create(&varIsTransactional, &varIsWorldReadable);
  139.     if (FAILED(hresult)) {
  140.       //
  141.       // API Fails, not because the queue exists
  142.       //
  143.       if (hresult != MQ_ERROR_QUEUE_EXISTS) {
  144.         PRINTERROR("Cannot create queue", hresult);
  145.       }
  146.     }
  147.  
  148.     //
  149.     // Open the queue for receive access
  150.     //
  151.     hresult = pqinfo->Open(MQ_RECEIVE_ACCESS,
  152.                            MQ_DENY_NONE,
  153.                            &pqReceive);
  154.  
  155.     //
  156.     // Little bit tricky. MQCreateQueue succeeded but it does not mean
  157.     // that MQOpenQueue will, because of replication delay. The queue is
  158.     // registered in MQIS, but it might take a replication interval
  159.     // until the replica reach the server I am connected to.
  160.     // To overcome this, open the queue in a loop.
  161.     //
  162.     // (in this specific case, this can happen only if this
  163.     //  program is run on a Backup Server Controller - BSC, or on
  164.     //  a client connected to a BSC)
  165.     // To be totally on the safe side, we should have put some code
  166.     // to exit the loop after a few retries, but hey, this is just a sample.
  167.     //
  168.     while (hresult == MQ_ERROR_QUEUE_NOT_FOUND) {
  169.       printf(".");
  170.  
  171.       // Wait a bit
  172.       Sleep(500);
  173.  
  174.       // And retry
  175.       hresult = pqinfo->Open(MQ_RECEIVE_ACCESS,
  176.                              MQ_DENY_NONE,
  177.                              &pqReceive);
  178.     }
  179.     if (FAILED(hresult)) {
  180.       PRINTERROR("Cannot open queue", hresult);
  181.     }
  182.  
  183.     //
  184.     // Main receiver loop
  185.     //
  186.     printf("\nWaiting for messages...\n");
  187.     while (!fQuit) {
  188.       //
  189.       // Receive the message
  190.       //
  191.       VariantInit(&varWantDestQueue);
  192.       VariantInit(&varWantBody);
  193.       VariantInit(&varReceiveTimeout);
  194.       varWantDestQueue.vt = VT_BOOL;
  195.       varWantDestQueue.boolVal = TRUE;    // yes we want the dest queue
  196.       varWantBody.vt = VT_BOOL;
  197.       varWantBody.boolVal = TRUE;         // yes we want the msg body
  198.       varReceiveTimeout.vt = VT_I4;
  199.       varReceiveTimeout.lVal = INFINITE;  // infinite timeout
  200.       hresult = pqReceive->Receive(
  201.                   NULL,
  202.                   &varWantDestQueue,
  203.                   &varWantBody,
  204.                   &varReceiveTimeout,
  205.                   &pmessageReceive);
  206.       if (FAILED(hresult)) {
  207.         PRINTERROR("Receive message", hresult);
  208.       }
  209.  
  210.       //
  211.       // Display the received message
  212.       //
  213.       pmessageReceive->get_Label(&bstrMsgLabel);
  214.       VariantInit(&varBody);
  215.       VariantInit(&varBody2);
  216.       hresult = pmessageReceive->get_Body(&varBody);
  217.       if (FAILED(hresult)) {
  218.         PRINTERROR("can't get body", hresult);
  219.       }
  220.       hresult = VariantChangeType(&varBody2,
  221.                                   &varBody,
  222.                                   0,
  223.                                   VT_BSTR);
  224.       if (FAILED(hresult)) {
  225.         PRINTERROR("can't convert message to string.", hresult);
  226.       }
  227.       printf("%S : %s\n", bstrMsgLabel, V_BSTR(&varBody2));
  228.       //
  229.       // Check for end of app
  230.       //
  231.       if (stricmp((char *)V_BSTR(&varBody2), "quit") == 0) {
  232.         fQuit = TRUE;
  233.       }
  234.  
  235.       VariantClear(&varBody);
  236.       VariantClear(&varBody2);
  237.  
  238.       //
  239.       // release the current message
  240.       //
  241.       RELEASE(pmessageReceive);
  242.     } /* while (1) */
  243.  
  244.     //
  245.     // Cleanup - Close handle to the queue
  246.     //
  247.     pqReceive->Close();
  248.     if (FAILED(hresult)) {
  249.       PRINTERROR("Cannot close queue", hresult);
  250.     }
  251.  
  252.     //
  253.     // Finish - Let's delete the queue from the directory service
  254.     // (We don't need to do it. Leaving the queue in the DS, enables
  255.     //  sender applications to send messages even if the receiver is not
  256.     //  available.)
  257.     //
  258.     hresult = pqinfo->Delete();
  259.     if (FAILED(hresult)) {
  260.       PRINTERROR("Cannot delete queue", hresult);
  261.     }
  262.     // fall through...
  263.  
  264. Cleanup:
  265.     SysFreeString(bstrPathName);
  266.     SysFreeString(bstrMsgLabel);
  267.     SysFreeString(bstrServiceType);
  268.     SysFreeString(bstrLabel);
  269.     RELEASE(pmessageReceive);
  270.     RELEASE(pqReceive);
  271.     RELEASE(pqinfo);
  272.     return hresult;
  273. }
  274.  
  275.  
  276. //-----------------------------------------------------
  277. //
  278. // Sender Mode
  279. // -----------
  280. // The sender side does the following:
  281. //    1. Locates all queues of type "guidMQTestType"
  282. //    2. Opens handles to all the queues
  283. //    3. In a loop
  284. //          Sends messages to all those queues
  285. //    4. Cleanup handles
  286. //
  287. //-----------------------------------------------------
  288. HRESULT Sender()
  289. {
  290.     IMSMQQuery *pquery = NULL;
  291.     IMSMQQueueInfo *rgpqinfo[MAX_VAR];
  292.     IMSMQQueue *rgpqSend[MAX_VAR];
  293.     IMSMQQueueInfo *pqinfo = NULL;
  294.     IMSMQQueueInfos *pqinfos = NULL;
  295.     IMSMQMessage *pmessage = NULL;
  296.     char *szBuffer = new char[MAX_BUFFER];
  297.     WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
  298.     BSTR bstrServiceType = NULL;
  299.     BSTR bstrLabel = NULL;
  300.     BSTR bstrBody = NULL;
  301.     VARIANT varBody;
  302.     DWORD i;
  303.     DWORD cQueue = 0;
  304.     HRESULT hresult = NOERROR;
  305.  
  306.     printf("\nSender Mode on Machine: %s\n\n", mbsMachineName);
  307.  
  308.     //
  309.     // create query object for lookup
  310.     //
  311.     hresult = CoCreateInstance(
  312.                    CLSID_MSMQQuery,
  313.                    NULL,      // punkOuter
  314.                    CLSCTX_SERVER,
  315.                    IID_IMSMQQuery,
  316.                    (LPVOID *)&pquery);
  317.     if (FAILED(hresult)) {
  318.       PRINTERROR("Cannot create query", hresult);
  319.     }
  320.  
  321.     //
  322.     // Prepare parameters to locate a queue: all queues that
  323.     //  match test guid type
  324.     //
  325.     VARIANT varGuidQueue;
  326.     VARIANT varStrLabel;
  327.     VARIANT varGuidServiceType;
  328.     VARIANT varRelServiceType;
  329.     VARIANT varRelLabel;
  330.     VARIANT varCreateTime;
  331.     VARIANT varModifyTime;
  332.     VARIANT varRelCreateTime;
  333.     VARIANT varRelModifyTime;
  334.  
  335.     VariantInit(&varGuidQueue);
  336.     VariantInit(&varStrLabel);
  337.     VariantInit(&varGuidServiceType);
  338.     VariantInit(&varRelServiceType);
  339.     VariantInit(&varRelLabel);
  340.     VariantInit(&varCreateTime);
  341.     VariantInit(&varModifyTime);
  342.     VariantInit(&varRelCreateTime);
  343.     VariantInit(&varRelModifyTime);
  344.  
  345.     //
  346.     // We only want to specify service type so we set
  347.     //  the other variant params to VT_ERROR to simulate
  348.     //  "missing", i.e. optional, params.
  349.     //
  350.     V_VT(&varGuidQueue) = VT_ERROR;
  351.     V_VT(&varStrLabel) = VT_ERROR;
  352.     V_VT(&varRelServiceType) = VT_ERROR;
  353.     V_VT(&varRelLabel) = VT_ERROR;
  354.     V_VT(&varCreateTime) = VT_ERROR;
  355.     V_VT(&varModifyTime) = VT_ERROR;
  356.     V_VT(&varRelCreateTime) = VT_ERROR;
  357.     V_VT(&varRelModifyTime) = VT_ERROR;
  358.     bstrServiceType = SysAllocString(strGuidMQTestType);
  359.     if (bstrServiceType == NULL) {
  360.       PRINTERROR("OOM: Service Type", E_OUTOFMEMORY);
  361.     }
  362.     V_VT(&varGuidServiceType) = VT_BSTR;
  363.     V_BSTR(&varGuidServiceType) = bstrServiceType;
  364.  
  365.     hresult = pquery->LookupQueue(&varGuidQueue,
  366.                                   &varGuidServiceType,
  367.                                   &varStrLabel,
  368.                                   &varCreateTime,
  369.                                   &varModifyTime,
  370.                                   &varRelServiceType,
  371.                                   &varRelLabel,
  372.                                   &varRelCreateTime,
  373.                                   &varRelModifyTime,
  374.                                   &pqinfos);
  375.     if (FAILED(hresult)) {
  376.       PRINTERROR("LookupQueue failed", hresult);
  377.     }
  378.  
  379.     //
  380.     // reset the queue collection
  381.     //
  382.     hresult = pqinfos->Reset();
  383.     if (FAILED(hresult)) {
  384.       PRINTERROR("Reset failed", hresult);
  385.     }
  386.  
  387.     //
  388.     // Open each of the queues found
  389.     //
  390.     i = 0;
  391.     hresult = pqinfos->Next(&rgpqinfo[i]);
  392.     if (FAILED(hresult)) {
  393.       PRINTERROR("Next failed", hresult);
  394.     }
  395.     pqinfo = rgpqinfo[i];
  396.     while (pqinfo) {
  397.       //
  398.       // Open the queue for send access
  399.       //
  400.       hresult = pqinfo->Open(
  401.                   MQ_SEND_ACCESS,
  402.                   MQ_DENY_NONE,
  403.                   &rgpqSend[i]);
  404.       if (FAILED(hresult)) {
  405.         PRINTERROR("Open failed", hresult);
  406.       }
  407.       i++;
  408.       hresult = pqinfos->Next(&rgpqinfo[i]);
  409.       if (FAILED(hresult)) {
  410.         PRINTERROR("Next failed", hresult);
  411.       }
  412.       pqinfo = rgpqinfo[i];
  413.     }
  414.     cQueue = i;
  415.     if (cQueue == 0) {
  416.       //
  417.       // Could Not find any queue, so exit
  418.       //
  419.       PRINTERROR("No queue registered", hresult = E_INVALIDARG);
  420.     }
  421.     printf("\t%d queue(s) found.\n", cQueue);
  422.     printf("\nEnter \"quit\" to exit\n");
  423.  
  424.  
  425.     //
  426.     // Build the message label property
  427.     //
  428.     swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName);
  429.  
  430.  
  431.     //
  432.     // Main sender loop
  433.     //
  434.     while (1) {
  435.       //
  436.       // Get a string from the console
  437.       //
  438.       printf("Enter a string: ");
  439.       if (gets(szBuffer) == NULL)
  440.         break;
  441.  
  442.  
  443.       //
  444.       // create a message object
  445.       //
  446.       hresult = CoCreateInstance(
  447.                      CLSID_MSMQMessage,
  448.                      NULL,      // punkOuter
  449.                      CLSCTX_SERVER,
  450.                      IID_IMSMQMessage,
  451.                      (LPVOID *)&pmessage);
  452.       //
  453.       // Send the message to all the queues
  454.       //
  455.       for (i = 0; i < cQueue; i++) {
  456.         bstrLabel = SysAllocString(wcsMsgLabel);
  457.         if (bstrLabel == NULL) {
  458.           PRINTERROR("OOM: label", E_OUTOFMEMORY);
  459.         }
  460.         hresult = pmessage->put_Label(bstrLabel);
  461.  
  462.         //
  463.         // This isn't a "true" unicode string of course...
  464.         //
  465.         bstrBody = SysAllocStringByteLen(szBuffer, strlen(szBuffer)+1);
  466.         if (bstrBody == NULL) {
  467.           PRINTERROR("OOM: body", E_OUTOFMEMORY);
  468.         }
  469.         VariantInit(&varBody);
  470.         V_VT(&varBody) = VT_BSTR;
  471.         V_BSTR(&varBody) = bstrBody;
  472.         hresult = pmessage->put_Body(varBody);
  473.         if (FAILED(hresult)) {
  474.           PRINTERROR("put_body failed", hresult);
  475.         }
  476.         hresult = pmessage->Send(rgpqSend[i], NULL);
  477.         if (FAILED(hresult)) {
  478.           PRINTERROR("Send failed", hresult);
  479.         }
  480.         VariantClear(&varBody);
  481.         bstrBody = NULL;
  482.       }
  483.       RELEASE(pmessage);
  484.  
  485.       //
  486.       // Check for end of app
  487.       //
  488.       if (stricmp(szBuffer, "quit") == 0)
  489.         break;
  490.     } /* while (1) */
  491.  
  492.  
  493.  
  494. Cleanup:
  495.     //
  496.     // Close and release all the queues
  497.     //
  498.     for (i = 0; i < cQueue; i++) {
  499.       rgpqSend[i]->Close();
  500.       rgpqSend[i]->Release();
  501.       rgpqinfo[i]->Release();
  502.     }
  503.     RELEASE(pqinfos);
  504.     RELEASE(pquery);
  505.     RELEASE(pmessage);
  506.     SysFreeString(bstrLabel);
  507.     SysFreeString(bstrBody);
  508.     SysFreeString(bstrServiceType);
  509.     delete [] szBuffer;
  510.     return hresult;
  511. }
  512.  
  513.  
  514. //-----------------------------------------------------
  515. //
  516. //  MAIN
  517. //
  518. //-----------------------------------------------------
  519. int main(int argc, char * * argv)
  520. {
  521.     DWORD dwNumChars;
  522.     HRESULT hresult = NOERROR;
  523.  
  524.     if (argc != 2)
  525.       return Syntax();
  526.  
  527.     hresult = OleInitialize(NULL);
  528.     if (FAILED(hresult)) {
  529.       PRINTERROR("Cannot init OLE", hresult);
  530.     }
  531.  
  532.  
  533.     //
  534.     // Retrieve machine name
  535.     //
  536.     dwNumChars = MAX_COMPUTERNAME_LENGTH + 1;
  537.     GetComputerNameA(mbsMachineName, &dwNumChars);
  538.  
  539.  
  540.     if (strcmp(argv[1], "-s") == 0)
  541.       hresult = Sender();
  542.  
  543.     else if (strcmp(argv[1], "-r") == 0)
  544.       hresult = Receiver();
  545.  
  546.     else
  547.       hresult = Syntax();
  548.  
  549.     printf("\nOK\n");
  550.  
  551.     // fall through...
  552.  
  553.  
  554. Cleanup:
  555.     return (int)hresult;
  556. }
  557.  
  558.  
  559. void PrintError(char *s, HRESULT hr)
  560. {
  561.     printf("Cleanup: %s (0x%X)\n", s, hr);
  562. }
  563.  
  564.  
  565. HRESULT Syntax()
  566. {
  567.     printf("\n");
  568.     printf("Syntax: mqtestoa -s | -r\n");
  569.     printf("\t-s: Sender\n");
  570.     printf("\t-r: Receiver\n");
  571.     return E_INVALIDARG;
  572. }
  573.