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.

908 lines
23 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: DPLMsgQ.cpp
  6. * Content: DirectPlay Lobby Message Queues
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 02/21/00 mjn Created
  12. * 04/26/00 mjn Fixed AddData() to return HRESULT
  13. * 07/06/00 rmt Bug #38111 - Fixed prefix bug
  14. * 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched
  15. * rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns
  16. * rmt Bug #38755 - No way to specify player name in Connection Settings
  17. * rmt Bug #38758 - DPLOBBY8.H has incorrect comments
  18. * rmt Bug #38783 - pvUserApplicationContext is only partially implemented
  19. * rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs).
  20. * 07/21/2000 rmt Removed assert which wasn't needed
  21. * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  22. * 08/31/2000 rmt Bug #171831, 131832 (Prefix Bugs)
  23. * 01/31/2001 rmt WINBUG #295562 IDirectPlay8LobbyClient: SetConnectionSettings not sending DPL_CONNECTION_SETTINGS message to App
  24. *@@END_MSINTERNAL
  25. *
  26. ***************************************************************************/
  27. #include "dnlobbyi.h"
  28. // DirectPlay Lobby Message Queues
  29. //
  30. // We will use shared memory circular message buffers to implement this.
  31. // Each MsgQ has a set of synchronization objects to control access to the MsgQs.
  32. // The head of the shared memory file contains state information about the MsgQ:
  33. // pStartAddress
  34. // dwTotalUsableSpace
  35. // dwFirstMsgOffset
  36. // dwNextFreeOffset
  37. // dwFreeSpaceAtEnd
  38. // dwTotalFreeSpace
  39. // Messages are DWORD aligned in the MsgQ.
  40. // Each message in the MsgQ has a header:
  41. // dwMsgId
  42. // dwCurrentOffset
  43. // dwCurrentSize
  44. // dwTotalSize
  45. // Messages which fit in one frame have dwCurrentSize = dwTotalSize and dwCurrentOffset = 0.
  46. // Messages over multiple frames have dwCurrentSize < dwTotalSize.
  47. //**********************************************************************
  48. // Constant definitions
  49. //**********************************************************************
  50. //**********************************************************************
  51. // Macro definitions
  52. //**********************************************************************
  53. //**********************************************************************
  54. // Structure definitions
  55. //**********************************************************************
  56. //**********************************************************************
  57. // Variable definitions
  58. //**********************************************************************
  59. //**********************************************************************
  60. // Function prototypes
  61. //**********************************************************************
  62. //**********************************************************************
  63. // Function definitions
  64. //**********************************************************************
  65. //**********************************************************************
  66. // ------------------------------
  67. // CMessageQueue::Open
  68. //
  69. // Entry: const DWORD dwPID Id associated with this queue (user supplied)
  70. // const CHAR cSuffix Suffix character associated with this Q (user supp.)
  71. // const DWORD dwQueueSize Size of file map to use when implementing msg queue
  72. // const DWORD dwIdleTimeout Amount of time between idle messages == INFINITE to disable idle
  73. // const DWORD dwFlags TBA
  74. //
  75. //
  76. // Exit: HRESULT: DPN_OK If able to open an existing message queue,
  77. // or create a message queue if one didn't exist
  78. // DPNERR_OUTOFMEMORY
  79. // ------------------------------
  80. #undef DPF_MODNAME
  81. #define DPF_MODNAME "CMessageQueue::Open"
  82. HRESULT CMessageQueue::Open(const DWORD dwPID,
  83. const CHAR cSuffix,
  84. const DWORD dwQueueSize,
  85. const DWORD dwIdleTimeout,
  86. const DWORD dwFlags)
  87. {
  88. HRESULT hResultCode;
  89. PSTR pszObjectName = NULL;
  90. BOOL bQueueExists = FALSE;
  91. DWORD dwFileMapSize;
  92. DPFX(DPFPREP, 3,"Parameters: dwPID [0x%lx], cSuffix [%c], dwQueueSize [%ld], dwFlags [0x%lx]",
  93. dwPID,cSuffix,dwQueueSize,dwFlags);
  94. // Create Receive Thread Running Event
  95. // This will be set by the receive thread once it has spun up. We need it for synchronization
  96. m_hReceiveThreadRunningEvent = CreateEventA(NULL,TRUE,FALSE,NULL);
  97. if (m_hReceiveThreadRunningEvent == NULL)
  98. {
  99. DPFERR("Could not create recevie thread");
  100. hResultCode = DPNERR_OUTOFMEMORY;
  101. goto EXIT_Initialize;
  102. }
  103. // Create shared object name
  104. // pszObjectName : {SharedObjectChar}PID{cSuffix}{\0}
  105. if ((pszObjectName = (PSTR)DNMalloc(1 + (sizeof(DWORD)*2) + 1 + 1)) == NULL)
  106. {
  107. DPFERR("Could not allocate space for lpszObjectName");
  108. hResultCode = DPNERR_OUTOFMEMORY;
  109. goto EXIT_Initialize;
  110. }
  111. wsprintfA(pszObjectName,"-%08X%c",dwPID,cSuffix);// save first char for object differentiation
  112. DPFX(DPFPREP, 5,"Shared object name [%s]",pszObjectName);
  113. // Set the filemap size big enough that the largest message (text) will be dwQueueSize
  114. // so we add on the MsgQ info structure at the front and 1 Msg header
  115. dwFileMapSize = dwQueueSize + sizeof(DPL_MSGQ_INFO) + sizeof(DPL_MSGQ_HEADER);
  116. dwFileMapSize = (dwFileMapSize + 3) & (~0x3); // DWORD align
  117. m_dwIdleTimeout = dwIdleTimeout;
  118. // Create File Mapping Object
  119. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_FILEMAP;
  120. m_hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE,DNGetNullDacl(),
  121. PAGE_READWRITE,(DWORD)0,dwQueueSize,pszObjectName);
  122. if (m_hFileMap == NULL)
  123. {
  124. DPFERR("CreateFileMapping() failed");
  125. hResultCode = DPNERR_GENERIC;
  126. goto EXIT_Initialize;
  127. }
  128. if (GetLastError() == ERROR_ALREADY_EXISTS)
  129. bQueueExists = TRUE;
  130. if ((dwFlags & DPL_MSGQ_OPEN_FLAG_NO_CREATE) && !bQueueExists)
  131. {
  132. DPFERR("Open existing queue failed - does not exist");
  133. hResultCode = DPNERR_DOESNOTEXIST;
  134. goto EXIT_Initialize;
  135. }
  136. // Map file
  137. m_pFileMapAddress = reinterpret_cast<BYTE*>(MapViewOfFile(m_hFileMap,FILE_MAP_ALL_ACCESS,0,0,0));
  138. if (m_pFileMapAddress == NULL)
  139. {
  140. DPFERR("MapViewOfFile() failed");
  141. hResultCode = DPNERR_OUTOFMEMORY;
  142. goto EXIT_Initialize;
  143. }
  144. // Create semaphore object
  145. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_SEMAPHORE;
  146. m_hSemaphore = CreateSemaphoreA(DNGetNullDacl(),0,
  147. (dwQueueSize/sizeof(DPL_MSGQ_HEADER))+1,pszObjectName);
  148. if (m_hSemaphore == NULL)
  149. {
  150. DPFERR("CreateSemaphore() failed");
  151. hResultCode = DPNERR_OUTOFMEMORY;
  152. goto EXIT_Initialize;
  153. }
  154. // Create event object
  155. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_EVENT;
  156. // Changed to a semaphore to ensure that we never miss an event signal
  157. m_hEvent = CreateSemaphoreA(DNGetNullDacl(), 0, (dwQueueSize/sizeof(DPL_MSGQ_HEADER))+1, pszObjectName );
  158. if( m_hEvent == NULL )
  159. {
  160. DPFERR( "CreateSemaphore() failed" );
  161. hResultCode = DPNERR_OUTOFMEMORY;
  162. goto EXIT_Initialize;
  163. }
  164. // Create mutex object
  165. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_MUTEX;
  166. m_hMutex = CreateMutexA(DNGetNullDacl(),FALSE,pszObjectName);
  167. if (m_hMutex == NULL)
  168. {
  169. DPFERR("CreateMutex() failed");
  170. hResultCode = DPNERR_OUTOFMEMORY;
  171. goto EXIT_Initialize;
  172. }
  173. // Update structure elements
  174. m_dwPID = dwPID;
  175. m_pInfo = reinterpret_cast<DPL_MSGQ_INFO*>(m_pFileMapAddress);
  176. // Initialize msg queue if it didn't exist
  177. if (!bQueueExists)
  178. {
  179. m_pInfo->dwFlags = dwFlags & 0x0000ffff; // Just last two bytes
  180. m_pInfo->dwStartOffset = 0;
  181. m_pInfo->dwEndOffset = 0;
  182. m_pInfo->dwQueueSize = dwQueueSize - sizeof(DPL_MSGQ_INFO);
  183. m_pInfo->dwFreeBytes = m_pInfo->dwQueueSize;
  184. m_pInfo->lRefCount = 0;
  185. }
  186. m_pData = (BYTE *) &m_pInfo[1];
  187. m_dwSig = DPL_MSGQ_SIGNATURE;
  188. // Increment user count
  189. Lock();
  190. m_pInfo->lRefCount++;
  191. Unlock();
  192. // If we made it this far, everything was okay
  193. hResultCode = DPN_OK;
  194. EXIT_Initialize:
  195. // Free object name string
  196. if (pszObjectName != NULL)
  197. DNFree(pszObjectName);
  198. // If there was a problem - close handles
  199. if (hResultCode != DPN_OK)
  200. {
  201. DPFERR("Errors encountered - closing");
  202. Close();
  203. }
  204. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  205. return(hResultCode);
  206. }
  207. //**********************************************************************
  208. // ------------------------------
  209. // CMessageQueue::Close
  210. //
  211. // Entry: Nothing
  212. //
  213. // Exit: Nothing
  214. // ------------------------------
  215. #undef DPF_MODNAME
  216. #define DPF_MODNAME "CMessageQueue::Close"
  217. void CMessageQueue::Close(void)
  218. {
  219. DPFX(DPFPREP, 3,"Parameters: (none)");
  220. if (m_hMutex != NULL)
  221. {
  222. // Decrement user count
  223. Lock();
  224. if( m_pInfo != NULL )
  225. {
  226. m_pInfo->lRefCount--;
  227. }
  228. Unlock();
  229. DPFX(DPFPREP, 5,"Close Mutex [0x%p]",m_hMutex);
  230. CloseHandle(m_hMutex);
  231. m_hMutex = NULL;
  232. }
  233. if (m_hEvent != NULL)
  234. {
  235. DPFX(DPFPREP, 5,"Close Event [0x%p]",m_hEvent);
  236. CloseHandle(m_hEvent);
  237. m_hEvent = NULL;
  238. }
  239. if (m_hSemaphore != NULL)
  240. {
  241. DPFX(DPFPREP, 5,"Close Semaphore [0x%p]",m_hSemaphore);
  242. CloseHandle(m_hSemaphore);
  243. m_hSemaphore = NULL;
  244. }
  245. if (m_pFileMapAddress != NULL)
  246. {
  247. DPFX(DPFPREP, 5,"UnMap View of File [0x%p]",m_pFileMapAddress);
  248. UnmapViewOfFile(m_pFileMapAddress);
  249. m_pFileMapAddress = NULL;
  250. }
  251. if (m_hFileMap != NULL)
  252. {
  253. DPFX(DPFPREP, 5,"Close FileMap [0x%p]",m_hFileMap);
  254. CloseHandle(m_hFileMap);
  255. m_hFileMap = NULL;
  256. }
  257. if (m_hReceiveThreadRunningEvent != NULL)
  258. {
  259. DPFX(DPFPREP, 5,"Close Event [0x%p]",m_hReceiveThreadRunningEvent);
  260. CloseHandle(m_hReceiveThreadRunningEvent);
  261. m_hReceiveThreadRunningEvent = NULL;
  262. }
  263. m_pInfo = NULL;
  264. DPFX(DPFPREP, 3,"Returning");
  265. }
  266. //**********************************************************************
  267. // ------------------------------
  268. // CMessageQueue::Terminate
  269. //
  270. // Entry: Nothing
  271. //
  272. // Exit: Nothing
  273. // ------------------------------
  274. #undef DPF_MODNAME
  275. #define DPF_MODNAME "CMessageQueue::Terminate"
  276. void CMessageQueue::Terminate(void)
  277. {
  278. BOOL bDone = FALSE;
  279. DPL_MSGQ_HEADER Header;
  280. Header.dwCurrentSize = 0;
  281. Header.dwTotalSize = 0;
  282. Header.dwMsgId = DPL_MSGQ_MSGID_TERMINATE;
  283. Header.hSender = 0xFFFFFFFF;
  284. Header.dwFlags = DPL_MSGQ_MSGFLAGS_QUEUESYSTEM;
  285. Header.dwCurrentOffset = 0;
  286. DPFX(DPFPREP, 3,"Parameters: (none)");
  287. DNASSERT(m_pInfo != NULL);
  288. while (!bDone)
  289. {
  290. // Wait until there's enough space for the message
  291. while (sizeof(DWORD) > m_pInfo->dwFreeBytes)
  292. WaitForConsumption(INFINITE);
  293. Lock();
  294. // Ensure there is space once we get the lock
  295. // (someone else might have beaten us here)
  296. if (sizeof(DWORD) <= m_pInfo->dwFreeBytes)
  297. {
  298. AddData(reinterpret_cast<BYTE*>(&Header),sizeof(DPL_MSGQ_HEADER));
  299. bDone = TRUE;
  300. IndicateMessage();
  301. }
  302. Unlock();
  303. }
  304. DPFX(DPFPREP, 3,"Returning");
  305. }
  306. // GetNextMessage
  307. //
  308. // Attempts to retrieve the next message from the queue
  309. //
  310. // pMsgHeader must be large enough to hold a message header.
  311. //
  312. // If no message is present in the queue then this function fills pMsgHeader with an
  313. // idle message header
  314. //
  315. HRESULT CMessageQueue::GetNextMessage( PDPL_MSGQ_HEADER pMsgHeader, BYTE *pbPayload, DWORD *pdwBufferSize )
  316. {
  317. HRESULT hr;
  318. Lock();
  319. hr = GetData( (BYTE *) pMsgHeader, sizeof( DPL_MSGQ_HEADER ) );
  320. // If there is no header on the queue fill in the header with an
  321. // idle message
  322. if( hr == DPNERR_DOESNOTEXIST )
  323. {
  324. pMsgHeader->dwCurrentSize = sizeof( DPL_MSGQ_HEADER );
  325. pMsgHeader->dwTotalSize = sizeof( DPL_MSGQ_HEADER );
  326. pMsgHeader->dwMsgId = DPL_MSGQ_MSGID_IDLE;
  327. pMsgHeader->hSender = 0;
  328. pMsgHeader->dwFlags = DPL_MSGQ_MSGFLAGS_QUEUESYSTEM;
  329. pMsgHeader->dwCurrentOffset = 0;
  330. Unlock();
  331. return DPN_OK;
  332. }
  333. //// DEBUG
  334. else if( FAILED( hr ) )
  335. {
  336. DNASSERT( FALSE );
  337. }
  338. else if( pMsgHeader->dwMsgId == 0xFFFFFFFF )
  339. {
  340. DNASSERT( FALSE );
  341. }
  342. DWORD dwPayloadSize = pMsgHeader->dwCurrentSize;
  343. // Otherwise it's a valid message of some kind
  344. if( *pdwBufferSize < dwPayloadSize || pbPayload == NULL )
  345. {
  346. *pdwBufferSize = dwPayloadSize;
  347. Unlock();
  348. return DPNERR_BUFFERTOOSMALL;
  349. }
  350. *pdwBufferSize = dwPayloadSize;
  351. Consume( sizeof(DPL_MSGQ_HEADER) );
  352. // There is no payload, only a header. Return here.
  353. if( dwPayloadSize == 0 )
  354. {
  355. Unlock();
  356. return DPN_OK;
  357. }
  358. hr = GetData( pbPayload, dwPayloadSize );
  359. if( FAILED( hr ) )
  360. {
  361. DPFX(DPFPREP, 0, "Error getting IPC queue message payload" );
  362. DNASSERT( FALSE );
  363. Unlock();
  364. return hr;
  365. }
  366. Consume( dwPayloadSize );
  367. Unlock();
  368. return DPN_OK;
  369. }
  370. // Consume
  371. //
  372. // Marks dwSize bytes as consumed
  373. //
  374. // Needs LOCK()
  375. void CMessageQueue::Consume( const DWORD dwSize )
  376. {
  377. DWORD dwAlignedSize = (dwSize + 3) & (~0x3);
  378. m_pInfo->dwStartOffset += dwAlignedSize;
  379. if( m_pInfo->dwStartOffset >= m_pInfo->dwQueueSize )
  380. {
  381. m_pInfo->dwStartOffset -= m_pInfo->dwQueueSize;
  382. }
  383. m_pInfo->dwFreeBytes += dwAlignedSize;
  384. DNASSERT( m_pInfo->dwFreeBytes <= m_pInfo->dwFreeBytes );
  385. IndicateConsumption();
  386. }
  387. // GetData
  388. //
  389. // Get dwSize bytes from the queue. If the queue is empty this function will return
  390. // DPNERR_DOESNOTEXIST. Once this function returns the dwSize bytes will be consumed
  391. //
  392. // REQUIRES LOCK
  393. //
  394. HRESULT CMessageQueue::GetData( BYTE *pbData, DWORD dwSize )
  395. {
  396. if( m_pInfo->dwQueueSize == m_pInfo->dwFreeBytes )
  397. {
  398. return DPNERR_DOESNOTEXIST;
  399. }
  400. if( pbData == NULL )
  401. {
  402. return DPNERR_BUFFERTOOSMALL;
  403. }
  404. // Calculate aligned size
  405. DWORD dwAlignedSize = (dwSize + 3) & (~0x3);
  406. // Data block we want is wrapped
  407. if( m_pInfo->dwStartOffset+dwAlignedSize > m_pInfo->dwQueueSize )
  408. {
  409. DWORD cbBytesLeft = m_pInfo->dwQueueSize - m_pInfo->dwStartOffset;
  410. DWORD cbSecondBlockAligned = dwAlignedSize - (cbBytesLeft);
  411. DWORD cbSecondBlock = dwSize - (cbBytesLeft);
  412. DNASSERT( dwAlignedSize > cbBytesLeft);
  413. memcpy( pbData, m_pData + m_pInfo->dwStartOffset, cbBytesLeft);
  414. memcpy( pbData + cbBytesLeft, m_pData , cbSecondBlock );
  415. }
  416. // Data block is contiguous
  417. else
  418. {
  419. memcpy( pbData, m_pData + m_pInfo->dwStartOffset, dwSize );
  420. }
  421. return DPN_OK;
  422. }
  423. //**********************************************************************
  424. // ------------------------------
  425. // CMessageQueue::AddData
  426. //
  427. // Entry: BYTE *const pBuffer
  428. // const DWORD dwSize
  429. //
  430. // Exit: HRESULT
  431. // ------------------------------
  432. //
  433. // REQUIRES LOCK!!
  434. //
  435. #undef DPF_MODNAME
  436. #define DPF_MODNAME "CMessageQueue::AddData"
  437. HRESULT CMessageQueue::AddData(BYTE *const pBuffer,
  438. const DWORD dwSize)
  439. {
  440. HRESULT hResultCode;
  441. DWORD dwAlignedSize;
  442. DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p], dwSize [%ld]",pBuffer,dwSize);
  443. dwAlignedSize = (dwSize + 3) & (~0x3);
  444. // Check to ensure there is space
  445. if( dwAlignedSize > m_pInfo->dwFreeBytes )
  446. {
  447. hResultCode = DPNERR_BUFFERTOOSMALL;
  448. goto Exit;
  449. }
  450. // We have a wrapping condition
  451. if( (m_pInfo->dwEndOffset+dwAlignedSize) > m_pInfo->dwQueueSize )
  452. {
  453. DWORD cbBytesLeft = m_pInfo->dwQueueSize - m_pInfo->dwEndOffset;
  454. DWORD cbSecondBlockAligned = dwAlignedSize - cbBytesLeft;
  455. DWORD cbSecondBlock = dwSize - cbBytesLeft;
  456. DNASSERT( dwAlignedSize > cbBytesLeft );
  457. memcpy( m_pData + m_pInfo->dwEndOffset, pBuffer, cbBytesLeft );
  458. memcpy( m_pData, pBuffer + cbBytesLeft, cbSecondBlock );
  459. m_pInfo->dwEndOffset = cbSecondBlockAligned;
  460. }
  461. // Queue is in the middle
  462. else
  463. {
  464. memcpy( m_pData + m_pInfo->dwEndOffset, pBuffer, dwSize );
  465. m_pInfo->dwEndOffset += dwAlignedSize;
  466. }
  467. m_pInfo->dwFreeBytes -= dwAlignedSize;
  468. hResultCode = DPN_OK;
  469. Exit:
  470. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  471. return(hResultCode);
  472. }
  473. //**********************************************************************
  474. // ------------------------------
  475. // CMessageQueue::Send
  476. //
  477. // Entry: BYTE *const pBuffer
  478. // const DWORD dwSize
  479. // const DWORD dwFlags
  480. //
  481. // Exit: HRESULT
  482. // ------------------------------
  483. #undef DPF_MODNAME
  484. #define DPF_MODNAME "CMessageQueue::Send"
  485. HRESULT CMessageQueue::Send(BYTE *const pBuffer,
  486. const DWORD dwSize,
  487. const DWORD dwTimeOut,
  488. const DWORD dwMsgFlags,
  489. const DWORD dwFlags)
  490. {
  491. HRESULT hResultCode;
  492. DWORD dwMsgSize; // DWORD aligned
  493. DWORD dwTotalMsgSize; // Msg + Header - DWORD aligned
  494. DPL_MSGQ_HEADER Header;
  495. DPL_MSGQ_HEADER *pHeader;
  496. BOOL bDone;
  497. DWORD dwTimeRemaining;
  498. DWORD dwTimeStart;
  499. DWORD dwTimeFinish;
  500. DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p], dwSize [%ld], dwFlags [0x%lx]",pBuffer,dwSize,dwFlags);
  501. DNASSERT( pBuffer != NULL );
  502. DNASSERT( dwSize <= m_pInfo->dwQueueSize );
  503. dwTimeRemaining = dwTimeOut;
  504. // Need DWORD aligned size
  505. dwMsgSize = (dwSize + 3) & (~0x3);
  506. dwTotalMsgSize = dwMsgSize + sizeof(DPL_MSGQ_HEADER);
  507. // Place the message into the MsgQ
  508. // Check to see if fragmentation is required
  509. // If we're at the end of the MsgQ and there isn't enough space for a Msg Header, REALIGN
  510. if (dwTotalMsgSize <= m_pInfo->dwQueueSize)
  511. {
  512. DPFX(DPFPREP, 5,"Message does not need to be fragmented");
  513. Header.dwMsgId = DPL_MSGQ_MSGID_SEND;
  514. Header.dwCurrentOffset = 0;
  515. Header.dwCurrentSize = dwSize;
  516. Header.dwTotalSize = dwSize;
  517. Header.hSender = m_hSender;
  518. Header.dwFlags = dwMsgFlags; // Mark this as a user message
  519. //// DEBUG
  520. if( Header.dwMsgId == 0xFFFFFFFF )
  521. {
  522. DNASSERT( FALSE );
  523. }
  524. bDone = FALSE;
  525. while (!bDone)
  526. {
  527. // Wait until there's enough space for the message
  528. while (dwTotalMsgSize > m_pInfo->dwFreeBytes)
  529. {
  530. if (dwTimeOut != INFINITE)
  531. {
  532. dwTimeStart = GETTIMESTAMP();
  533. }
  534. if (!WaitForConsumption(dwTimeRemaining))
  535. {
  536. return(DPNERR_TIMEDOUT);
  537. }
  538. if (dwTimeOut != INFINITE)
  539. {
  540. dwTimeFinish = GETTIMESTAMP();
  541. if ((dwTimeFinish - dwTimeStart) > dwTimeRemaining)
  542. {
  543. return(DPNERR_TIMEDOUT);
  544. }
  545. dwTimeRemaining -= (dwTimeFinish - dwTimeStart);
  546. }
  547. }
  548. Lock();
  549. // Ensure there is space once we get the lock
  550. // (someone else might have beaten us here)
  551. if (dwTotalMsgSize <= m_pInfo->dwFreeBytes)
  552. {
  553. //// DEBUG
  554. if( Header.dwMsgId == 0xFFFFFFFF )
  555. {
  556. DNASSERT( FALSE );
  557. }
  558. hResultCode = AddData(reinterpret_cast<BYTE*>(&Header),sizeof(DPL_MSGQ_HEADER));
  559. DNASSERT(hResultCode == DPN_OK);
  560. hResultCode = AddData(pBuffer,dwSize);
  561. DNASSERT(hResultCode == DPN_OK);
  562. bDone = TRUE;
  563. IndicateMessage();
  564. }
  565. Unlock();
  566. hResultCode = DPN_OK;
  567. }
  568. }
  569. else
  570. {
  571. DPFX(DPFPREP, 5,"Message needs to be fragmented");
  572. DNASSERT(FALSE);
  573. hResultCode = DPNERR_GENERIC;
  574. #pragma TODO(a-minara,"Implement this")
  575. }
  576. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  577. return(hResultCode);
  578. }
  579. //**********************************************************************
  580. // ------------------------------
  581. // DPLIsApplicationAvailable
  582. //
  583. // Entry: const DWORD dwPID PID to check
  584. //
  585. // Exit: BOOL TRUE If the application's queue's flags were retrieved successfully
  586. // and the application is waiting for a connection
  587. // FALSE Otherwise
  588. // ------------------------------
  589. #undef DPF_MODNAME
  590. #define DPF_MODNAME "DPLIsApplicationAvailable"
  591. BOOL DPLIsApplicationAvailable(const DWORD dwPID)
  592. {
  593. BOOL bReturnCode;
  594. CMessageQueue MessageQueue;
  595. DPFX(DPFPREP, 3,"Parameters: dwPID [%lx]",dwPID);
  596. if (MessageQueue.Open(dwPID,DPL_MSGQ_OBJECT_SUFFIX_APPLICATION,DPL_MSGQ_SIZE,
  597. INFINITE, DPL_MSGQ_OPEN_FLAG_NO_CREATE) != DPN_OK)
  598. {
  599. DPFERR("Could not open Msg Queue");
  600. return(FALSE);
  601. }
  602. bReturnCode = MessageQueue.IsAvailable();
  603. MessageQueue.Close();
  604. DPFX(DPFPREP, 3,"Returning: [%ld]",bReturnCode);
  605. return(bReturnCode);
  606. }
  607. //**********************************************************************
  608. // ------------------------------
  609. // DPLMakeApplicationUnavailable
  610. //
  611. // Entry: const DWORD dwPID PID to check
  612. //
  613. // Exit: HRESULT DPN_OK If the application was waiting for a connection
  614. // and made unavailable
  615. // DPNERR_INVALIDAPPLICATION
  616. // ------------------------------
  617. #undef DPF_MODNAME
  618. #define DPF_MODNAME "DPLMakeApplicationUnavailable"
  619. HRESULT DPLMakeApplicationUnavailable(const DWORD dwPID)
  620. {
  621. HRESULT hResultCode;
  622. CMessageQueue MessageQueue;
  623. DPFX(DPFPREP, 3,"Parameters: dwPID [%lx]",dwPID);
  624. if (MessageQueue.Open(dwPID,DPL_MSGQ_OBJECT_SUFFIX_APPLICATION,DPL_MSGQ_SIZE,
  625. DPL_MSGQ_OPEN_FLAG_NO_CREATE,INFINITE) != DPN_OK)
  626. {
  627. DPFERR("Could not open Msg Queue");
  628. return(DPNERR_INVALIDAPPLICATION);
  629. }
  630. if ((hResultCode = MessageQueue.MakeUnavailable()) != DPN_OK)
  631. {
  632. DPFERR("Could not make application unavailable");
  633. hResultCode = DPNERR_INVALIDAPPLICATION;
  634. }
  635. MessageQueue.Close();
  636. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  637. return(hResultCode);
  638. }
  639. //**********************************************************************
  640. // ------------------------------
  641. // DPLProcessMessageQueue
  642. //
  643. // Entry:
  644. //
  645. // Exit: HRESULT DPN_OK If the application was waiting for a connection
  646. // and made unavailable
  647. // DPNERR_INVALIDAPPLICATION
  648. // ------------------------------
  649. #undef DPF_MODNAME
  650. #define DPF_MODNAME "DPLProcessMessageQueue"
  651. DWORD WINAPI DPLProcessMessageQueue(PVOID pvReceiveQueue)
  652. {
  653. HRESULT hResultCode;
  654. DPL_MSGQ_HEADER dplMsgHeader;
  655. BYTE *pData;
  656. BYTE *pBuffer = NULL;
  657. DWORD dwBufferSize = 0;
  658. DWORD dwSize;
  659. CMessageQueue *pReceiveQueue;
  660. BYTE *pMsg;
  661. DWORD dwWaitResult;
  662. DPFX(DPFPREP, 3,"Parameters: (none)");
  663. COM_CoInitialize(NULL);
  664. pReceiveQueue = static_cast<CMessageQueue*>(pvReceiveQueue);
  665. // Indicate we are running
  666. pReceiveQueue->MakeReceiving();
  667. while(1)
  668. {
  669. dwWaitResult = pReceiveQueue->WaitForMessages();
  670. while( 1 )
  671. {
  672. dwSize = dwBufferSize;
  673. hResultCode = pReceiveQueue->GetNextMessage(&dplMsgHeader, pBuffer, &dwSize);
  674. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  675. {
  676. if( pBuffer )
  677. delete [] pBuffer;
  678. pBuffer = new BYTE[dwSize];
  679. if( pBuffer == NULL )
  680. {
  681. DPFX(DPFPREP, 0, "Error allocating memory" );
  682. DNASSERT( FALSE );
  683. goto EXIT_DPLProcessMessageQueue;
  684. }
  685. dwBufferSize = dwSize;
  686. }
  687. else if( FAILED( hResultCode ) )
  688. {
  689. DPFX(DPFPREP, 0, "Error while getting messages from the queue" );
  690. DNASSERT( FALSE );
  691. goto EXIT_DPLProcessMessageQueue;
  692. }
  693. else
  694. {
  695. break;
  696. }
  697. }
  698. DPFX(DPFPREP, 5,"dwMsgId [0x%lx] dwTotalSize [0x%lx] dwCurrentSize [0x%lx] dwCurrentOffset [0x%lx] ",
  699. dplMsgHeader.dwMsgId, dplMsgHeader.dwTotalSize, dplMsgHeader.dwCurrentSize,
  700. dplMsgHeader.dwCurrentOffset );
  701. switch(dplMsgHeader.dwMsgId)
  702. {
  703. case DPL_MSGQ_MSGID_IDLE:
  704. {
  705. DPFX(DPFPREP, 6,"Idle message fired" );
  706. DWORD dwMsgId = DPL_MSGID_INTERNAL_IDLE_TIMEOUT;
  707. // 7/17/2000(RichGr) - IA64: Change last parm from sizeof(DWORD) to sizeof(BYTE*).
  708. hResultCode = pReceiveQueue->CallMessageHandler(NULL,DPL_MSGQ_MSGFLAGS_USER1,(BYTE *) &dwMsgId,sizeof(BYTE*));
  709. }
  710. break;
  711. case DPL_MSGQ_MSGID_SEND:
  712. {
  713. DPFX(DPFPREP, 5,"DPL_MSGQ_MSGID_SEND");
  714. hResultCode = pReceiveQueue->CallMessageHandler(dplMsgHeader.hSender,dplMsgHeader.dwFlags,pBuffer,dwSize);
  715. break;
  716. }
  717. case DPL_MSGQ_MSGID_TERMINATE:
  718. {
  719. DPFX(DPFPREP, 5,"DPL_MSGQ_MSGID_TERMINATE");
  720. hResultCode = DPN_OK;
  721. goto EXIT_DPLProcessMessageQueue;
  722. break;
  723. }
  724. default:
  725. {
  726. DPFX(DPFPREP, 5,"UNKNOWN - should never get here");
  727. DNASSERT(FALSE);
  728. hResultCode = DPNERR_GENERIC;
  729. goto EXIT_DPLProcessMessageQueue;
  730. break;
  731. }
  732. }
  733. }
  734. EXIT_DPLProcessMessageQueue:
  735. if( pBuffer )
  736. delete [] pBuffer;
  737. // Indicate we are no longer running
  738. pReceiveQueue->MakeNotReceiving();
  739. COM_CoUninitialize();
  740. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  741. return(hResultCode);
  742. }