MSMQTEST.C
/******************************************************************************\ 
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1996 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 <stdio.h> 
#include <windows.h> 
 
 
// 
// Unique include file for MSMQ apps 
// 
#include "mq.h" 
 
 
// 
// Various defines 
// 
#define MAX_VAR       20 
#define MAX_FORMAT   100 
#define MAX_BUFFER   500 
 
 
// 
// 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]; 
 
 
//----------------------------------------------------- 
// 
// Receiver Mode 
// ------------- 
// The receiver side does the following: 
//    1. Creates a public queue on its own machine 
//       of type "guidMQTestType" 
//    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() 
{ 
 
    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 
    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"); 
 
        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 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 reach 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 
    // 
    printf("\nWaiting for messages...\n"); 
    while (1) 
    { 
        // 
        // 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. Leaving the queue 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: 
//    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. Cleanup handles 
// 
//----------------------------------------------------- 
void Sender() 
{ 
    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 
    // 
    while (1) 
    { 
        // 
        // 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; 
 
    } /* while (1) */ 
 
 
    // 
    // Close all the queue handles 
    // 
    for (i = 0; i < cQueue; i++) 
        MQCloseQueue(aqh[i]); 
 
} 
 
 
//----------------------------------------------------- 
// 
//  MAIN 
// 
//----------------------------------------------------- 
main(int argc, char * * argv) 
{ 
    DWORD dwNumChars; 
 
 
    if (argc != 2) 
        Syntax(); 
 
 
    // 
    // Retrieve machine name 
    // 
    dwNumChars = MAX_COMPUTERNAME_LENGTH + 1; 
    GetComputerName(mbsMachineName, &dwNumChars); 
 
 
    if (strcmp(argv[1], "-s") == 0) 
        Sender(); 
 
    else if (strcmp(argv[1], "-r") == 0) 
        Receiver(); 
 
    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); 
}