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);
}