Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

853 lines
20 KiB

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