|
|
/******************************************************************************\
* 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 <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
#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); }
|