home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / msmqocm.cab / msmqtest.c < prev    next >
C/C++ Source or Header  |  1997-10-06  |  15KB  |  563 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. //
  20. // Unique include file for MSMQ apps
  21. //
  22. #include "mq.h"
  23.  
  24.  
  25. //
  26. // Various defines
  27. //
  28. #define MAX_VAR       20
  29. #define MAX_FORMAT   100
  30. #define MAX_BUFFER   500
  31.  
  32.  
  33. //
  34. // GUID created with the tool "GUIDGEN"
  35. //
  36. static CLSID guidMQTestType =
  37. { 0xc30e0960, 0xa2c0, 0x11cf, { 0x97, 0x85, 0x0, 0x60, 0x8c, 0xb3, 0xe8, 0xc } };
  38.  
  39.  
  40. //
  41. // Prototypes
  42. //
  43. void Error(char *s, HRESULT hr);
  44. void Syntax();
  45.  
  46.  
  47.  
  48. char mbsMachineName[MAX_COMPUTERNAME_LENGTH + 1];
  49.  
  50.  
  51. //-----------------------------------------------------
  52. //
  53. // Receiver Mode
  54. // -------------
  55. // The receiver side does the following:
  56. //    1. Creates a public queue on its own machine
  57. //       of type "guidMQTestType"
  58. //    2. Opens the queue
  59. //    3. In a Loop
  60. //          Receives messages
  61. //          Prints message body and message label
  62. //    4. Cleanup handles
  63. //    5. Deletes the queue from the directory service
  64. //
  65. //-----------------------------------------------------
  66. void Receiver()
  67. {
  68.  
  69.     MQQUEUEPROPS  qprops;
  70.     MQMSGPROPS    msgprops;
  71.     MQPROPVARIANT aPropVar[MAX_VAR];
  72.     QUEUEPROPID   aqPropId[MAX_VAR];
  73.     MSGPROPID     amPropId[MAX_VAR];
  74.     DWORD         cProps;
  75.  
  76.     WCHAR         wcsFormat[MAX_FORMAT];
  77.  
  78.     UCHAR         Buffer[MAX_BUFFER];
  79.     WCHAR         wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
  80.     WCHAR         wcsPathName[1000];
  81.  
  82.  
  83.     DWORD         dwNumChars;
  84.     QUEUEHANDLE   qh;
  85.  
  86.     HRESULT       hr;
  87.  
  88.  
  89.     printf("\nReceiver Mode on Machine: %s\n\n", mbsMachineName);
  90.  
  91.  
  92.     //
  93.     // Prepare properties to create a queue on local machine
  94.     //
  95.     cProps = 0;
  96.  
  97.     // Set the PathName
  98.     swprintf(wcsPathName, L"%S\\MSMQTest", mbsMachineName);
  99.     aqPropId[cProps]         = PROPID_Q_PATHNAME;
  100.     aPropVar[cProps].vt      = VT_LPWSTR;
  101.     aPropVar[cProps].pwszVal = wcsPathName;
  102.     cProps++;
  103.  
  104.     // Set the type of the queue
  105.     // (Will be used to locate all the queues of this type)
  106.     aqPropId[cProps]         = PROPID_Q_TYPE;
  107.     aPropVar[cProps].vt      = VT_CLSID;
  108.     aPropVar[cProps].puuid   = &guidMQTestType;
  109.     cProps++;
  110.  
  111.     // Put a description to the queue
  112.     // (Useful for administration through the MSMQ admin tools)
  113.     aqPropId[cProps]         = PROPID_Q_LABEL;
  114.     aPropVar[cProps].vt      = VT_LPWSTR;
  115.     aPropVar[cProps].pwszVal = L"Sample application of MSMQ SDK";
  116.     cProps++;
  117.  
  118.     // Create a QUEUEPROPS structure
  119.     qprops.cProp    = cProps;
  120.     qprops.aPropID  = aqPropId;
  121.     qprops.aPropVar = aPropVar;
  122.     qprops.aStatus  = 0;
  123.  
  124.  
  125.     //
  126.     // Create the queue
  127.     //
  128.     dwNumChars = MAX_FORMAT;
  129.     hr = MQCreateQueue(
  130.             NULL,           // IN:     Default security
  131.             &qprops,        // IN/OUT: Queue properties
  132.             wcsFormat,      // OUT:    Format name (OUT)
  133.             &dwNumChars);   // IN/OUT: Size of format name
  134.  
  135.     if (FAILED(hr))
  136.     {
  137.         //
  138.         // API Fails, not because the queue exists
  139.         //
  140.         if (hr != MQ_ERROR_QUEUE_EXISTS)
  141.             Error("Cannot create queue", hr);
  142.  
  143.         //
  144.         // Queue exist, so get its format name
  145.         //
  146.         printf("Queue already exists. Open it anyway.\n");
  147.  
  148.         dwNumChars = MAX_FORMAT;
  149.         hr = MQPathNameToFormatName(
  150.                    wcsPathName,     // IN:     Queue pathname
  151.                    wcsFormat,       // OUT:    Format name
  152.                    &dwNumChars);    // IN/OUT: Size of format name
  153.  
  154.         if (FAILED(hr))
  155.             Error("Cannot retrieve format name", hr);
  156.     }
  157.  
  158.  
  159.     //
  160.     // Open the queue for receive access
  161.     //
  162.     hr = MQOpenQueue(
  163.              wcsFormat,          // IN:  Queue format name
  164.              MQ_RECEIVE_ACCESS,  // IN:  Want to receive from queue
  165.              0,                  // IN:  Allow sharing
  166.              &qh);               // OUT: Handle of open queue
  167.  
  168.     //
  169.     // Little bit tricky. MQCreateQueue succeeded but it does not mean
  170.     // that MQOpenQueue will, because of replication delay. The queue is
  171.     // registered in MQIS, but it might take a replication interval
  172.     // until the replica reach the server I am connected to.
  173.     // To overcome this, open the queue in a loop.
  174.     //
  175.     // (in this specific case, this can happen only if this
  176.     //  program is run on a Backup Server Controller - BSC, or on
  177.     //  a client connected to a BSC)
  178.     // To be totally on the safe side, we should have put some code
  179.     // to exit the loop after a few retries, but hey, this is just a sample.
  180.     //
  181.     while (hr == MQ_ERROR_QUEUE_NOT_FOUND)
  182.     {
  183.        printf(".");
  184.  
  185.        // Wait a bit
  186.        Sleep(500);
  187.  
  188.        // And retry
  189.        hr = MQOpenQueue(wcsFormat, MQ_RECEIVE_ACCESS, 0, &qh);
  190.     }
  191.  
  192.     if (FAILED(hr))
  193.          Error("Cannot open queue", hr);
  194.  
  195.  
  196.     //
  197.     // Main receiver loop
  198.     //
  199.     printf("\nWaiting for messages...\n");
  200.     while (1)
  201.     {
  202.         //
  203.         // Prepare message properties to read
  204.         //
  205.         cProps = 0;
  206.  
  207.         // Ask for the body of the message
  208.         amPropId[cProps]            = PROPID_M_BODY;
  209.         aPropVar[cProps].vt         = VT_UI1 | VT_VECTOR;
  210.         aPropVar[cProps].caub.cElems = sizeof(Buffer);
  211.         aPropVar[cProps].caub.pElems = Buffer;
  212.         cProps++;
  213.  
  214.         // Ask for the label of the message
  215.         amPropId[cProps]         = PROPID_M_LABEL;
  216.         aPropVar[cProps].vt      = VT_LPWSTR;
  217.         aPropVar[cProps].pwszVal = wcsMsgLabel;
  218.         cProps++;
  219.  
  220.         // Ask for the length of the label of the message
  221.         amPropId[cProps]         = PROPID_M_LABEL_LEN;
  222.         aPropVar[cProps].vt      = VT_UI4;
  223.         aPropVar[cProps].ulVal   = MQ_MAX_MSG_LABEL_LEN;
  224.         cProps++;
  225.  
  226.         // Create a MSGPROPS structure
  227.         msgprops.cProp    = cProps;
  228.         msgprops.aPropID  = amPropId;
  229.         msgprops.aPropVar = aPropVar;
  230.         msgprops.aStatus  = 0;
  231.  
  232.  
  233.         //
  234.         // Receive the message
  235.         //
  236.         hr = MQReceiveMessage(
  237.                qh,                // IN:     Queue handle
  238.                INFINITE,          // IN:     Timeout
  239.                MQ_ACTION_RECEIVE, // IN:     Read operation
  240.                &msgprops,         // IN/OUT: Message properties to receive
  241.                NULL,              // IN/OUT: No overlap
  242.                NULL,              // IN:     No callback
  243.                NULL,              // IN:     No cursor
  244.                NULL);           // IN:     Not part of a transaction
  245.  
  246.         if (FAILED(hr))
  247.             Error("Receive message", hr);
  248.  
  249.         //
  250.         // Display the received message
  251.         //
  252.         printf("%S : %s\n", wcsMsgLabel, Buffer);
  253.  
  254.         //
  255.         // Check for end of app
  256.         //
  257.         if (stricmp(Buffer, "quit") == 0)
  258.             break;
  259.  
  260.     } /* while (1) */
  261.  
  262.     //
  263.     // Cleanup - Close handle to the queue
  264.     //
  265.     MQCloseQueue(qh);
  266.  
  267.  
  268.     //
  269.     // Finish - Let's delete the queue from the directory service
  270.     // (We don't need to do it. Leaving the queue in the DS, enables
  271.     //  sender applications to send messages even if the receiver is not
  272.     //  available.)
  273.     //
  274.     hr = MQDeleteQueue(wcsFormat);
  275.     if (FAILED(hr))
  276.         Error("Cannot delete queue", hr);
  277. }
  278.  
  279.  
  280. //-----------------------------------------------------
  281. //
  282. // Sender Mode
  283. // -----------
  284. // The sender side does the following:
  285. //    1. Locates all queues of type "guidMQTestType"
  286. //    2. Opens handles to all the queues
  287. //    3. In a loop
  288. //          Sends messages to all those queues
  289. //    4. Cleanup handles
  290. //
  291. //-----------------------------------------------------
  292. void Sender()
  293. {
  294.     DWORD         cProps;
  295.  
  296.     MQMSGPROPS    msgprops;
  297.     MQPROPVARIANT aPropVar[MAX_VAR];
  298.     QUEUEPROPID   aqPropId[MAX_VAR];
  299.     MSGPROPID     amPropId[MAX_VAR];
  300.  
  301.     MQPROPERTYRESTRICTION aPropRestriction[MAX_VAR];
  302.     MQRESTRICTION Restriction;
  303.  
  304.     MQCOLUMNSET      Column;
  305.     HANDLE        hEnum;
  306.  
  307.     WCHAR         wcsFormat[MAX_FORMAT];
  308.  
  309.     UCHAR         Buffer[MAX_BUFFER];
  310.     WCHAR         wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
  311.  
  312.     DWORD         i;
  313.  
  314.     DWORD         cQueue;
  315.     DWORD         dwNumChars;
  316.     QUEUEHANDLE   aqh[MAX_VAR];
  317.  
  318.     HRESULT       hr;
  319.  
  320.  
  321.     printf("\nSender Mode on Machine: %s\n\n", mbsMachineName);
  322.  
  323.  
  324.     //
  325.     // Prepare parameters to locate a queue
  326.     //
  327.  
  328.     //
  329.     // 1. Restriction = Queues with PROPID_TYPE = MSMQTest queue type
  330.     //
  331.     cProps = 0;
  332.     aPropRestriction[cProps].rel         = PREQ;
  333.     aPropRestriction[cProps].prop        = PROPID_Q_TYPE;
  334.     aPropRestriction[cProps].prval.vt    = VT_CLSID;
  335.     aPropRestriction[cProps].prval.puuid = &guidMQTestType;
  336.     cProps++;
  337.  
  338.     Restriction.cRes      = cProps;
  339.     Restriction.paPropRes = aPropRestriction;
  340.  
  341.  
  342.     //
  343.     // 2. Columnset (i.e. queue properties to retrieve) = queue instance
  344.     //
  345.     cProps = 0;
  346.     aqPropId[cProps] = PROPID_Q_INSTANCE;
  347.     cProps++;
  348.  
  349.     Column.cCol = cProps;
  350.     Column.aCol = aqPropId;
  351.  
  352.  
  353.     //
  354.     // Locate the queues. Issue the query
  355.     //
  356.     hr = MQLocateBegin(
  357.              NULL,          // IN:  Context must be NULL
  358.              &Restriction,  // IN:  Restriction
  359.              &Column,       // IN:  Columns (properties) to return
  360.              NULL,          // IN:  No need to sort
  361.              &hEnum);       // OUT: Enumeration handle
  362.  
  363.     if (FAILED(hr))
  364.         Error("LocateBegin", hr);
  365.  
  366.     //
  367.     // Get the results (up to MAX_VAR)
  368.     // (For more results, call MQLocateNext in a loop)
  369.     //
  370.     cQueue = MAX_VAR;
  371.     hr = MQLocateNext(
  372.              hEnum,         // IN:     Enumeration handle
  373.              &cQueue,       // IN/OUT: Count of properties
  374.              aPropVar);     // OUT:    Properties of located queues
  375.  
  376.     if (FAILED(hr))
  377.         Error("LocateNext", hr);
  378.  
  379.     //
  380.     // And that's it for locate
  381.     //
  382.     hr = MQLocateEnd(hEnum);
  383.  
  384.     if (cQueue == 0)
  385.     {
  386.         //
  387.         // Could Not find any queue, so exit
  388.         //
  389.         printf("No queue registered");
  390.         exit(0);
  391.     }
  392.  
  393.  
  394.     printf("\t%d queue(s) found.\n", cQueue);
  395.  
  396.  
  397.     //
  398.     // Open a handle for each of the queues found
  399.     //
  400.     for (i = 0; i < cQueue; i++)
  401.     {
  402.         // Convert the queue instance to a format name
  403.         dwNumChars = MAX_FORMAT;
  404.         hr = MQInstanceToFormatName(
  405.                   aPropVar[i].puuid,    // IN:     Queue instance
  406.                   wcsFormat,            // OUT:    Format name
  407.                   &dwNumChars);         // IN/OUT: Size of format name
  408.  
  409.         if (FAILED(hr))
  410.             Error("GuidToFormatName", hr);
  411.  
  412.         //
  413.         // Open the queue for send access
  414.         //
  415.         hr = MQOpenQueue(
  416.                  wcsFormat,           // IN:  Queue format name
  417.                  MQ_SEND_ACCESS,      // IN:  Want to send to queue
  418.                  0,                   // IN:  Must be 0 for send access
  419.                  &aqh[i]);            // OUT: Handle of open queue
  420.  
  421.         if (FAILED(hr))
  422.             Error("OpenQueue", hr);
  423.  
  424.         //
  425.         // Free the GUID memory that was allocated during the locate.
  426.         //
  427.         MQFreeMemory(aPropVar[i].puuid);
  428.     }
  429.  
  430.  
  431.     printf("\nEnter \"quit\" to exit\n");
  432.  
  433.  
  434.     //
  435.     // Build the message label property
  436.     //
  437.     swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName);
  438.  
  439.  
  440.     //
  441.     // Main sender loop
  442.     //
  443.     while (1)
  444.     {
  445.         //
  446.         // Get a string from the console
  447.         //
  448.         printf("Enter a string: ");
  449.         if (gets(Buffer) == NULL)
  450.             break;
  451.  
  452.  
  453.         //
  454.         // Prepare properties of message to send
  455.         //
  456.         cProps = 0;
  457.  
  458.         // Set the body of the message
  459.         amPropId[cProps]            = PROPID_M_BODY;
  460.         aPropVar[cProps].vt         = VT_UI1 | VT_VECTOR;
  461.         aPropVar[cProps].caub.cElems = sizeof(Buffer);
  462.         aPropVar[cProps].caub.pElems = Buffer;
  463.         cProps++;
  464.  
  465.         // Set the label of the message
  466.         amPropId[cProps]            = PROPID_M_LABEL;
  467.         aPropVar[cProps].vt         = VT_LPWSTR;
  468.         aPropVar[cProps].pwszVal    = wcsMsgLabel;
  469.         cProps++;
  470.  
  471.         // Create a MSGPROPS structure
  472.         msgprops.cProp    = cProps;
  473.         msgprops.aPropID  = amPropId;
  474.         msgprops.aPropVar = aPropVar;
  475.         msgprops.aStatus  = 0;
  476.  
  477.  
  478.         //
  479.         // Send the message to all the queue
  480.         //
  481.         for (i = 0; i < cQueue; i++)
  482.         {
  483.             hr = MQSendMessage(
  484.                     aqh[i],     // IN: Queue handle
  485.                     &msgprops,  // IN: Message properties to send
  486.                     NULL);      // IN: Not part of a transaction
  487.  
  488.             if (FAILED(hr))
  489.                 Error("Send message", hr);
  490.         }
  491.  
  492.         //
  493.         // Check for end of app
  494.         //
  495.         if (stricmp(Buffer, "quit") == 0)
  496.             break;
  497.  
  498.     } /* while (1) */
  499.  
  500.  
  501.     //
  502.     // Close all the queue handles
  503.     //
  504.     for (i = 0; i < cQueue; i++)
  505.         MQCloseQueue(aqh[i]);
  506.  
  507. }
  508.  
  509.  
  510. //-----------------------------------------------------
  511. //
  512. //  MAIN
  513. //
  514. //-----------------------------------------------------
  515. main(int argc, char * * argv)
  516. {
  517.     DWORD dwNumChars;
  518.  
  519.  
  520.     if (argc != 2)
  521.         Syntax();
  522.  
  523.  
  524.     //
  525.     // Retrieve machine name
  526.     //
  527.     dwNumChars = MAX_COMPUTERNAME_LENGTH + 1;
  528.     GetComputerName(mbsMachineName, &dwNumChars);
  529.  
  530.  
  531.     if (strcmp(argv[1], "-s") == 0)
  532.         Sender();
  533.  
  534.     else if (strcmp(argv[1], "-r") == 0)
  535.         Receiver();
  536.  
  537.     else
  538.         Syntax();
  539.  
  540.  
  541.     printf("\nOK\n");
  542.  
  543.  
  544.     return(1);
  545. }
  546.  
  547.  
  548. void Error(char *s, HRESULT hr)
  549. {
  550.     printf("Error: %s (0x%X)\n", s, hr);
  551.     exit(1);
  552. }
  553.  
  554.  
  555. void Syntax()
  556. {
  557.     printf("\n");
  558.     printf("Syntax: msmqtest -s | -r\n");
  559.     printf("\t-s: Sender\n");
  560.     printf("\t-r: Receiver\n");
  561.     exit(1);
  562. }
  563.