|
|
/******************************************************************************\
* 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 ActiveX MSMQ apps
//
#include <mqoai.h>
//
// Various defines
//
#define MAX_VAR 20
#define MAX_BUFFER 500
//
// GUID created with the tool "GUIDGEN"
//
static WCHAR strGuidMQTestType[] = L"{c30e0960-a2c0-11cf-9785-00608cb3e80c}"; //
// Prototypes
//
void PrintError(char *s, HRESULT hr); HRESULT Syntax();
char mbsMachineName[MAX_COMPUTERNAME_LENGTH + 1];
// Some useful macros
#define RELEASE(punk) if (punk) { (punk)->Release(); (punk) = NULL; }
#define ADDREF(punk) ((punk) ? (punk)->AddRef() : 0)
#define PRINTERROR(s, hr) { PrintError(s, hr); goto Cleanup; }
//-----------------------------------------------------
//
// Check if local computer is DS enabled or DS disabled
//
//-----------------------------------------------------
short DetectDsConnection(void) { IMSMQApplication2 *pqapp = NULL; short fDsConnection; HRESULT hresult;
hresult = CoCreateInstance( CLSID_MSMQApplication, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQApplication2, (LPVOID *)&pqapp); if (FAILED(hresult)) PRINTERROR("Cannot create application", hresult);
pqapp->get_IsDsEnabled(&fDsConnection); Cleanup: RELEASE(pqapp); return fDsConnection; }
//-----------------------------------------------------
//
// Allow a DS enabled client connect with a
// DS disabled one.
//
//-----------------------------------------------------
bool SetConnectionMode(void) {
char cDirectMode;
//
// In case the local computer is DS enabled,
// we have two cases:
// 1. Other side is a DS enabled computer.
// 2. Other side is a DS disabled computer.
//
if(DetectDsConnection() != 0) { printf("Do you wish to connect with a DS disabled computer (y or n) ? "); scanf("%c", &cDirectMode); switch(tolower(cDirectMode)) { case 'y': return true;
case 'n': return false;
default: printf("Bye.\n"); exit(1); } } return true; // 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
//
//--------------------------------------------------------
HRESULT Receiver(bool fDirectMode) { IMSMQMessage *pmessageReceive = NULL; IMSMQQueue *pqReceive = NULL; IMSMQQueueInfo *pqinfo = NULL; BSTR bstrPathName = NULL; BSTR bstrServiceType = NULL; BSTR bstrLabel = NULL; BSTR bstrMsgLabel = NULL; VARIANT varIsTransactional, varIsWorldReadable, varBody, varBody2, varWantDestQueue, varWantBody, varReceiveTimeout; WCHAR wcsPathName[1000]; BOOL fQuit = FALSE; HRESULT hresult = NOERROR;
printf("\nReceiver Mode on Machine: %s\n\n", mbsMachineName);
//
// Create MSMQQueueInfo object
//
hresult = CoCreateInstance( CLSID_MSMQQueueInfo, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQQueueInfo, (LPVOID *)&pqinfo); if (FAILED(hresult)) { PRINTERROR("Cannot create queue", hresult); }
//
// Prepare properties to create a queue on local machine
//
// Set the PathName
if(fDirectMode) // Private queue pathname
{ swprintf(wcsPathName, L"%S\\private$\\MSMQTest", mbsMachineName); } else // Public queue pathname
{ swprintf(wcsPathName, L"%S\\MSMQTest", mbsMachineName); }
bstrPathName = SysAllocString(wcsPathName); if (bstrPathName == NULL) { PRINTERROR("OOM: pathname", E_OUTOFMEMORY); } pqinfo->put_PathName(bstrPathName);
//
// Set the type of the queue
// (Will be used to locate all the queues of this type)
//
bstrServiceType = SysAllocString(strGuidMQTestType); if (bstrServiceType == NULL) { PRINTERROR("OOM: ServiceType", E_OUTOFMEMORY); } pqinfo->put_ServiceTypeGuid(bstrServiceType);
//
// Put a description to the queue
// (Useful for administration through the MSMQ admin tools)
//
bstrLabel = SysAllocString(L"Sample ActiveX application of MSMQ SDK"); if (bstrLabel == NULL) { PRINTERROR("OOM: label ", E_OUTOFMEMORY); } pqinfo->put_Label(bstrLabel);
//
// specify if transactional
//
VariantInit(&varIsTransactional); varIsTransactional.vt = VT_BOOL; varIsTransactional.boolVal = MQ_TRANSACTIONAL_NONE; VariantInit(&varIsWorldReadable); varIsWorldReadable.vt = VT_BOOL; varIsWorldReadable.boolVal = FALSE; //
// create the queue
//
hresult = pqinfo->Create(&varIsTransactional, &varIsWorldReadable); if (FAILED(hresult)) { //
// API Fails, not because the queue exists
//
if (hresult != MQ_ERROR_QUEUE_EXISTS) PRINTERROR("Cannot create queue", hresult); }
//
// Open the queue for receive access
//
hresult = pqinfo->Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE, &pqReceive);
//
// 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 (hresult == MQ_ERROR_QUEUE_NOT_FOUND) { printf(".");
// Wait a bit
Sleep(500);
// And retry
hresult = pqinfo->Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE, &pqReceive); } if (FAILED(hresult)) { PRINTERROR("Cannot open queue", hresult); }
//
// Main receiver loop
//
printf("\nWaiting for messages...\n"); while (!fQuit) { //
// Receive the message
//
VariantInit(&varWantDestQueue); VariantInit(&varWantBody); VariantInit(&varReceiveTimeout); varWantDestQueue.vt = VT_BOOL; varWantDestQueue.boolVal = TRUE; // yes we want the dest queue
varWantBody.vt = VT_BOOL; varWantBody.boolVal = TRUE; // yes we want the msg body
varReceiveTimeout.vt = VT_I4; varReceiveTimeout.lVal = INFINITE; // infinite timeout
hresult = pqReceive->Receive( NULL, &varWantDestQueue, &varWantBody, &varReceiveTimeout, &pmessageReceive); if (FAILED(hresult)) { PRINTERROR("Receive message", hresult); }
//
// Display the received message
//
pmessageReceive->get_Label(&bstrMsgLabel); VariantInit(&varBody); VariantInit(&varBody2); hresult = pmessageReceive->get_Body(&varBody); if (FAILED(hresult)) { PRINTERROR("can't get body", hresult); } hresult = VariantChangeType(&varBody2, &varBody, 0, VT_BSTR); if (FAILED(hresult)) { PRINTERROR("can't convert message to string.", hresult); } printf("%S : %s\n", bstrMsgLabel, V_BSTR(&varBody2)); //
// Check for end of app
//
if (stricmp((char *)V_BSTR(&varBody2), "quit") == 0) { fQuit = TRUE; }
VariantClear(&varBody); VariantClear(&varBody2);
//
// release the current message
//
RELEASE(pmessageReceive); } /* while (!fQuit) */
//
// Cleanup - Close handle to the queue
//
pqReceive->Close(); if (FAILED(hresult)) { PRINTERROR("Cannot close queue", hresult); }
//
// 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.)
//
hresult = pqinfo->Delete(); if (FAILED(hresult)) { PRINTERROR("Cannot delete queue", hresult); } // fall through...
Cleanup: SysFreeString(bstrPathName); SysFreeString(bstrMsgLabel); SysFreeString(bstrServiceType); SysFreeString(bstrLabel); RELEASE(pmessageReceive); RELEASE(pqReceive); RELEASE(pqinfo); return hresult; }
//-----------------------------------------------------
//
// 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
//
//-----------------------------------------------------
HRESULT StandardSender() { IMSMQQuery *pquery = NULL; IMSMQQueueInfo *rgpqinfo[MAX_VAR]; IMSMQQueue *rgpqSend[MAX_VAR]; IMSMQQueueInfo *pqinfo = NULL; IMSMQQueueInfos *pqinfos = NULL; IMSMQMessage *pmessage = NULL; char szBuffer[MAX_BUFFER]; WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN]; BSTR bstrServiceType = NULL; BSTR bstrLabel = NULL; BSTR bstrBody = NULL; VARIANT varBody; DWORD i; DWORD cQueue = 0; HRESULT hresult = NOERROR;
printf("\nSender Mode on Machine: %s\n\n", mbsMachineName);
//
// create query object for lookup
//
hresult = CoCreateInstance( CLSID_MSMQQuery, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQQuery, (LPVOID *)&pquery); if (FAILED(hresult)) { PRINTERROR("Cannot create query", hresult); }
//
// Prepare parameters to locate a queue: all queues that
// match test guid type
//
VARIANT varGuidQueue; VARIANT varStrLabel; VARIANT varGuidServiceType; VARIANT varRelServiceType; VARIANT varRelLabel; VARIANT varCreateTime; VARIANT varModifyTime; VARIANT varRelCreateTime; VARIANT varRelModifyTime;
VariantInit(&varGuidQueue); VariantInit(&varStrLabel); VariantInit(&varGuidServiceType); VariantInit(&varRelServiceType); VariantInit(&varRelLabel); VariantInit(&varCreateTime); VariantInit(&varModifyTime); VariantInit(&varRelCreateTime); VariantInit(&varRelModifyTime);
//
// We only want to specify service type so we set
// the other variant params to VT_ERROR to simulate
// "missing", i.e. optional, params.
//
V_VT(&varGuidQueue) = VT_ERROR; V_VT(&varStrLabel) = VT_ERROR; V_VT(&varRelServiceType) = VT_ERROR; V_VT(&varRelLabel) = VT_ERROR; V_VT(&varCreateTime) = VT_ERROR; V_VT(&varModifyTime) = VT_ERROR; V_VT(&varRelCreateTime) = VT_ERROR; V_VT(&varRelModifyTime) = VT_ERROR; bstrServiceType = SysAllocString(strGuidMQTestType); if (bstrServiceType == NULL) { PRINTERROR("OOM: Service Type", E_OUTOFMEMORY); } V_VT(&varGuidServiceType) = VT_BSTR; V_BSTR(&varGuidServiceType) = bstrServiceType;
hresult = pquery->LookupQueue(&varGuidQueue, &varGuidServiceType, &varStrLabel, &varCreateTime, &varModifyTime, &varRelServiceType, &varRelLabel, &varRelCreateTime, &varRelModifyTime, &pqinfos); if (FAILED(hresult)) { PRINTERROR("LookupQueue failed", hresult); }
//
// reset the queue collection
//
hresult = pqinfos->Reset(); if (FAILED(hresult)) { PRINTERROR("Reset failed", hresult); }
//
// Open each of the queues found
//
i = 0; hresult = pqinfos->Next(&rgpqinfo[i]); if (FAILED(hresult)) { PRINTERROR("Next failed", hresult); } pqinfo = rgpqinfo[i]; while (pqinfo) { //
// Open the queue for send access
//
hresult = pqinfo->Open( MQ_SEND_ACCESS, MQ_DENY_NONE, &rgpqSend[i]); if (FAILED(hresult)) { PRINTERROR("Open failed", hresult); } i++; hresult = pqinfos->Next(&rgpqinfo[i]); if (FAILED(hresult)) { PRINTERROR("Next failed", hresult); } pqinfo = rgpqinfo[i]; } cQueue = i; if (cQueue == 0) { //
// Could Not find any queue, so exit
//
PRINTERROR("No queue registered", hresult = E_INVALIDARG); } printf("\t%d queue(s) found.\n", cQueue); printf("\nEnter \"quit\" to exit\n");
//
// Build the message label property
//
swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName); bstrLabel = SysAllocString(wcsMsgLabel); if (bstrLabel == NULL) PRINTERROR("OOM: label", E_OUTOFMEMORY);
fflush(stdin); //
// Main sender loop
//
while (1) { //
// Get a string from the console
//
printf("Enter a string: "); if (gets(szBuffer) == NULL) break;
//
// create a message object
//
hresult = CoCreateInstance( CLSID_MSMQMessage, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQMessage, (LPVOID *)&pmessage); //
// Send the message to all the queues
//
for (i = 0; i < cQueue; i++) { hresult = pmessage->put_Label(bstrLabel);
//
// This isn't a "true" unicode string of course...
//
bstrBody = SysAllocStringByteLen(szBuffer, strlen(szBuffer)+1); if (bstrBody == NULL) { PRINTERROR("OOM: body", E_OUTOFMEMORY); } VariantInit(&varBody); V_VT(&varBody) = VT_BSTR; V_BSTR(&varBody) = bstrBody; hresult = pmessage->put_Body(varBody); if (FAILED(hresult)) { PRINTERROR("put_body failed", hresult); } hresult = pmessage->Send(rgpqSend[i], NULL); if (FAILED(hresult)) { PRINTERROR("Send failed", hresult); } VariantClear(&varBody); bstrBody = NULL; } RELEASE(pmessage);
//
// Check for end of app
//
if (stricmp(szBuffer, "quit") == 0) break; } /* while (1) */
Cleanup: //
// Close and release all the queues
//
for (i = 0; i < cQueue; i++) { rgpqSend[i]->Close(); rgpqSend[i]->Release(); rgpqinfo[i]->Release(); } RELEASE(pqinfos); RELEASE(pquery); RELEASE(pmessage); SysFreeString(bstrLabel); SysFreeString(bstrBody); SysFreeString(bstrServiceType); return hresult; }
//-----------------------------------------------------
//
// Sender in DIRECT mode
//
//-----------------------------------------------------
HRESULT DirectSender(void) { IMSMQQueue *rgpqSend; IMSMQQueueInfo *pqinfo = NULL; IMSMQMessage *pmessage = NULL; char szBuffer[MAX_BUFFER]; WCHAR wcsMsgLabel[MQ_MAX_MSG_LABEL_LEN]; WCHAR wcsFormat[MAX_BUFFER]; WCHAR wcsReceiverComputer[MAX_BUFFER]; BSTR bstrFormat = NULL; BSTR bstrServiceType = NULL; BSTR bstrLabel = NULL; BSTR bstrBody = NULL; VARIANT varBody; DWORD cQueue = 0; HRESULT hresult = NOERROR;
//
// Get the receiver computer name
//
printf("\nEnter receiver computer name: "); wscanf(L"%s", wcsReceiverComputer); if(wcsReceiverComputer[0] == 0) { printf("You have entered an incorrect parameter. Exiting...\n"); return E_INVALIDARG; }
hresult = CoCreateInstance( CLSID_MSMQQueueInfo, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQQueueInfo, (LPVOID *)&pqinfo); if (FAILED(hresult)) PRINTERROR("Cannot open queue", hresult);
swprintf(wcsFormat, L"DIRECT=OS:%s\\private$\\MSMQTest", wcsReceiverComputer); bstrFormat = SysAllocString(wcsFormat); hresult = pqinfo->put_FormatName(bstrFormat); if (FAILED(hresult)) PRINTERROR("Open failed", hresult);
//
// Open the queue for send access
//
hresult = pqinfo->Open( MQ_SEND_ACCESS, MQ_DENY_NONE, &rgpqSend); if (FAILED(hresult)) PRINTERROR("Open failed", hresult);
printf("\nSender Mode on Machine: %s\n\n", mbsMachineName); printf("\nEnter \"quit\" to exit\n");
//
// Build the message label property
//
swprintf(wcsMsgLabel, L"Message from %S", mbsMachineName); bstrLabel = SysAllocString(wcsMsgLabel); if (bstrLabel == NULL) PRINTERROR("OOM: label", E_OUTOFMEMORY);
fflush(stdin); //
// Main sender loop
//
while (1) { //
// Get a string from the console
//
printf("Enter a string: "); if (gets(szBuffer) == NULL) break;
//
// create a message object
//
hresult = CoCreateInstance( CLSID_MSMQMessage, NULL, // punkOuter
CLSCTX_SERVER, IID_IMSMQMessage, (LPVOID *)&pmessage); //
// Send the message
//
hresult = pmessage->put_Label(bstrLabel);
bstrBody = SysAllocStringByteLen(szBuffer, strlen(szBuffer)+1); if (bstrBody == NULL) PRINTERROR("OOM: body", E_OUTOFMEMORY);
VariantInit(&varBody); V_VT(&varBody) = VT_BSTR; V_BSTR(&varBody) = bstrBody; hresult = pmessage->put_Body(varBody); if (FAILED(hresult)) PRINTERROR("put_body failed", hresult);
hresult = pmessage->Send(rgpqSend, NULL); if (FAILED(hresult)) PRINTERROR("Send failed", hresult);
VariantClear(&varBody); bstrBody = NULL;
RELEASE(pmessage);
//
// Check for end of app
//
if (stricmp(szBuffer, "quit") == 0) break; } /* while (1) */
Cleanup: rgpqSend->Close(); rgpqSend->Release(); RELEASE(pqinfo); RELEASE(pmessage); SysFreeString(bstrFormat); SysFreeString(bstrLabel); SysFreeString(bstrBody); SysFreeString(bstrServiceType); return hresult; }
//------------------------------------------------------
//
// Sender function
//
//------------------------------------------------------
HRESULT Sender(int fDirectMode) {
if(fDirectMode != 0) return DirectSender();
else return StandardSender(); }
//-----------------------------------------------------
//
// MAIN
//
//-----------------------------------------------------
int main(int argc, char * * argv) { DWORD dwNumChars; HRESULT hresult = NOERROR; bool fDirectMode;
if (argc != 2) return Syntax();
hresult = OleInitialize(NULL); if (FAILED(hresult)) PRINTERROR("Cannot init OLE", hresult);
//
// Retrieve machine name
//
dwNumChars = MAX_COMPUTERNAME_LENGTH + 1; GetComputerNameA(mbsMachineName, &dwNumChars);
//
// Detect DS connection and working mode
//
fDirectMode = SetConnectionMode();
if (strcmp(argv[1], "-s") == 0) hresult = Sender(fDirectMode);
else if (strcmp(argv[1], "-r") == 0) hresult = Receiver(fDirectMode);
else hresult = Syntax();
printf("\nOK\n");
// fall through...
Cleanup: return (int)hresult; }
void PrintError(char *s, HRESULT hr) { printf("Cleanup: %s (0x%X)\n", s, hr); }
HRESULT Syntax() { printf("\n"); printf("Syntax: mqtestoa -s | -r\n"); printf("\t-s: Sender\n"); printf("\t-r: Receiver\n"); return E_INVALIDARG; }
|