Leaked source code of windows server 2003
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.

698 lines
20 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: fifqdbg.cpp
  5. //
  6. // Description: Implementation for CFifoQueueDbgIterator class.
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 9/13/99 - MikeSwa Created
  12. //
  13. // Copyright (C) 1999 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #define _ANSI_UNICODE_STRINGS_DEFINED_
  17. #include "aqincs.h"
  18. #ifdef PLATINUM
  19. #include "ptrwinst.h"
  20. #include "ptntdefs.h"
  21. #include "ptntintf.h"
  22. #else //PLATINUM
  23. #include "rwinst.h"
  24. #endif //PLATINUM
  25. #include <fifoqdbg.h>
  26. #include <fifoqimp.h>
  27. #include <smtpconn.h>
  28. #define MIN(x, y) ((x) > (y) ? (y) : (x))
  29. //---[ GetQueueType ]----------------------------------------------------------
  30. //
  31. //
  32. // Description:
  33. // Determines the queue type for a given ptr
  34. // Parameters:
  35. // hCurrentProcess Handle to the debuggee process
  36. // pvAddressOtherProc Addess of the DMQ in the debugee process
  37. // Returns:
  38. // AQ_QUEUE_TYPE_UNKNOWN Queue type cannot be determined
  39. // AQ_QUEUE_TYPE_FIFOQ Queue is a CFifoQ
  40. // AQ_QUEUE_TYPE_DMQ Queue is a CDestMsgQueue
  41. // AQ_QUEUE_TYPE_LMQ Queue is a CLinkMsgQueue
  42. // History:
  43. // 10/21/1999 - MikeSwa Created
  44. //
  45. //-----------------------------------------------------------------------------
  46. AQ_QUEUE_TYPE CQueueDbgIterator::GetQueueType(HANDLE hCurrentProcess, PVOID pvAddressOtherProc)
  47. {
  48. BYTE pbQueueBuffer[100];
  49. ZeroMemory(pbQueueBuffer, sizeof(pbQueueBuffer));
  50. if (!ReadMemory(pvAddressOtherProc, pbQueueBuffer,
  51. sizeof(pbQueueBuffer), NULL))
  52. return AQ_QUEUE_TYPE_UNKNOWN;
  53. if (FIFOQ_SIG == ((CFifoQueue<PVOID *> *)pbQueueBuffer)->m_dwSignature)
  54. return AQ_QUEUE_TYPE_FIFOQ;
  55. if (DESTMSGQ_SIG == ((CDestMsgQueue *)pbQueueBuffer)->m_dwSignature)
  56. return AQ_QUEUE_TYPE_DMQ;
  57. if (LINK_MSGQ_SIG == ((CLinkMsgQueue *)pbQueueBuffer)->m_dwSignature)
  58. return AQ_QUEUE_TYPE_LMQ;
  59. return AQ_QUEUE_TYPE_UNKNOWN;
  60. }
  61. #define pvGetNextPage(pvCurrent) ((PVOID) ((CFifoQueuePage<PVOID> *)pvCurrent)->m_pfqpNext)
  62. CFifoQueueDbgIterator::CFifoQueueDbgIterator(PWINDBG_EXTENSION_APIS pApis)
  63. {
  64. m_iCurrentPage = 0;
  65. m_iCurrentIndexInPage = 0;
  66. m_cPagesLoaded = 0;
  67. m_iHeadIndex = 0;
  68. m_iTailIndex = 0;
  69. pExtensionApis = pApis;
  70. ZeroMemory(m_pbQueueBuffer, sizeof(m_pbQueueBuffer));
  71. };
  72. CFifoQueueDbgIterator::~CFifoQueueDbgIterator()
  73. {
  74. PVOID pvCurrent = NULL;
  75. PVOID pvNext = NULL;
  76. pvCurrent = ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead;
  77. while (pvCurrent)
  78. {
  79. pvNext = pvGetNextPage(pvCurrent);
  80. free(pvCurrent);
  81. pvCurrent = pvNext;
  82. }
  83. }
  84. BOOL CFifoQueueDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc)
  85. {
  86. DWORD cbBytes = 0;
  87. PVOID pvPageOtherProc = NULL;
  88. PVOID pvPageThisProc = NULL;
  89. PVOID pvPreviousPageThisProc = NULL;
  90. //Read the entire queue structure in memory
  91. if (!ReadMemory(pvAddressOtherProc, m_pbQueueBuffer,
  92. sizeof(m_pbQueueBuffer), NULL))
  93. return FALSE;
  94. //Iterate over the previous pointers from the head page
  95. pvPageOtherProc = ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead;
  96. ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead = NULL;
  97. while (pvPageOtherProc)
  98. {
  99. pvPageThisProc = malloc(sizeof(CFifoQueuePage<PVOID>));
  100. if (!pvPageThisProc)
  101. return FALSE;
  102. if (pvPreviousPageThisProc)
  103. {
  104. ((CFifoQueuePage<PVOID> *)pvPreviousPageThisProc)->m_pfqpNext =
  105. (CFifoQueuePage<PVOID> *) pvPageThisProc;
  106. }
  107. else
  108. {
  109. ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead =
  110. (CFifoQueuePage<PVOID> *) pvPageThisProc;
  111. }
  112. if (!ReadMemory(pvPageOtherProc,
  113. pvPageThisProc, sizeof(CFifoQueuePage<PVOID>), NULL))
  114. {
  115. if (pvPreviousPageThisProc)
  116. ((CFifoQueuePage<PVOID> *)pvPreviousPageThisProc)->m_pfqpNext = NULL;
  117. else
  118. ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead = NULL;
  119. free(pvPageThisProc);
  120. return FALSE;
  121. }
  122. if (!pvPreviousPageThisProc)
  123. {
  124. //This is the head page. save index
  125. m_iHeadIndex = (DWORD) ((DWORD_PTR)
  126. (((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_ppqdataHead -
  127. ((CFifoQueuePage<PVOID> *)pvPageOtherProc)->m_rgpqdata));
  128. m_iCurrentIndexInPage = m_iHeadIndex;
  129. }
  130. //save tail index... in case this is the last page
  131. m_iTailIndex = (DWORD) ((DWORD_PTR)
  132. (((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_ppqdataTail -
  133. ((CFifoQueuePage<PVOID> *)pvPageOtherProc)->m_rgpqdata));
  134. pvPreviousPageThisProc = pvPageThisProc;
  135. pvPageOtherProc = pvGetNextPage(pvPageThisProc);
  136. ((CFifoQueuePage<PVOID> *)pvPreviousPageThisProc)->m_pfqpNext = NULL;
  137. m_cPagesLoaded++;
  138. }
  139. return TRUE;
  140. }
  141. DWORD CFifoQueueDbgIterator::cGetCount()
  142. {
  143. return ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_cQueueEntries;
  144. }
  145. PVOID CFifoQueueDbgIterator::pvGetNext()
  146. {
  147. PVOID pvCurrentPage = ((CFifoQueue<PVOID> *)m_pbQueueBuffer)->m_pfqpHead;
  148. PVOID pvData = NULL;
  149. DWORD i = 0;
  150. if (!pvCurrentPage)
  151. return NULL;
  152. //Loop over empty entries (left by DSN generation) or until
  153. //we reach the end of the queue
  154. do
  155. {
  156. //Figure out if we are on a page boundary
  157. if (FIFOQ_QUEUE_PAGE_SIZE == m_iCurrentIndexInPage)
  158. {
  159. m_iCurrentIndexInPage = 0;
  160. m_iCurrentPage++;
  161. }
  162. //Get current page
  163. for (i = 0; i < m_iCurrentPage; i++)
  164. {
  165. pvCurrentPage = pvGetNextPage(pvCurrentPage);
  166. if (!pvCurrentPage)
  167. return NULL;
  168. }
  169. if (!((CFifoQueuePage<PVOID> *)pvCurrentPage)->m_rgpqdata)
  170. return NULL;
  171. //Get data from current page
  172. pvData = ((CFifoQueuePage<PVOID> *)pvCurrentPage)->m_rgpqdata[m_iCurrentIndexInPage];
  173. if ((m_iCurrentIndexInPage > m_iTailIndex) && !pvGetNextPage(pvCurrentPage))
  174. {
  175. //We at the end of data
  176. return NULL;
  177. }
  178. m_iCurrentIndexInPage++;
  179. } while (!pvData);
  180. return pvData;
  181. }
  182. //---[ CDMQDbgIterator ]-------------------------------------------------------
  183. //
  184. //
  185. // Description:
  186. // Constructor for CDMQDbgIterator
  187. // Parameters:
  188. // pApis A ptr to the PWINDBG_EXTENSION_APIS struct passed in by
  189. // the debugger.
  190. // Returns:
  191. // -
  192. // History:
  193. // 10/21/1999 - MikeSwa Created
  194. //
  195. //-----------------------------------------------------------------------------
  196. CDMQDbgIterator::CDMQDbgIterator(PWINDBG_EXTENSION_APIS pApis)
  197. {
  198. ZeroMemory(m_pbDMQBuffer, sizeof(m_pbDMQBuffer));
  199. ZeroMemory(m_pvFifoQOtherProc, sizeof(m_pvFifoQOtherProc));
  200. ZeroMemory(m_szName, sizeof(m_szName));
  201. m_pdmq = (CDestMsgQueue *)m_pbDMQBuffer;
  202. m_iCurrentFifoQ = 0;
  203. m_cCount = 0;
  204. pExtensionApis = pApis;
  205. m_cItemsReturnedThisQueue = 0;
  206. }
  207. //---[ CDMQDbgIterator::fInit ]------------------------------------------------
  208. //
  209. //
  210. // Description:
  211. // Initializes the iterator (and the iterators for all its queues
  212. // Parameters:
  213. // hCurrentProcess Handle to the debuggee process
  214. // pvAddressOtherProc Addess of the DMQ in the debugee process
  215. // Returns:
  216. // TRUE on success
  217. // FALSE otherwise
  218. // History:
  219. // 10/21/1999 - MikeSwa Created
  220. //
  221. //-----------------------------------------------------------------------------
  222. BOOL CDMQDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc)
  223. {
  224. DWORD i = 0;
  225. PVOID pvQueue = NULL;
  226. BOOL fVerbose = TRUE && pExtensionApis;
  227. BYTE pbDomainEntry[sizeof(CDomainEntry)];
  228. CDomainEntry *pdentry = (CDomainEntry *)pbDomainEntry;
  229. if (!ReadMemory(pvAddressOtherProc, m_pbDMQBuffer,
  230. sizeof(m_pbDMQBuffer), NULL))
  231. {
  232. if (fVerbose) dprintf("ReadMemory failex 0x%X\n", GetLastError());
  233. return FALSE;
  234. }
  235. if (DESTMSGQ_SIG != m_pdmq->m_dwSignature)
  236. {
  237. if (fVerbose) dprintf("Bad signature\n");
  238. return FALSE;
  239. }
  240. //Get domain if possible
  241. if (ReadMemory(m_pdmq->m_dmap.m_pdentryDomainID,
  242. pbDomainEntry, sizeof(pbDomainEntry), NULL))
  243. {
  244. ReadMemory(pdentry->m_szDomainName, m_szName,
  245. (DWORD)MIN((sizeof(m_szName)-1), (pdentry->m_cbDomainName+1)), NULL);
  246. }
  247. for (i = 0; i < NUM_PRIORITIES; i++)
  248. {
  249. m_rgfifoqdbg[i].SetApis(pExtensionApis);
  250. pvQueue = m_pdmq->m_rgpfqQueues[i];
  251. m_pvFifoQOtherProc[i] = pvQueue;
  252. if (pvQueue)
  253. {
  254. if (!m_rgfifoqdbg[i].fInit(hCurrentProcess, pvQueue))
  255. {
  256. if (fVerbose) dprintf("Cannot init queue %d at 0x%X\n", i, pvQueue);
  257. return FALSE;
  258. }
  259. m_cCount += m_rgfifoqdbg[i].cGetCount();
  260. }
  261. }
  262. //Init retry queue
  263. m_rgfifoqdbg[NUM_PRIORITIES].SetApis(pExtensionApis);
  264. pvQueue = (((PBYTE)pvAddressOtherProc) + FIELD_OFFSET(CDestMsgQueue, m_fqRetryQueue));
  265. m_pvFifoQOtherProc[NUM_PRIORITIES] = pvQueue;
  266. if (pvQueue)
  267. {
  268. if (!m_rgfifoqdbg[NUM_PRIORITIES].fInit(hCurrentProcess, pvQueue))
  269. {
  270. if (fVerbose) dprintf("Cannon init retry queue at 0x%X\n", pvQueue);
  271. return FALSE;
  272. }
  273. m_cCount += m_rgfifoqdbg[NUM_PRIORITIES].cGetCount();
  274. }
  275. return TRUE;
  276. }
  277. //---[ CDMQDbgIterator::pvGetNext ]--------------------------------------------
  278. //
  279. //
  280. // Description:
  281. // Gets the next item from the DMQ
  282. // Parameters:
  283. // -
  284. // Returns:
  285. // An ptr to the item in the debuggee process on success
  286. // NULL when there are no more items
  287. // History:
  288. // 10/21/1999 - MikeSwa Created
  289. //
  290. //-----------------------------------------------------------------------------
  291. PVOID CDMQDbgIterator::pvGetNext()
  292. {
  293. PVOID pvItem = NULL;
  294. while (m_iCurrentFifoQ <= NUM_PRIORITIES)
  295. {
  296. if (m_pvFifoQOtherProc[m_iCurrentFifoQ])
  297. {
  298. if (m_rgfifoqdbg[m_iCurrentFifoQ].cGetCount())
  299. {
  300. pvItem = m_rgfifoqdbg[m_iCurrentFifoQ].pvGetNext();
  301. //If we found an item we are done
  302. if (pvItem)
  303. {
  304. //If it is the first item annouce this queue
  305. if (!m_cItemsReturnedThisQueue && pExtensionApis)
  306. {
  307. dprintf("Dumping FifoQueue at address 0x%08X:\n",
  308. m_pvFifoQOtherProc[m_iCurrentFifoQ]);
  309. }
  310. m_cItemsReturnedThisQueue++;
  311. break;
  312. }
  313. }
  314. }
  315. m_iCurrentFifoQ++;
  316. m_cItemsReturnedThisQueue = 0;
  317. }
  318. return pvItem;
  319. }
  320. //---[ CQueueDbgIterator ]-----------------------------------------------------
  321. //
  322. //
  323. // Description:
  324. // Constructor for CQueueDbgIterator
  325. // Parameters:
  326. // pApis A ptr to the PWINDBG_EXTENSION_APIS struct passed in by
  327. // the debugger.
  328. // Returns:
  329. // -
  330. // History:
  331. // 10/21/1999 - MikeSwa Created
  332. //
  333. //-----------------------------------------------------------------------------
  334. CQueueDbgIterator::CQueueDbgIterator(PWINDBG_EXTENSION_APIS pApis)
  335. {
  336. pExtensionApis = pApis;
  337. m_pqdbgi = NULL;
  338. m_QueueType = AQ_QUEUE_TYPE_UNKNOWN;
  339. }
  340. //---[ CQueueDbgIterator::fInit ]----------------------------------------------
  341. //
  342. //
  343. // Description:
  344. // Initialized generic queue iterator. Will determine the type
  345. // of queue and initialize the correct type-specific iterator.
  346. // Parameters:
  347. // hCurrentProcess Handle to the debuggee process
  348. // pvAddressOtherProc Addess of the DMQ in the debugee process
  349. // Returns:
  350. // TRUE on success
  351. // FALSE otherwise
  352. // History:
  353. // 10/21/1999 - MikeSwa Created
  354. //
  355. //-----------------------------------------------------------------------------
  356. BOOL CQueueDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc)
  357. {
  358. LPSTR szQueueType = "unknown";
  359. m_QueueType = GetQueueType(hCurrentProcess, pvAddressOtherProc);
  360. switch (m_QueueType)
  361. {
  362. case AQ_QUEUE_TYPE_DMQ:
  363. m_pqdbgi = (IQueueDbgIterator *) &m_dmqdbg;
  364. szQueueType = "DMQ";
  365. break;
  366. case AQ_QUEUE_TYPE_FIFOQ:
  367. m_pqdbgi = (IQueueDbgIterator *) &m_fifoqdbg;
  368. szQueueType = "CFifoQueue";
  369. break;
  370. case AQ_QUEUE_TYPE_LMQ:
  371. m_pqdbgi = (IQueueDbgIterator *) &m_lmqdbg;
  372. szQueueType = "LMQ";
  373. break;
  374. default:
  375. return FALSE;
  376. }
  377. if (!m_pqdbgi)
  378. return FALSE;
  379. m_pqdbgi->SetApis(pExtensionApis);
  380. if (!m_pqdbgi->fInit(hCurrentProcess, pvAddressOtherProc))
  381. return FALSE;
  382. if (pExtensionApis)
  383. {
  384. dprintf("Dumping %s (%s) at address 0x%08X:\n",
  385. szQueueType, m_pqdbgi->szGetName(), pvAddressOtherProc);
  386. }
  387. return TRUE;
  388. }
  389. //---[ CQueueDbgIterator::cGetCount ]------------------------------------------
  390. //
  391. //
  392. // Description:
  393. // Returns count of items in queue
  394. // Parameters:
  395. // -
  396. // Returns:
  397. // count of items in queue
  398. // History:
  399. // 10/21/1999 - MikeSwa Created
  400. //
  401. //-----------------------------------------------------------------------------
  402. DWORD CQueueDbgIterator::cGetCount()
  403. {
  404. if (!m_pqdbgi)
  405. return 0;
  406. else
  407. return m_pqdbgi->cGetCount();
  408. }
  409. //---[ CQueueDbgIterator::pvGetNext ]------------------------------------------
  410. //
  411. //
  412. // Description:
  413. // Returns the next item pointed to by the iterator
  414. // Parameters:
  415. // -
  416. // Returns:
  417. // Pointer to next item in debugee process on success
  418. // NULL if no more items or failure
  419. // History:
  420. // 10/21/1999 - MikeSwa Created
  421. //
  422. //-----------------------------------------------------------------------------
  423. PVOID CQueueDbgIterator::pvGetNext()
  424. {
  425. if (!m_pqdbgi)
  426. return NULL;
  427. else
  428. return m_pqdbgi->pvGetNext();
  429. }
  430. //---[ CQueueDbgIterator::szGetName ]------------------------------------------
  431. //
  432. //
  433. // Description:
  434. // Returns the name of the iterator
  435. // Parameters:
  436. // -
  437. // Returns:
  438. // Pointer to string for iterator
  439. // NULL if no name
  440. // History:
  441. // 10/22/1999 - MikeSwa Created
  442. //
  443. //-----------------------------------------------------------------------------
  444. LPSTR CQueueDbgIterator::szGetName()
  445. {
  446. if (!m_pqdbgi)
  447. return NULL;
  448. else
  449. return m_pqdbgi->szGetName();
  450. }
  451. //---[ CLMQDbgIterator::CLMQDbgIterator ]--------------------------------------
  452. //
  453. //
  454. // Description:
  455. //
  456. // Parameters:
  457. //
  458. // Returns:
  459. //
  460. // History:
  461. // 10/22/1999 - MikeSwa Created
  462. //
  463. //-----------------------------------------------------------------------------
  464. CLMQDbgIterator::CLMQDbgIterator(PWINDBG_EXTENSION_APIS pApis)
  465. {
  466. ZeroMemory(m_pbLMQBuffer, sizeof(m_pbLMQBuffer));
  467. ZeroMemory(m_rgpvDMQOtherProc, sizeof(m_rgpvDMQOtherProc));
  468. ZeroMemory(m_szName, sizeof(m_szName));
  469. ZeroMemory(m_rgpvItemsPendingDelivery, sizeof(m_rgpvItemsPendingDelivery));
  470. ZeroMemory(m_rgpvConnectionsOtherProc, sizeof(m_rgpvConnectionsOtherProc));
  471. m_plmq = (CLinkMsgQueue *)m_pbLMQBuffer;
  472. m_iCurrentDMQ = 0;
  473. m_cCount = 0;
  474. m_cItemsThisDMQ = 0;
  475. m_cPending = 0;
  476. pExtensionApis = pApis;
  477. }
  478. //---[ CLMQDbgIterator::fInit ]------------------------------------------------
  479. //
  480. //
  481. // Description:
  482. // Initializes iterator for CLinkMsgQueue
  483. // Parameters:
  484. // hCurrentProcess Handle to the debuggee process
  485. // pvAddressOtherProc Addess of the DMQ in the debugee process
  486. // Returns:
  487. //
  488. // History:
  489. // 10/22/1999 - MikeSwa Created
  490. //
  491. //-----------------------------------------------------------------------------
  492. BOOL CLMQDbgIterator::fInit(HANDLE hCurrentProcess, PVOID pvAddressOtherProc)
  493. {
  494. DWORD i = 0;
  495. PLIST_ENTRY pliCurrent = NULL;
  496. PLIST_ENTRY pliHead = NULL;
  497. BYTE pbConnection[sizeof(CSMTPConn)];
  498. CSMTPConn *pConn = (CSMTPConn *)pbConnection;
  499. PVOID pvPending = NULL;
  500. PVOID pvConnOtherProc = NULL;
  501. BOOL fVerbose = TRUE && pExtensionApis;
  502. if (!ReadMemory(pvAddressOtherProc, m_pbLMQBuffer,
  503. sizeof(m_pbLMQBuffer), NULL))
  504. {
  505. if (fVerbose) dprintf("ReadMemory failex 0x%X\n", GetLastError());
  506. return FALSE;
  507. }
  508. if (LINK_MSGQ_SIG != m_plmq->m_dwSignature)
  509. {
  510. if (fVerbose) dprintf("Signature does not match\n");
  511. return FALSE;
  512. }
  513. //Read in address of all the queues for this link
  514. //$$TODO - Support more than 1 quick list
  515. memcpy(m_rgpvDMQOtherProc, m_plmq->m_qlstQueues.m_rgpvData,
  516. sizeof(m_rgpvDMQOtherProc));
  517. //Read in name of link
  518. ReadMemory(m_plmq->m_szSMTPDomain, m_szName,
  519. (DWORD)MIN((sizeof(m_szName)-1), (m_plmq->m_cbSMTPDomain+1)), NULL);
  520. for (i = 0; i < MAX_QUEUES_PER_LMQ; i++)
  521. {
  522. if (m_rgpvDMQOtherProc[i])
  523. {
  524. m_rgdmqdbg[i].SetApis(pExtensionApis);
  525. if (!m_rgdmqdbg[i].fInit(hCurrentProcess, m_rgpvDMQOtherProc[i]))
  526. {
  527. if (fVerbose)
  528. dprintf("Unable to init DMQ at 0x%X\n", m_rgpvDMQOtherProc[i]);
  529. return FALSE;
  530. }
  531. m_cCount += m_rgdmqdbg[i].cGetCount();
  532. }
  533. }
  534. //Get the messages pending on a connection
  535. pliCurrent = m_plmq->m_liConnections.Flink;
  536. //Loop through connections and save those with pending messages.
  537. while (pliHead != pliCurrent)
  538. {
  539. pvConnOtherProc = ((PBYTE) pliCurrent)-FIELD_OFFSET(CSMTPConn, m_liConnections);
  540. if (!ReadMemory(pvConnOtherProc, pbConnection,
  541. sizeof(pbConnection), NULL))
  542. {
  543. break;
  544. }
  545. pliCurrent = pConn->m_liConnections.Flink;
  546. if (!pliHead)
  547. pliHead = pConn->m_liConnections.Blink;
  548. pvPending = pConn->m_dcntxtCurrentDeliveryContext.m_pmsgref;
  549. if (pvPending)
  550. {
  551. m_rgpvConnectionsOtherProc[m_cPending] = pvConnOtherProc;
  552. m_rgpvItemsPendingDelivery[m_cPending] = pvPending;
  553. m_cPending++;
  554. m_cCount++;
  555. }
  556. if (m_cPending >= MAX_CONNECTIONS_PER_LMQ)
  557. break;
  558. }
  559. return TRUE;
  560. }
  561. //---[ CLMQDbgIterator::pvGetNext ]--------------------------------------------
  562. //
  563. //
  564. // Description:
  565. // Gets the next item in the current DMQ. Moves to next DMQ when that
  566. // is emtpy
  567. // Parameters:
  568. // -
  569. // Returns:
  570. // Next item on success
  571. // NULL when empty or failure
  572. // History:
  573. // 10/22/1999 - MikeSwa Created
  574. //
  575. //-----------------------------------------------------------------------------
  576. PVOID CLMQDbgIterator::pvGetNext()
  577. {
  578. PVOID pvItem = NULL;
  579. while (m_iCurrentDMQ < MAX_QUEUES_PER_LMQ)
  580. {
  581. if (m_rgpvDMQOtherProc[m_iCurrentDMQ])
  582. {
  583. if (!m_cItemsThisDMQ && m_rgdmqdbg[m_iCurrentDMQ].cGetCount())
  584. {
  585. if (pExtensionApis)
  586. {
  587. dprintf("Dumping DMQ (%s) at address 0x%08X:\n",
  588. m_rgdmqdbg[m_iCurrentDMQ].szGetName(),
  589. m_rgpvDMQOtherProc[m_iCurrentDMQ]);
  590. }
  591. }
  592. pvItem = m_rgdmqdbg[m_iCurrentDMQ].pvGetNext();
  593. if (pvItem)
  594. {
  595. //Check if this is the first item for this DMQ
  596. m_cItemsThisDMQ++;
  597. break;
  598. }
  599. }
  600. m_iCurrentDMQ++;
  601. m_cItemsThisDMQ = 0;
  602. }
  603. //If the queues are empty, dump the connections
  604. if (!pvItem && m_cPending)
  605. {
  606. m_cPending--;
  607. if (pExtensionApis)
  608. {
  609. dprintf("Dumping Connection at address 0x%08X:\n",
  610. m_rgpvConnectionsOtherProc[m_cPending]);
  611. }
  612. pvItem = m_rgpvItemsPendingDelivery[m_cPending];
  613. }
  614. return pvItem;
  615. }