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.

714 lines
19 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: dsthread.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // FILE: dsThread.cpp
  11. #include "stdafx.h"
  12. #include "dssnap.h" // Note: this has to be before dsthread.h
  13. #include "dsthread.h"
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. void WaitForThreadShutdown(HANDLE* phThreadArray, DWORD dwCount)
  20. {
  21. TRACE(L"entering WaitForThreadShutdown()\n");
  22. while (TRUE)
  23. {
  24. //
  25. // NOTE: this will block the console. This the intended behavior
  26. // to keep MMC from breaking on none re-entrant code.
  27. //
  28. DWORD dwWaitResult = WaitForMultipleObjectsEx(
  29. dwCount,
  30. phThreadArray, // handle array
  31. TRUE, // wait for all
  32. INFINITE, // time-out
  33. FALSE);// signal completion routine
  34. //TRACE(L"after MsgWaitForMultipleObjects()\n");
  35. //TRACE(L"dwWaitResult = 0x%x\n", dwWaitResult);
  36. if (dwWaitResult == WAIT_OBJECT_0 ||
  37. (WAIT_FAILED == dwWaitResult))
  38. {
  39. // woke up because the thread handle got signalled,
  40. // or because the handle is no longer valid (thread already terminated)
  41. // can proceed
  42. TRACE(L"WaitForMultipleObjectsEx() succeeded\n");
  43. break;
  44. }
  45. else
  46. {
  47. TRACE(L"WaitForMultipleObjectsEx() return 0x%x\n", dwWaitResult);
  48. }
  49. /* Whistler bug #176012 MMC: Assert m_pScopeTree == 0
  50. This message pump causes the UI not to be blocked which means
  51. MMC can reach code that is not re-entrant.
  52. else
  53. {
  54. // woke up because there is a message in the queue
  55. // need to pump
  56. MSG msg;
  57. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  58. {
  59. TRACE(L"inside while(PeekMessage())\n");
  60. ASSERT(msg.message != WM_QUIT);
  61. DispatchMessage(&msg);
  62. }
  63. }*/
  64. } // while
  65. TRACE(L"exiting WaitForThreadShutdown()\n");
  66. }
  67. ////////////////////////////////////////////////////////////////////
  68. // CHiddenWnd
  69. const UINT CHiddenWnd::s_ThreadStartNotificationMessage = WM_USER + 1;
  70. const UINT CHiddenWnd::s_ThreadTooMuchDataNotificationMessage = WM_USER + 2;
  71. const UINT CHiddenWnd::s_ThreadHaveDataNotificationMessage = WM_USER + 3;
  72. const UINT CHiddenWnd::s_ThreadDoneNotificationMessage = WM_USER + 4;
  73. const UINT CHiddenWnd::s_SheetCloseNotificationMessage = WM_DSA_SHEET_CLOSE_NOTIFY; // propcfg.h
  74. const UINT CHiddenWnd::s_SheetCreateNotificationMessage = WM_DSA_SHEET_CREATE_NOTIFY; // propcfg.h
  75. const UINT CHiddenWnd::s_RefreshAllNotificationMessage = WM_USER + 7;
  76. const UINT CHiddenWnd::s_ThreadShutDownNotificationMessage = WM_USER + 8;
  77. BOOL CHiddenWnd::Create()
  78. {
  79. RECT rcPos;
  80. ZeroMemory(&rcPos, sizeof(RECT));
  81. HWND hWnd = CWindowImpl<CHiddenWnd>::Create( NULL, //HWND hWndParent,
  82. rcPos, //RECT& rcPos,
  83. NULL, //LPCTSTR szWindowName = NULL,
  84. WS_POPUP, //DWORD dwStyle = WS_CHILD | WS_VISIBLE,
  85. 0x0, //DWORD dwExStyle = 0,
  86. 0 //UINT nID = 0
  87. );
  88. return hWnd != NULL;
  89. }
  90. LRESULT CHiddenWnd::OnThreadStartNotification(UINT, WPARAM, LPARAM, BOOL&)
  91. {
  92. TRACE(_T("CHiddenWnd::OnThreadStartNotification()\n"));
  93. ASSERT(m_pCD != NULL);
  94. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_state == notStarted);
  95. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_nThreadID != 0);
  96. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_hThreadHandle != NULL);
  97. m_pCD->m_pBackgroundThreadInfo->m_state = running;
  98. return 1;
  99. }
  100. LRESULT CHiddenWnd::OnThreadShutDownNotification(UINT, WPARAM, LPARAM, BOOL&)
  101. {
  102. TRACE(_T("CHiddenWnd::OnThreadShutDownNotification()\n"));
  103. ASSERT(m_pCD != NULL);
  104. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_state == shuttingDown);
  105. m_pCD->m_pBackgroundThreadInfo->m_state = terminated;
  106. return 1;
  107. }
  108. LRESULT CHiddenWnd::OnThreadTooMuchDataNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  109. {
  110. TRACE(_T("CHiddenWnd::OnThreadTooMuchDataNotification()\n"));
  111. ASSERT(m_pCD != NULL);
  112. // ingnore if we are shutting down (i.e. not running state)
  113. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  114. {
  115. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  116. m_pCD->_OnTooMuchData(pUINode);
  117. }
  118. return 1;
  119. }
  120. LRESULT CHiddenWnd::OnThreadHaveDataNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  121. {
  122. TRACE(_T("CHiddenWnd::OnThreadHaveDataNotification()\n"));
  123. ASSERT(m_pCD != NULL);
  124. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  125. CThreadQueryResult* pResult = reinterpret_cast<CThreadQueryResult*>(lParam);
  126. // ingnore if we are shutting down (i.e. not running state)
  127. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  128. {
  129. m_pCD->_OnHaveData(pUINode, pResult);
  130. }
  131. else
  132. {
  133. // going down, eat up data
  134. if (pResult != NULL)
  135. delete pResult;
  136. }
  137. return 1;
  138. }
  139. LRESULT CHiddenWnd::OnThreadDoneNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  140. {
  141. HRESULT ReturnedHr = (HRESULT)lParam;
  142. ASSERT(m_pCD != NULL);
  143. // ingnore if we are shutting down (i.e. not running state)
  144. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  145. {
  146. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  147. m_pCD->_OnDone(pUINode, ReturnedHr);
  148. }
  149. return 1;
  150. }
  151. LRESULT CHiddenWnd::OnSheetCloseNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  152. {
  153. ASSERT(m_pCD != NULL);
  154. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  155. m_pCD->_OnSheetClose(pUINode);
  156. return 1;
  157. }
  158. LRESULT CHiddenWnd::OnSheetCreateNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  159. {
  160. ASSERT(m_pCD != NULL);
  161. PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo = reinterpret_cast<PDSA_SEC_PAGE_INFO>(wParam);
  162. ASSERT(pDsaSecondaryPageInfo != NULL);
  163. // ingnore if we are shutting down (i.e. not running state)
  164. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  165. {
  166. m_pCD->_OnSheetCreate(pDsaSecondaryPageInfo);
  167. }
  168. ::LocalFree(pDsaSecondaryPageInfo);
  169. return 1;
  170. }
  171. LRESULT CHiddenWnd::OnRefreshAllNotification(UINT, WPARAM, LPARAM, BOOL&)
  172. {
  173. ASSERT(m_pCD != NULL);
  174. // ingnore if we are shutting down (i.e. not running state)
  175. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  176. {
  177. m_pCD->ForceRefreshAll();
  178. }
  179. return 1;
  180. }
  181. ////////////////////////////////////////////////////////////////////
  182. // CBackgroundThreadBase
  183. CBackgroundThreadBase::CBackgroundThreadBase()
  184. {
  185. m_bAutoDelete = TRUE;
  186. m_hWnd = NULL;
  187. m_pCD = NULL;
  188. }
  189. CBackgroundThreadBase::~CBackgroundThreadBase()
  190. {
  191. }
  192. BOOL CBackgroundThreadBase::Start(HWND hWnd, CDSComponentData* pCD)
  193. {
  194. // this function executes in the context of the parent thread
  195. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  196. ASSERT(::IsWindow(hWnd));
  197. m_hWnd = hWnd;
  198. m_pCD = pCD;
  199. return CreateThread();
  200. }
  201. BOOL CBackgroundThreadBase::InitInstance()
  202. {
  203. // this function executes in the context of the child thread
  204. HRESULT hr = ::CoInitialize(NULL);
  205. if (FAILED(hr))
  206. return FALSE;
  207. return SUCCEEDED(hr);
  208. }
  209. int CBackgroundThreadBase::ExitInstance()
  210. {
  211. ::CoUninitialize();
  212. PostExitNotification();
  213. // Sleep(1000);
  214. return CWinThread::ExitInstance();
  215. }
  216. BOOL CBackgroundThreadBase::PostMessageToWnd(UINT msg, WPARAM wParam, LPARAM lParam)
  217. {
  218. ASSERT(::IsWindow(m_hWnd));
  219. return ::PostMessage(m_hWnd, msg, wParam, lParam);
  220. }
  221. ////////////////////////////////////////////////////////////////////
  222. // CDispatcherThread
  223. #define WORKER_THREAD_COUNT 2
  224. CDispatcherThread::CDispatcherThread()
  225. {
  226. m_nArrCount = WORKER_THREAD_COUNT;
  227. m_pThreadInfoArr = (CBackgroundThreadInfo*)malloc(m_nArrCount*sizeof(CBackgroundThreadInfo));
  228. if (m_pThreadInfoArr != NULL)
  229. {
  230. ZeroMemory(m_pThreadInfoArr, m_nArrCount*sizeof(CBackgroundThreadInfo));
  231. }
  232. }
  233. CDispatcherThread::~CDispatcherThread()
  234. {
  235. free(m_pThreadInfoArr);
  236. }
  237. int CDispatcherThread::Run()
  238. {
  239. TRACE(_T("CDispatcherThread::Run() starting\n"));
  240. BOOL bShuttingDown = FALSE;
  241. MSG msg;
  242. // initialize the message pump
  243. ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  244. // get let the main thread know we are entering the loop
  245. PostMessageToWnd(CHiddenWnd::s_ThreadStartNotificationMessage,0,0);
  246. BOOL bQuit = FALSE;
  247. while(!bQuit && ::GetMessage(&msg, NULL, 0, 0))
  248. {
  249. switch(msg.message)
  250. {
  251. case DISPATCH_THREAD_RUN_MSG:
  252. {
  253. if (bShuttingDown)
  254. {
  255. // going down, eat up the message
  256. CDSThreadQueryInfo* pQueryInfo = reinterpret_cast<CDSThreadQueryInfo*>(msg.lParam);
  257. // reclaim memory in the queue
  258. delete pQueryInfo;
  259. }
  260. else
  261. {
  262. // get a thread from the thread pool
  263. UINT nEntry = GetThreadEntryFromPool();
  264. ASSERT(m_pThreadInfoArr[nEntry].m_nThreadID != 0);
  265. ASSERT(m_pThreadInfoArr[nEntry].m_state == running);
  266. // forward the processing request to the thread from the pool
  267. ::PostThreadMessage(m_pThreadInfoArr[nEntry].m_nThreadID,
  268. DISPATCH_THREAD_RUN_MSG, msg.wParam, msg.lParam);
  269. // move the thread to a busy state
  270. m_pThreadInfoArr[nEntry].m_state = busy;
  271. }
  272. }
  273. break;
  274. case DISPATCH_THREAD_DONE_MSG:
  275. {
  276. UINT nThreadID = (UINT)(msg.wParam);
  277. ReturnThreadToPool(nThreadID);
  278. }
  279. break;
  280. case THREAD_SHUTDOWN_MSG:
  281. {
  282. TRACE(L"CDispatcherThread got THREAD_SHUTDOWN_MSG\n");
  283. ASSERT(!bShuttingDown);
  284. // asked to shut down
  285. bShuttingDown = TRUE;
  286. // if no threads running, we go down immediately
  287. // otherwise we have to wait for them to terminate
  288. bQuit = BroadcastShutDownAllThreads();
  289. TRACE(L"BroadcastShutDownAllThreads() returned bQuit = %d\n", bQuit);
  290. }
  291. break;
  292. case THREAD_SHUTDOWN_ACK_MSG:
  293. {
  294. TRACE(L"CDispatcherThread got THREAD_SHUTDOWN_ACK_MSG\n");
  295. ASSERT(bShuttingDown);
  296. // worker thread has gone down
  297. UINT nThreadID = (UINT)(msg.wParam);
  298. bQuit = MarkThreadAsTerminated(nThreadID);
  299. TRACE(L"MarkThreadAsTerminated() returned bQuit = %d\n", bQuit);
  300. }
  301. break;
  302. default:
  303. {
  304. // unknown message, just let it through
  305. ::DispatchMessage(&msg);
  306. } // default
  307. } //switch
  308. } // while
  309. ASSERT(bShuttingDown);
  310. // wait now for all the thread handles to become signalled
  311. WaitForAllWorkerThreadsToExit();
  312. TRACE(_T("CDispatcherThread::Run() is terminating\n"));
  313. return ExitInstance();
  314. }
  315. void CDispatcherThread::PostExitNotification()
  316. {
  317. // we are finally done shutting down, let the main thread know
  318. // that we are going down
  319. PostMessageToWnd(CHiddenWnd::s_ThreadShutDownNotificationMessage, 0, 0);
  320. TRACE(_T("CDispatcherThread::PostExitNotification() posted thread shutdown notification\n"));
  321. }
  322. UINT CDispatcherThread::_GetEntryFromArray()
  323. {
  324. UINT nFreeSlot = m_nArrCount; // set as "not found"
  325. for (UINT k=0; k<m_nArrCount; k++)
  326. {
  327. if ( (m_pThreadInfoArr[k].m_nThreadID == 0) && (nFreeSlot == m_nArrCount))
  328. nFreeSlot = k; // remember the first free slot
  329. if ((m_pThreadInfoArr[k].m_nThreadID != 0) && (m_pThreadInfoArr[k].m_state == running))
  330. return k; // found an idle running thread
  331. }
  332. // not found any idle thread, return an empty slot
  333. if (nFreeSlot == m_nArrCount)
  334. {
  335. // no free space anymore, need to reallocate array
  336. int nAlloc = m_nArrCount*2;
  337. m_pThreadInfoArr = (CBackgroundThreadInfo*)realloc(m_pThreadInfoArr, sizeof(CBackgroundThreadInfo)*nAlloc);
  338. ::ZeroMemory(&m_pThreadInfoArr[m_nArrCount], sizeof(CBackgroundThreadInfo)*m_nArrCount);
  339. nFreeSlot = m_nArrCount; // first free in new block
  340. m_nArrCount = nAlloc;
  341. }
  342. return nFreeSlot;
  343. }
  344. UINT CDispatcherThread::GetThreadEntryFromPool()
  345. {
  346. UINT nEntry = _GetEntryFromArray();
  347. // if the entry is empty, need to
  348. // spawn a thread and wait it is running
  349. if (m_pThreadInfoArr[nEntry].m_nThreadID == 0)
  350. {
  351. // create the thread
  352. CWorkerThread* pThreadObj = new CWorkerThread(m_nThreadID);
  353. ASSERT(pThreadObj != NULL);
  354. if (pThreadObj == NULL)
  355. return 0;
  356. // start the the thread
  357. ASSERT(m_pThreadInfoArr[nEntry].m_hThreadHandle == NULL);
  358. ASSERT(m_pThreadInfoArr[nEntry].m_state == notStarted);
  359. ASSERT(pThreadObj->m_bAutoDelete);
  360. if (!pThreadObj->Start(GetHiddenWnd(),GetCD()))
  361. return 0;
  362. ASSERT(pThreadObj->m_nThreadID != 0);
  363. ASSERT(pThreadObj->m_hThread != NULL);
  364. // copy the thread info we need from the thread object
  365. m_pThreadInfoArr[nEntry].m_hThreadHandle = pThreadObj->m_hThread;
  366. m_pThreadInfoArr[nEntry].m_nThreadID = pThreadObj->m_nThreadID;
  367. // wait for the thread to start
  368. MSG msg;
  369. while(TRUE)
  370. {
  371. if (::PeekMessage(&msg,(HWND)-1,WORKER_THREAD_START_MSG, WORKER_THREAD_START_MSG,
  372. PM_REMOVE))
  373. {
  374. TRACE(_T("CDispatcherThread::GetThreadFromPool() got WORKER_THREAD_START_MSG\n"));
  375. m_pThreadInfoArr[nEntry].m_state = running;
  376. break;
  377. }
  378. } // while
  379. } // if
  380. ASSERT(m_pThreadInfoArr[nEntry].m_state == running);
  381. ASSERT(m_pThreadInfoArr[nEntry].m_nThreadID != 0);
  382. return nEntry;
  383. }
  384. void CDispatcherThread::ReturnThreadToPool(UINT nThreadID)
  385. {
  386. ASSERT(nThreadID != 0);
  387. for (UINT k=0; k<m_nArrCount; k++)
  388. {
  389. if (m_pThreadInfoArr[k].m_nThreadID == nThreadID)
  390. {
  391. // return the thread to a busy state
  392. m_pThreadInfoArr[k].m_state = running;
  393. return;
  394. }
  395. }
  396. ASSERT(FALSE); // should never get here
  397. }
  398. BOOL CDispatcherThread::BroadcastShutDownAllThreads()
  399. {
  400. BOOL bQuit = TRUE;
  401. for (UINT k=0; k<m_nArrCount; k++)
  402. {
  403. if (m_pThreadInfoArr[k].m_nThreadID != 0)
  404. {
  405. ::PostThreadMessage(m_pThreadInfoArr[k].m_nThreadID, THREAD_SHUTDOWN_MSG,0,0);
  406. bQuit = FALSE;
  407. }
  408. }
  409. TRACE(L"CDispatcherThread::BroadcastShutDownAllThreads() returning %d\n", bQuit);
  410. return bQuit;
  411. }
  412. BOOL CDispatcherThread::MarkThreadAsTerminated(UINT nThreadID)
  413. {
  414. TRACE(L"CDispatcherThread::MarkThreadAsTerminated()\n");
  415. ASSERT(nThreadID != 0);
  416. for (UINT k=0; k<m_nArrCount; k++)
  417. {
  418. if (m_pThreadInfoArr[k].m_nThreadID == nThreadID)
  419. {
  420. // mark the thread as done
  421. TRACE(L"marking thread k = %d as terminated\n", k);
  422. ASSERT(m_pThreadInfoArr[k].m_state == running);
  423. m_pThreadInfoArr[k].m_state = terminated;
  424. break;
  425. }
  426. }
  427. // check if all the threads are terminated
  428. for (k=0; k<m_nArrCount; k++)
  429. {
  430. if ((m_pThreadInfoArr[k].m_nThreadID != 0) &&
  431. (m_pThreadInfoArr[k].m_state != terminated))
  432. {
  433. // at least one thread is still running
  434. return FALSE;
  435. }
  436. }
  437. // all the threads are gone (terminated state)
  438. return TRUE;
  439. }
  440. void CDispatcherThread::WaitForAllWorkerThreadsToExit()
  441. {
  442. TRACE(L"CDispatcherThread::WaitForAllWorkerThreadsToExit()\n");
  443. // wait for the dispatcher thread handle to become signalled
  444. DWORD nCount = 0;
  445. HANDLE* pHandles = new HANDLE[m_nArrCount];
  446. if (!pHandles)
  447. {
  448. TRACE(L"Failed to allocate space for the handles\n");
  449. return;
  450. }
  451. ::ZeroMemory(pHandles, sizeof(HANDLE)*m_nArrCount);
  452. for (UINT k=0; k<m_nArrCount; k++)
  453. {
  454. if (m_pThreadInfoArr[k].m_nThreadID != 0)
  455. {
  456. TRACE(L"m_pThreadInfoArr[%d].m_state = %d\n", k, m_pThreadInfoArr[k].m_state);
  457. ASSERT(m_pThreadInfoArr[k].m_state == terminated);
  458. ASSERT(m_pThreadInfoArr[k].m_hThreadHandle != NULL);
  459. pHandles[nCount++] = m_pThreadInfoArr[k].m_hThreadHandle;
  460. }
  461. }
  462. if (nCount == 0)
  463. {
  464. TRACE(L"WARNING: no worker threads to wait for!!!\n");
  465. return;
  466. }
  467. TRACE(L"before WaitForThreadShutdown() loop on %d worker threads\n", nCount);
  468. WaitForThreadShutdown(pHandles, nCount);
  469. TRACE(L"after WaitForThreadShutdown() loop on worker threads\n");
  470. #if (FALSE)
  471. TRACE(L"before WaitForMultipleObjects() on worker threads\n");
  472. WaitForMultipleObjects(nCount, pHandles, TRUE /*fWaitAll*/, INFINITE);
  473. TRACE(L"after WaitForMultipleObjects() on worker threads\n");
  474. #endif
  475. delete[] pHandles;
  476. pHandles = 0;
  477. }
  478. ////////////////////////////////////////////////////////////////////
  479. // CWorkerThread
  480. CWorkerThread::CWorkerThread(UINT nParentThreadID)
  481. : m_nMaxQueueLength(49)
  482. {
  483. ASSERT(nParentThreadID != 0);
  484. m_nParentThreadID = nParentThreadID;
  485. m_bQuit = FALSE;
  486. m_pCurrentQueryResult = NULL;
  487. m_currWParamCookie = 0;
  488. }
  489. CWorkerThread::~CWorkerThread()
  490. {
  491. ASSERT(m_pCurrentQueryResult == NULL);
  492. }
  493. int CWorkerThread::Run()
  494. {
  495. HRESULT hr = S_OK;
  496. TRACE(_T("CWorkerThread::Run() starting\n"));
  497. MSG msg;
  498. // initialize the message pump
  499. ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  500. // get let the main thread know we are entering the loop
  501. ::PostThreadMessage(m_nParentThreadID, WORKER_THREAD_START_MSG, 0,0);
  502. ASSERT(m_bQuit == FALSE);
  503. while(!m_bQuit && ::GetMessage(&msg, NULL, 0, 0))
  504. {
  505. if(msg.message == DISPATCH_THREAD_RUN_MSG)
  506. {
  507. m_currWParamCookie = msg.wParam;
  508. //::MessageBox(NULL, _T("Wait"), _T("Thread"), MB_OK);
  509. CThreadQueryInfo* pQueryInfo = reinterpret_cast<CThreadQueryInfo*>(msg.lParam);
  510. hr = GetCD()->QueryFromWorkerThread(pQueryInfo, this);
  511. // make sure we flush the result set
  512. SendCurrentQueryResult();
  513. // if we had to many items, let the hidden window know
  514. if (pQueryInfo->m_bTooMuchData)
  515. {
  516. PostMessageToWnd(CHiddenWnd::s_ThreadTooMuchDataNotificationMessage,
  517. m_currWParamCookie, (LPARAM)0);
  518. }
  519. delete pQueryInfo; // not needed anymore
  520. // tell the hidden window we are done
  521. PostMessageToWnd(CHiddenWnd::s_ThreadDoneNotificationMessage,
  522. m_currWParamCookie, (LPARAM)hr);
  523. // tell the dispatcher thread we are done processing
  524. ::PostThreadMessage(m_nParentThreadID, DISPATCH_THREAD_DONE_MSG, m_nThreadID,0);
  525. m_currWParamCookie = 0; // reset
  526. }
  527. else if (msg.message == THREAD_SHUTDOWN_MSG)
  528. {
  529. TRACE(_T("CWorkerThread::Run() got THREAD_SHUTDOWN_MSG\n"));
  530. m_bQuit = TRUE;
  531. }
  532. else
  533. {
  534. // unknown message, just let it through
  535. ::DispatchMessage(&msg);
  536. }
  537. } // while
  538. TRACE(_T("CWorkerThread::Run() is terminating\n"));
  539. return ExitInstance();
  540. }
  541. void CWorkerThread::PostExitNotification()
  542. {
  543. // we are finally done shutting down, let the main thread know
  544. // that we are going down
  545. ::PostThreadMessage(m_nParentThreadID, THREAD_SHUTDOWN_ACK_MSG, m_nThreadID,0);
  546. TRACE(_T("CWorkerThread::PostExitNotification() posted THREAD_SHUTDOWN_ACK_MSG, m_nThreadID = 0x%x\n"),
  547. m_nThreadID);
  548. }
  549. void CWorkerThread::AddToQueryResult(CUINode* pUINode)
  550. {
  551. ASSERT(!m_bQuit);
  552. if (m_pCurrentQueryResult == NULL)
  553. {
  554. m_pCurrentQueryResult = new CThreadQueryResult;
  555. }
  556. ASSERT(m_pCurrentQueryResult != NULL);
  557. m_pCurrentQueryResult->m_nodeList.AddTail(pUINode);
  558. if (m_pCurrentQueryResult->m_nodeList.GetCount() > m_nMaxQueueLength)
  559. SendCurrentQueryResult();
  560. // check to see if we are forced to abort
  561. MSG msg;
  562. if (::PeekMessage(&msg,(HWND)-1,THREAD_SHUTDOWN_MSG, THREAD_SHUTDOWN_MSG,
  563. PM_REMOVE))
  564. {
  565. TRACE(_T("CWorkerThread::AddToQueryResult() got THREAD_SHUTDOWN_MSG\n"));
  566. m_bQuit = TRUE;
  567. }
  568. }
  569. void CWorkerThread::SendCurrentQueryResult()
  570. {
  571. if(m_pCurrentQueryResult != NULL)
  572. {
  573. // wParam has the cookie, that we just ship back
  574. PostMessageToWnd(CHiddenWnd::s_ThreadHaveDataNotificationMessage,
  575. m_currWParamCookie, reinterpret_cast<LPARAM>(m_pCurrentQueryResult));
  576. m_pCurrentQueryResult = NULL;
  577. }
  578. }