PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/library/MsmqQueue.cpp

#
C++ | 507 lines | 339 code | 95 blank | 73 comment | 44 complexity | b4744f95f2109321d3e13b45362f2399 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // MsmqQueue.cpp
  3. // ------------------------------------------------------------------
  4. //
  5. // Copyright (c) 2006-2010 Dino Chiesa.
  6. // All rights reserved.
  7. //
  8. // This code module is part of MsmqJava, a JNI library that provides
  9. // access to MSMQ for Java on Windows.
  10. //
  11. // ------------------------------------------------------------------
  12. //
  13. // This code is licensed under the Microsoft Public License.
  14. // See the file License.txt for the license details.
  15. // More info on: http://dotnetzip.codeplex.com
  16. //
  17. // ------------------------------------------------------------------
  18. //
  19. // last saved (in emacs):
  20. // Time-stamp: <2010-March-28 00:26:45>
  21. //
  22. // ------------------------------------------------------------------
  23. //
  24. // This module provides an Object wrapper around the Win32 MSMQ
  25. // functions.
  26. //
  27. // ------------------------------------------------------------------
  28. // See the MQ Functions Ref:
  29. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msmq/msmq_ref_functions_4o37.asp
  30. #include <stdio.h>
  31. #include <MqOai.h>
  32. #include <mq.h>
  33. #include "MsmqQueue.hpp"
  34. extern void _PrintByteArray(BYTE *b, int offset, int length);
  35. #if DEBUG
  36. #define DIAG(...) { printf(__VA_ARGS__); }
  37. #else
  38. #define DIAG(...) { if(FALSE) {}}
  39. #endif
  40. HRESULT MsmqQueue::createQueue( char *szQueuePath,
  41. char *szQueueLabel,
  42. LPWSTR wszFormatName,
  43. DWORD * p_dwFormatNameBufferLength,
  44. int isTransactional )
  45. {
  46. HRESULT hr = MQ_OK;
  47. int len;
  48. // example: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msmq/msmq_using_createqueue_0f51.asp
  49. const int NUMBEROFPROPERTIES = 5;
  50. MQQUEUEPROPS QueueProps;
  51. MQPROPVARIANT aQueuePropVar[NUMBEROFPROPERTIES];
  52. QUEUEPROPID aQueuePropId[NUMBEROFPROPERTIES];
  53. HRESULT aQueueStatus[NUMBEROFPROPERTIES];
  54. DWORD i = 0;
  55. if (szQueuePath == NULL)
  56. return MQ_ERROR_INVALID_PARAMETER;
  57. WCHAR wszPathName[MQ_MAX_Q_NAME_LEN];
  58. len= strlen(szQueuePath);
  59. if (MultiByteToWideChar(
  60. (UINT) CP_ACP,
  61. (DWORD) 0,
  62. (LPCSTR) szQueuePath,
  63. len,
  64. (LPWSTR) wszPathName,
  65. (int) sizeof( wszPathName ) ) == 0)
  66. return MQ_ERROR_INVALID_PARAMETER;
  67. if (len < sizeof( wszPathName ) )
  68. wszPathName[len]= 0; // need this to terminate
  69. WCHAR wszLabel[MQ_MAX_Q_LABEL_LEN];
  70. len= strlen(szQueueLabel);
  71. if (MultiByteToWideChar(
  72. (UINT) CP_ACP,
  73. (DWORD) 0,
  74. (LPCSTR) szQueueLabel,
  75. len,
  76. (LPWSTR) wszLabel,
  77. (int) sizeof( wszLabel ) ) == 0)
  78. {
  79. return MQ_ERROR_INVALID_PARAMETER;
  80. }
  81. if (len < sizeof( wszLabel ) )
  82. wszLabel[len]= 0; // need this to terminate
  83. DIAG("attempting to create queue with name= '%S', label='%S'\n", wszPathName, wszLabel);
  84. // Set the PROPID_Q_PATHNAME property with the path name provided.
  85. aQueuePropId[i] = PROPID_Q_PATHNAME;
  86. aQueuePropVar[i].vt = VT_LPWSTR;
  87. aQueuePropVar[i].pwszVal = wszPathName; // wszActualName
  88. i++;
  89. // Set optional queue properties. PROPID_Q_TRANSACTIONAL
  90. // must be set to make the queue transactional.
  91. aQueuePropId[i] = PROPID_Q_TRANSACTION;
  92. aQueuePropVar[i].vt = VT_UI1;
  93. aQueuePropVar[i].bVal = (unsigned char) isTransactional;
  94. i++;
  95. aQueuePropId[i] = PROPID_Q_LABEL;
  96. aQueuePropVar[i].vt = VT_LPWSTR;
  97. aQueuePropVar[i].pwszVal = wszLabel;
  98. i++;
  99. // Initialize the MQQUEUEPROPS structure
  100. QueueProps.cProp = i; //Number of properties
  101. QueueProps.aPropID = aQueuePropId; //IDs of the queue properties
  102. QueueProps.aPropVar = aQueuePropVar; //Values of the queue properties
  103. QueueProps.aStatus = aQueueStatus; //Pointer to return status
  104. // http://msdn.microsoft.com/library/en-us/msmq/msmq_ref_functions_8dut.asp
  105. hr = MQCreateQueue(NULL, // Security descriptor
  106. &QueueProps, // Address of queue property structure
  107. wszFormatName, // Pointer to format name buffer
  108. p_dwFormatNameBufferLength); // Pointer to receive the queue's format name length
  109. return hr;
  110. };
  111. HRESULT MsmqQueue::deleteQueue( char *szQueuePath )
  112. {
  113. HRESULT hr = MQ_OK;
  114. int len;
  115. // example: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msmq/msmq_using_createqueue_0f51.asp
  116. if (szQueuePath == NULL)
  117. return MQ_ERROR_INVALID_PARAMETER;
  118. // dinoch - Mon, 18 Apr 2005 16:34
  119. // removed the prefix. The caller is now responsible for providing it.
  120. //CHAR szDestFormatName[MQ_MAX_Q_NAME_LEN] = "DIRECT=OS:";
  121. //strcat(szDestFormatName, szQueuePath);
  122. CHAR szDestFormatName[MQ_MAX_Q_NAME_LEN];
  123. strncpy_s(szDestFormatName, MQ_MAX_Q_NAME_LEN, szQueuePath, MQ_MAX_Q_NAME_LEN);
  124. WCHAR wszPathName[MQ_MAX_Q_NAME_LEN];
  125. len= strlen(szDestFormatName);
  126. if (MultiByteToWideChar(
  127. (UINT) CP_ACP,
  128. (DWORD) 0,
  129. (LPCSTR) szDestFormatName,
  130. len,
  131. (LPWSTR) wszPathName,
  132. (int) sizeof( wszPathName ) ) == 0)
  133. {
  134. return MQ_ERROR_INVALID_PARAMETER;
  135. }
  136. if (len < sizeof( wszPathName ) )
  137. wszPathName[len]= 0; // need this to terminate
  138. hr = MQDeleteQueue( wszPathName );
  139. return hr;
  140. };
  141. HRESULT MsmqQueue::openQueue(char *szQueuePath, int openmode)
  142. {
  143. // DIRECT=OS: says to use the computer name to identify the message queue
  144. // dinoch - Mon, 18 Apr 2005 16:25
  145. // removed initialization
  146. //CHAR szDestFormatName[MQ_MAX_Q_NAME_LEN] = "DIRECT=OS:";
  147. CHAR szDestFormatName[MQ_MAX_Q_NAME_LEN];
  148. WCHAR wszDestFormatName[2*MQ_MAX_Q_NAME_LEN];
  149. long accessmode = openmode; // bit field: MQ_{RECEIVE,SEND,PEEK,ADMIN}_ACCESS,
  150. long sharemode = MQ_DENY_NONE;
  151. // Validate the input string.
  152. if (szQueuePath == NULL)
  153. {
  154. return MQ_ERROR_INVALID_PARAMETER;
  155. }
  156. // dinoch - Mon, 18 Apr 2005 16:24
  157. // removed. The caller now needs to add any required prefix.
  158. // add a prefix of DIRECT=OS: to MSMQ queuepath
  159. //strcat(szDestFormatName, szQueuePath);
  160. strncpy_s(szDestFormatName, MQ_MAX_Q_NAME_LEN, szQueuePath, sizeof(szDestFormatName)/sizeof(CHAR));
  161. // convert to wide characters;
  162. if (MultiByteToWideChar(
  163. (UINT) CP_ACP,
  164. (DWORD) 0,
  165. (LPCSTR) szDestFormatName,
  166. (int) sizeof(szDestFormatName),
  167. (LPWSTR) wszDestFormatName,
  168. (int) sizeof(wszDestFormatName) ) == 0)
  169. {
  170. return MQ_ERROR_INVALID_PARAMETER;
  171. }
  172. HRESULT hr = MQ_OK;
  173. // dinoch Mon, 18 Apr 2005 16:12
  174. DIAG("open: ");
  175. DIAG("fmtname(%ls) ", wszDestFormatName);
  176. DIAG("accessmode(%d) ", accessmode);
  177. DIAG("sharemode(%d) ", sharemode);
  178. DIAG("\n");
  179. hr = MQOpenQueue(
  180. wszDestFormatName, // Format name of the queue
  181. accessmode, // Access mode
  182. sharemode, // Share mode
  183. &hQueue // OUT: Handle to queue
  184. );
  185. // Retry to handle AD replication delays.
  186. //
  187. if (hr == MQ_ERROR_QUEUE_NOT_FOUND)
  188. {
  189. int iCount = 0 ;
  190. while((hr == MQ_ERROR_QUEUE_NOT_FOUND) && (iCount < 120))
  191. {
  192. DIAG(".");
  193. // Wait a bit.
  194. iCount++ ;
  195. Sleep(50);
  196. // Retry.
  197. hr = MQOpenQueue(wszDestFormatName,
  198. accessmode,
  199. sharemode,
  200. &hQueue);
  201. }
  202. }
  203. if (FAILED(hr))
  204. {
  205. MQCloseQueue(hQueue);
  206. }
  207. return hr;
  208. };
  209. HRESULT MsmqQueue::receiveBytes(BYTE **ppbMessageBody,
  210. DWORD *dwpBodyLen,
  211. WCHAR *wszMessageLabel,
  212. BYTE *pCorrelationId, // sz PROPID_M_CORRELATIONID_SIZE
  213. DWORD dwTimeOut,
  214. int ReadOrPeek
  215. )
  216. {
  217. // for receive message
  218. const int NUMBEROFPROPERTIES = 6;
  219. MQMSGPROPS MsgProps;
  220. MQPROPVARIANT fields[NUMBEROFPROPERTIES];
  221. MSGPROPID propId[NUMBEROFPROPERTIES];
  222. DWORD i = 0;
  223. DWORD dwAction = (ReadOrPeek==1)? MQ_ACTION_RECEIVE : MQ_ACTION_PEEK_CURRENT;
  224. HRESULT hr = S_OK;
  225. int iBodyLen = 0;
  226. int iBody = 0;
  227. int iLabelLen = 0;
  228. ULONG ulLabelLen = MQ_MAX_MSG_LABEL_LEN;
  229. // initialize all out variables to NULL
  230. if (NULL != wszMessageLabel)
  231. *wszMessageLabel = L'\0';
  232. if (NULL != pCorrelationId)
  233. memset(pCorrelationId, 0, PROPID_M_CORRELATIONID_SIZE);
  234. int MAX_INITIAL_BODY_SIZE= 1024;
  235. *ppbMessageBody = new BYTE[MAX_INITIAL_BODY_SIZE];
  236. // prepare the property array PROPVARIANT of
  237. // message properties that we want to receive
  238. propId[i] = PROPID_M_BODY_SIZE;
  239. fields[i].vt = VT_UI4;
  240. fields[i].ulVal = *dwpBodyLen;
  241. iBodyLen = i;
  242. i++;
  243. propId[i] = PROPID_M_BODY;
  244. fields[i].vt = VT_VECTOR|VT_UI1;
  245. fields[i].caub.cElems = *dwpBodyLen;
  246. fields[i].caub.pElems = (unsigned char *)*ppbMessageBody;
  247. iBody = i;
  248. i++;
  249. if (NULL != pCorrelationId)
  250. {
  251. propId[i] = PROPID_M_CORRELATIONID;
  252. fields[i].vt = VT_VECTOR | VT_UI1;
  253. fields[i].caub.pElems = (LPBYTE)pCorrelationId;
  254. fields[i].caub.cElems = PROPID_M_CORRELATIONID_SIZE;
  255. i++;
  256. }
  257. propId[i] = PROPID_M_LABEL_LEN;
  258. fields[i].vt = VT_UI4;
  259. fields[i].ulVal = ulLabelLen;
  260. iLabelLen = i;
  261. i++;
  262. propId[i] = PROPID_M_LABEL;
  263. fields[i].vt = VT_LPWSTR;
  264. fields[i].pwszVal = wszMessageLabel;
  265. i++;
  266. // Set the MQMSGPROPS structure
  267. MsgProps.cProp = i; // Number of properties.
  268. MsgProps.aPropID = propId; // Id of properties.
  269. MsgProps.aPropVar = fields; // Value of properties.
  270. MsgProps.aStatus = NULL; // No Error report.
  271. hr = MQReceiveMessage(
  272. hQueue, // handle to the Queue.
  273. dwTimeOut, // Max time (msec) to wait for the message.
  274. dwAction, // Action.
  275. &MsgProps, // properties to retrieve.
  276. NULL, // No overlaped structure.
  277. NULL, // No callback function.
  278. NULL, // No Cursor.
  279. NULL // transaction
  280. );
  281. // handle the case where the buffer is too small
  282. do
  283. {
  284. if (MQ_ERROR_BUFFER_OVERFLOW == hr)
  285. {
  286. if (NULL != *ppbMessageBody)
  287. {
  288. delete[] *ppbMessageBody;
  289. *ppbMessageBody = NULL;
  290. }
  291. INT iNewMsgLen = fields[iBodyLen].ulVal ;
  292. *ppbMessageBody = new BYTE[iNewMsgLen];
  293. fields[iBody].caub.cElems =
  294. fields[iBodyLen].ulVal;
  295. fields[iBody].caub.pElems =
  296. (unsigned char *)*ppbMessageBody;
  297. hr = MQReceiveMessage(
  298. hQueue, // handle to the Queue.
  299. dwTimeOut, // Max time (msec) to wait for the message.
  300. dwAction, // Action.
  301. &MsgProps, // properties to retrieve.
  302. NULL, // No overlapped structure.
  303. NULL, // No callback function.
  304. NULL, // No Cursor.
  305. NULL // transaction
  306. );
  307. }
  308. if (hr == MQ_ERROR_LABEL_BUFFER_TOO_SMALL)
  309. {
  310. fields[iLabelLen].ulVal = ulLabelLen;
  311. fields[iLabelLen+1].pwszVal = wszMessageLabel;
  312. hr = MQReceiveMessage(
  313. hQueue, // handle to the Queue.
  314. dwTimeOut, // Max time (msec) to wait for the message.
  315. dwAction, // Action.
  316. &MsgProps, // properties to retrieve.
  317. NULL, // No overlapped structure.
  318. NULL, // No callback function.
  319. NULL, // No Cursor.
  320. NULL // transaction
  321. );
  322. }
  323. }
  324. while(MQ_ERROR_BUFFER_OVERFLOW == hr) ;
  325. if (FAILED(hr))
  326. {
  327. delete[] *ppbMessageBody;
  328. *ppbMessageBody = NULL;
  329. return hr;
  330. }
  331. // printf("receive: hr 0x%08x\n", hr );
  332. // printf(" : body: %d bytes (0x%x)\n", fields[iBodyLen].ulVal * 2,
  333. // fields[iBodyLen].ulVal * 2);
  334. // _PrintByteArray((BYTE*)*ppbMessageBody, 0, fields[iBodyLen].ulVal * 2);
  335. // printf(" : label: %d bytes (0x%X)\n", fields[iLabelLen].ulVal * 2,
  336. // fields[iLabelLen].ulVal * 2);
  337. // _PrintByteArray((BYTE*)wszMessageLabel, 0, fields[iLabelLen].ulVal * 2);
  338. *dwpBodyLen = fields[iBodyLen].ulVal;
  339. if (0 == *dwpBodyLen)
  340. {
  341. delete[] *ppbMessageBody;
  342. *ppbMessageBody = NULL;
  343. }
  344. ulLabelLen = fields[iLabelLen].ulVal;
  345. return hr;
  346. };
  347. HRESULT MsmqQueue::sendBytes(BYTE *pbMessageBody,
  348. DWORD dwBodyLen,
  349. WCHAR *wszMessageLabel,
  350. BYTE *pCorrelationId,
  351. DWORD dwCorIdLen,
  352. DWORD transactionFlag,
  353. BOOL fHighPriority
  354. )
  355. {
  356. const int MAX_NUM_PROPERTIES = 4; // Max. Number of properties for send message
  357. MQMSGPROPS MsgProps;
  358. MSGPROPID propId[MAX_NUM_PROPERTIES];
  359. MQPROPVARIANT aPropVariant[MAX_NUM_PROPERTIES];
  360. DWORD i = 0;
  361. HRESULT hr = S_OK;
  362. BYTE corId[PROPID_M_CORRELATIONID_SIZE];
  363. memset(corId, 0, PROPID_M_CORRELATIONID_SIZE);
  364. if (dwCorIdLen > 0) {
  365. // Copy correlationId truncating to MSMQ max corId size of 20.
  366. // We don't do any translation of this field.
  367. if (dwCorIdLen > PROPID_M_CORRELATIONID_SIZE) dwCorIdLen= PROPID_M_CORRELATIONID_SIZE;
  368. memcpy(corId, pCorrelationId, dwCorIdLen);
  369. }
  370. if (NULL != pbMessageBody)
  371. {
  372. // Set the PROPID_M_BODY property.
  373. propId[i] = PROPID_M_BODY;
  374. aPropVariant[i].vt = VT_VECTOR|VT_UI1;
  375. aPropVariant[i].caub.cElems = dwBodyLen;
  376. aPropVariant[i].caub.pElems = const_cast<BYTE *>(pbMessageBody);
  377. i++;
  378. }
  379. propId[i] = PROPID_M_CORRELATIONID;
  380. aPropVariant[i].vt = VT_VECTOR | VT_UI1;
  381. aPropVariant[i].caub.pElems = (LPBYTE)corId;
  382. aPropVariant[i].caub.cElems = PROPID_M_CORRELATIONID_SIZE;
  383. i++;
  384. propId[i] = PROPID_M_LABEL;
  385. aPropVariant[i].vt = VT_LPWSTR;
  386. aPropVariant[i].pwszVal = wszMessageLabel;
  387. i++;
  388. if (fHighPriority)
  389. {
  390. // Set the PROPID_M_PRIORITY property.
  391. propId[i] = PROPID_M_PRIORITY;
  392. aPropVariant[i].vt = VT_UI1;
  393. aPropVariant[i].bVal = 7; // Highest priority
  394. i++;
  395. }
  396. // Set the MQMSGPROPS structure
  397. MsgProps.cProp = i; // Number of properties.
  398. MsgProps.aPropID = propId; // Id of properties.
  399. MsgProps.aPropVar = aPropVariant; // Value of properties.
  400. MsgProps.aStatus = NULL; // No Error report.
  401. hr = MQSendMessage(hQueue, // handle to the Queue.
  402. &MsgProps, // Message properties to be sent.
  403. (ITransaction *) transactionFlag
  404. );
  405. return hr;
  406. };
  407. HRESULT MsmqQueue::closeQueue( )
  408. {
  409. HRESULT hr = MQ_OK;
  410. hr = MQCloseQueue(hQueue);
  411. return hr;
  412. };