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.

865 lines
19 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. handlers.cpp
  7. Implementation for non-threaded handlers and background
  8. threaded handlers.
  9. FILE HISTORY:
  10. */
  11. #include "stdafx.h"
  12. #include "handlers.h"
  13. /*---------------------------------------------------------------------------
  14. ThreadHandler implementation
  15. ---------------------------------------------------------------------------*/
  16. ThreadHandler::ThreadHandler()
  17. : m_hThread(NULL),
  18. m_hwndHidden(NULL),
  19. m_cRef(1)
  20. {
  21. }
  22. ThreadHandler::~ThreadHandler()
  23. {
  24. }
  25. IMPLEMENT_ADDREF_RELEASE(ThreadHandler)
  26. STDMETHODIMP ThreadHandler::QueryInterface(REFIID iid,void **ppv)
  27. {
  28. *ppv = 0;
  29. if (iid == IID_IUnknown)
  30. *ppv = (IUnknown *) this;
  31. else if (iid == IID_ITFSThreadHandler)
  32. *ppv = (ITFSThreadHandler *) this;
  33. else
  34. return ResultFromScode(E_NOINTERFACE);
  35. ((IUnknown *) *ppv)->AddRef();
  36. return hrOK;
  37. }
  38. /*!--------------------------------------------------------------------------
  39. ThreadHandler::StartBackgroundThread
  40. -
  41. Author:
  42. ---------------------------------------------------------------------------*/
  43. BOOL
  44. ThreadHandler::StartBackgroundThread(ITFSNode * pNode, HWND hWndHidden, ITFSQueryObject *pQuery)
  45. {
  46. CQueryObject * pquery = NULL;
  47. HRESULT hr = hrOK;
  48. BOOL bRes = TRUE;
  49. CBackgroundThread * pThread;
  50. // Store the node pointer
  51. this->m_spNode.Set(pNode);
  52. // Get the data for the hidden window
  53. m_hwndHidden = hWndHidden;
  54. Assert(m_hwndHidden);
  55. Assert(::IsWindow(m_hwndHidden));
  56. // First create the thread object (it hasn't started yet)
  57. pThread = CreateThreadObject();
  58. ASSERT(pThread != NULL);
  59. // Now that we have everything allocated, register ourselves for msgs
  60. m_uMsgBase = (INT)::SendMessage(m_hwndHidden, WM_HIDDENWND_REGISTER, TRUE, 0);
  61. Assert(m_uMsgBase);
  62. // Initialize and setup the query object
  63. CORg( pQuery->Init(this, m_hwndHidden, m_uMsgBase) );
  64. pThread->SetQueryObj(pQuery);
  65. m_spQuery.Set(pQuery);
  66. // phew, now start the thread
  67. bRes = pThread->Start();
  68. if (bRes)
  69. {
  70. if (pThread->m_hThread)
  71. {
  72. HANDLE hPseudohandle;
  73. hPseudohandle = pThread->m_hThread;
  74. BOOL bRet = DuplicateHandle(GetCurrentProcess(),
  75. hPseudohandle,
  76. GetCurrentProcess(),
  77. &m_hThread,
  78. SYNCHRONIZE,
  79. FALSE,
  80. DUPLICATE_SAME_ACCESS);
  81. if (!bRet)
  82. {
  83. DWORD dwLastErr = GetLastError();
  84. hr = HRESULT_FROM_WIN32(dwLastErr);
  85. }
  86. // NOTE::: ericdav 10/23/97
  87. // the thread is initially suspended so we can duplicate the handle
  88. // if the query object exits very quickly, the background thread object
  89. // may be destroyed before we can duplicate the handle.
  90. pThread->ResumeThread();
  91. }
  92. else
  93. {
  94. m_hThread = NULL;
  95. }
  96. }
  97. Error:
  98. if (FHrFailed(hr) || (bRes == FALSE))
  99. {
  100. // Need to do some cleanup
  101. ReleaseThreadHandler();
  102. delete pThread;
  103. bRes = FALSE;
  104. }
  105. return bRes;
  106. }
  107. /*!--------------------------------------------------------------------------
  108. ThreadHandler::ReleaseThreadHandler
  109. -
  110. Author:
  111. ---------------------------------------------------------------------------*/
  112. void ThreadHandler::ReleaseThreadHandler()
  113. {
  114. if (m_hwndHidden)
  115. {
  116. Assert(m_uMsgBase);
  117. ::SendMessage(m_hwndHidden, WM_HIDDENWND_REGISTER, FALSE, m_uMsgBase);
  118. m_hwndHidden = NULL;
  119. m_uMsgBase = 0;
  120. }
  121. if (m_spQuery)
  122. {
  123. // Signal the thread to abort
  124. m_spQuery->SetAbortEvent();
  125. m_spQuery.Release();
  126. }
  127. if (m_spNode)
  128. {
  129. m_spNode.Release();
  130. }
  131. // Trace1("%X ReleaseThreadHandler() called\n", GetCurrentThreadId());
  132. }
  133. void ThreadHandler::WaitForThreadToExit()
  134. {
  135. //$ Review: kennt, should this be INFINITE?
  136. // Ok, wait for 5 seconds, else just shutdown
  137. // If we return, we can't do anything about the return value anyway
  138. if (m_hThread)
  139. {
  140. if (WaitForSingleObjectEx(m_hThread, 10000, FALSE) != WAIT_OBJECT_0)
  141. {
  142. // Trace1("%X WaitForThreadToExit() Wait failed! \n", GetCurrentThreadId());
  143. }
  144. CloseHandle(m_hThread);
  145. m_hThread = NULL;
  146. }
  147. }
  148. CBackgroundThread* ThreadHandler::CreateThreadObject()
  149. {
  150. return new CBackgroundThread; // override if need derived tipe of object
  151. }
  152. DEBUG_DECLARE_INSTANCE_COUNTER(CHandler);
  153. /*---------------------------------------------------------------------------
  154. CHandler implementation
  155. ---------------------------------------------------------------------------*/
  156. CHandler::CHandler(ITFSComponentData *pTFSCompData)
  157. : CBaseHandler(pTFSCompData),
  158. CBaseResultHandler(pTFSCompData),
  159. m_cRef(1)
  160. {
  161. DEBUG_INCREMENT_INSTANCE_COUNTER(CHandler);
  162. m_nLockCount = 0;
  163. m_nState = 0;
  164. m_dwErr = 0;
  165. m_bExpanded = FALSE;
  166. }
  167. CHandler::~CHandler()
  168. {
  169. DEBUG_DECREMENT_INSTANCE_COUNTER(CHandler);
  170. Assert(m_nLockCount == 0);
  171. }
  172. IMPLEMENT_ADDREF_RELEASE(CHandler)
  173. STDMETHODIMP CHandler::QueryInterface(REFIID riid, LPVOID *ppv)
  174. {
  175. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  176. // Is the pointer bad?
  177. if (ppv == NULL)
  178. return E_INVALIDARG;
  179. // Place NULL in *ppv in case of failure
  180. *ppv = NULL;
  181. // This is the non-delegating IUnknown implementation
  182. if (riid == IID_IUnknown)
  183. *ppv = (LPVOID) this;
  184. else if (riid == IID_ITFSResultHandler)
  185. *ppv = (ITFSResultHandler *) this;
  186. else if (riid == IID_ITFSNodeHandler)
  187. *ppv = (ITFSNodeHandler *) this;
  188. // If we're going to return an interface, AddRef it first
  189. if (*ppv)
  190. {
  191. ((LPUNKNOWN) *ppv)->AddRef();
  192. return hrOK;
  193. }
  194. else
  195. return E_NOINTERFACE;
  196. }
  197. void
  198. CHandler::Lock()
  199. {
  200. InterlockedIncrement(&m_nLockCount);
  201. }
  202. void
  203. CHandler::Unlock()
  204. {
  205. InterlockedDecrement(&m_nLockCount);
  206. }
  207. /*!--------------------------------------------------------------------------
  208. CHandler::UserNotify
  209. Implememntation of ITFSNodeHandler::UserNotify
  210. Author: KennT
  211. ---------------------------------------------------------------------------*/
  212. STDMETHODIMP
  213. CHandler::UserNotify
  214. (
  215. ITFSNode * pNode,
  216. LPARAM dwParam1,
  217. LPARAM dwParam2
  218. )
  219. {
  220. HRESULT hr = hrOK;
  221. switch (dwParam1)
  222. {
  223. case TFS_MSG_CREATEPROPSHEET:
  224. {
  225. CPropertyPageHolderBase * pPropSheet =
  226. reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
  227. AddPropSheet(pPropSheet);
  228. }
  229. break;
  230. case TFS_MSG_DELETEPROPSHEET:
  231. {
  232. CPropertyPageHolderBase * pPropSheet =
  233. reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
  234. RemovePropSheet(pPropSheet);
  235. }
  236. break;
  237. default:
  238. Panic1("Alert the troops!: invalid arg(%d) to CHandler::UserNotify\n",
  239. dwParam1);
  240. break;
  241. }
  242. return hr;
  243. }
  244. /*!--------------------------------------------------------------------------
  245. CHandler::UserResultNotify
  246. Implememntation of ITFSResultHandler::UserResultNotify
  247. Author: KennT
  248. ---------------------------------------------------------------------------*/
  249. STDMETHODIMP
  250. CHandler::UserResultNotify
  251. (
  252. ITFSNode * pNode,
  253. LONG_PTR dwParam1,
  254. LONG_PTR dwParam2
  255. )
  256. {
  257. HRESULT hr = hrOK;
  258. switch (dwParam1)
  259. {
  260. case TFS_MSG_CREATEPROPSHEET:
  261. {
  262. CPropertyPageHolderBase * pPropSheet =
  263. reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
  264. AddPropSheet(pPropSheet);
  265. }
  266. break;
  267. case TFS_MSG_DELETEPROPSHEET:
  268. {
  269. CPropertyPageHolderBase * pPropSheet =
  270. reinterpret_cast<CPropertyPageHolderBase *>(dwParam2);
  271. RemovePropSheet(pPropSheet);
  272. }
  273. break;
  274. default:
  275. Panic1("Alert the troops!: invalid arg(%d) to CHandler::UserResultNotify\n",
  276. dwParam1);
  277. break;
  278. }
  279. return hr;
  280. }
  281. /*!--------------------------------------------------------------------------
  282. CHandler::DestroyPropSheets
  283. Implememntation of DestroyPropSheets
  284. Author: KennT
  285. ---------------------------------------------------------------------------*/
  286. HRESULT
  287. CHandler::DestroyPropSheets()
  288. {
  289. // Trace1("CHandler destructor - hander has %d prop sheets active\n", m_listPropSheets.GetCount());
  290. while (!m_listPropSheets.IsEmpty())
  291. {
  292. // This handler still has some prop sheets up.
  293. // Destroy them before we go away.
  294. HANDLE hThread;
  295. CPropertyPageHolderBase * pPropSheet;
  296. pPropSheet = m_listPropSheets.RemoveHead();
  297. hThread = pPropSheet->m_hThread;
  298. pPropSheet->ForceDestroy();
  299. DWORD dwReturn = WaitForSingleObject(hThread, 1000);
  300. if (dwReturn == WAIT_OBJECT_0)
  301. {
  302. }
  303. else
  304. if (dwReturn == WAIT_TIMEOUT)
  305. {
  306. }
  307. else
  308. if (dwReturn == WAIT_ABANDONED)
  309. {
  310. }
  311. else
  312. if (dwReturn == WAIT_FAILED)
  313. {
  314. DWORD dwReturn = GetLastError();
  315. }
  316. CloseHandle(hThread);
  317. }
  318. return hrOK;
  319. }
  320. /*!--------------------------------------------------------------------------
  321. CHandler::HasPropSheets
  322. Implememntation of CHandler::HasPropSheets
  323. returns the # of prop sheets this node has open
  324. Author: EricDav
  325. ---------------------------------------------------------------------------*/
  326. int
  327. CHandler::HasPropSheetsOpen()
  328. {
  329. return (int)m_listPropSheets.GetCount();
  330. }
  331. /*!--------------------------------------------------------------------------
  332. CHandler::GetPropSheet
  333. Implememntation of CHandler::GetPropSheet
  334. returns the CPropPageHolderBase of the given index # (zero based)
  335. Author: EricDav
  336. ---------------------------------------------------------------------------*/
  337. HRESULT
  338. CHandler::GetOpenPropSheet
  339. (
  340. int nIndex,
  341. CPropertyPageHolderBase ** ppPropSheet
  342. )
  343. {
  344. HRESULT hr = hrOK;
  345. if (ppPropSheet)
  346. {
  347. POSITION pos = m_listPropSheets.FindIndex(nIndex);
  348. *ppPropSheet = m_listPropSheets.GetAt(pos);
  349. }
  350. return hr;
  351. }
  352. /*!--------------------------------------------------------------------------
  353. CHandler::AddPropSheet
  354. Implememntation of CHandler::AddPropSheet
  355. Author: EricDav
  356. ---------------------------------------------------------------------------*/
  357. HRESULT
  358. CHandler::AddPropSheet
  359. (
  360. CPropertyPageHolderBase * pPropSheet
  361. )
  362. {
  363. HRESULT hr = hrOK;
  364. m_listPropSheets.AddTail(pPropSheet);
  365. // Trace1("CHandler::AddPropSheet - Added page holder %lx\n", pPropSheet);
  366. return hr;
  367. }
  368. /*!--------------------------------------------------------------------------
  369. CHandler::RemovePropSheet
  370. Implememntation of CHandler::RemovePropSheet
  371. Author: EricDav
  372. ---------------------------------------------------------------------------*/
  373. HRESULT
  374. CHandler::RemovePropSheet
  375. (
  376. CPropertyPageHolderBase * pPropSheet
  377. )
  378. {
  379. HRESULT hr = hrOK;
  380. POSITION pos = m_listPropSheets.Find(pPropSheet);
  381. if (pos)
  382. {
  383. m_listPropSheets.RemoveAt(pos);
  384. }
  385. // else
  386. // {
  387. // // prop sheet is not in the list
  388. // Trace0("CHandler::RemovePropSheet - prop page holder not in list!\n");
  389. // Assert(FALSE);
  390. // }
  391. return hr;
  392. }
  393. /*!--------------------------------------------------------------------------
  394. CHandler::OnRefresh
  395. Default implementation for the refresh functionality
  396. Author: EricDav
  397. ---------------------------------------------------------------------------*/
  398. HRESULT
  399. CHandler::OnRefresh
  400. (
  401. ITFSNode * pNode,
  402. LPDATAOBJECT pDataObject,
  403. DWORD dwType,
  404. LPARAM arg,
  405. LPARAM param
  406. )
  407. {
  408. /*
  409. pNode->DeleteAllChildren();
  410. Assert(GetChildCount() == 0);
  411. OnEnumerate(pComponentData, pDataObject, bExtension);
  412. AddCurrentChildrenToUI(pComponentData);
  413. */
  414. return hrOK;
  415. }
  416. /*!--------------------------------------------------------------------------
  417. CHandler::BuildSelectedItemList
  418. Builds a list of selected items in the result pane (can't do
  419. multiple selection in the scope pane).
  420. Author: EricDav
  421. ---------------------------------------------------------------------------*/
  422. HRESULT
  423. CHandler::BuildSelectedItemList
  424. (
  425. ITFSComponent * pComponent,
  426. CTFSNodeList * plistSelectedItems
  427. )
  428. {
  429. RESULTDATAITEM resultDataItem;
  430. HRESULT hr = hrOK;
  431. ZeroMemory(&resultDataItem, sizeof(resultDataItem));
  432. resultDataItem.nState = LVIS_SELECTED;
  433. resultDataItem.nIndex = -1;
  434. CTFSNodeList listSelectedNodes;
  435. SPIResultData spResultData;
  436. CORg ( pComponent->GetResultData(&spResultData) );
  437. //
  438. // Loop through and build a list of all selected items
  439. //
  440. while (TRUE)
  441. {
  442. //
  443. // Gets the Selected items ID
  444. //
  445. resultDataItem.mask = RDI_STATE;
  446. CORg (spResultData->GetNextItem(&resultDataItem));
  447. if (hr == S_FALSE)
  448. break;
  449. //
  450. // Now get the items lparam
  451. //
  452. //resultDataItem.mask = RDI_PARAM;
  453. //CORg (spResultData->GetItem(&resultDataItem));
  454. ITFSNode * pNode;
  455. pNode = reinterpret_cast<ITFSNode *>(resultDataItem.lParam);
  456. Assert(pNode != NULL);
  457. pNode->AddRef();
  458. plistSelectedItems->AddTail(pNode);
  459. }
  460. Error:
  461. return hr;
  462. }
  463. /*!--------------------------------------------------------------------------
  464. CHandler::BuildVirtualSelectedItemList
  465. Builds a list of selected items in the result pane (can't do
  466. multiple selection in the scope pane).
  467. Author: EricDav
  468. ---------------------------------------------------------------------------*/
  469. HRESULT
  470. CHandler::BuildVirtualSelectedItemList
  471. (
  472. ITFSComponent * pComponent,
  473. CVirtualIndexArray * parraySelectedItems
  474. )
  475. {
  476. RESULTDATAITEM resultDataItem;
  477. HRESULT hr = hrOK;
  478. ZeroMemory(&resultDataItem, sizeof(resultDataItem));
  479. resultDataItem.nState = LVIS_SELECTED;
  480. resultDataItem.nIndex = -1;
  481. SPIResultData spResultData;
  482. CORg ( pComponent->GetResultData(&spResultData) );
  483. //
  484. // Loop through and build a list of all selected items
  485. //
  486. while (TRUE)
  487. {
  488. //
  489. // Gets the Selected items ID
  490. //
  491. resultDataItem.mask = RDI_STATE;
  492. CORg (spResultData->GetNextItem(&resultDataItem));
  493. if (hr == S_FALSE)
  494. break;
  495. //
  496. // The index of the selected item is in the resultDataItem struct
  497. //
  498. parraySelectedItems->Add(resultDataItem.nIndex);
  499. }
  500. Error:
  501. return hr;
  502. }
  503. DEBUG_DECLARE_INSTANCE_COUNTER(CMTHandler);
  504. /*---------------------------------------------------------------------------
  505. CMTHandler implementation
  506. ---------------------------------------------------------------------------*/
  507. CMTHandler::CMTHandler(ITFSComponentData *pTFSCompData)
  508. : CHandler(pTFSCompData),
  509. m_cRef(1)
  510. {
  511. DEBUG_INCREMENT_INSTANCE_COUNTER(CMTHandler);
  512. }
  513. CMTHandler::~CMTHandler()
  514. {
  515. DEBUG_DECREMENT_INSTANCE_COUNTER(CMTHandler);
  516. }
  517. IMPLEMENT_ADDREF_RELEASE(CMTHandler)
  518. STDMETHODIMP CMTHandler::QueryInterface(REFIID riid, LPVOID *ppv)
  519. {
  520. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  521. // Is the pointer bad?
  522. if (ppv == NULL)
  523. return E_INVALIDARG;
  524. // Place NULL in *ppv in case of failure
  525. *ppv = NULL;
  526. // This is the non-delegating IUnknown implementation
  527. if (riid == IID_IUnknown)
  528. *ppv = (LPVOID) this;
  529. else if (riid == IID_ITFSResultHandler)
  530. *ppv = (ITFSResultHandler *) this;
  531. else if (riid == IID_ITFSNodeHandler)
  532. *ppv = (ITFSNodeHandler *) this;
  533. else if (riid == IID_ITFSThreadHandler)
  534. *ppv = (ITFSThreadHandler *) this;
  535. // If we're going to return an interface, AddRef it first
  536. if (*ppv)
  537. {
  538. ((LPUNKNOWN) *ppv)->AddRef();
  539. return hrOK;
  540. }
  541. else
  542. return E_NOINTERFACE;
  543. }
  544. /*!--------------------------------------------------------------------------
  545. CMTHandler::DestoryHandler
  546. This gets called when the node for this handler is told to destroy.
  547. Free up anything we may be holding onto here.
  548. Author: EricDav
  549. ---------------------------------------------------------------------------*/
  550. STDMETHODIMP
  551. CMTHandler::DestroyHandler(ITFSNode *pNode)
  552. {
  553. ReleaseThreadHandler();
  554. WaitForThreadToExit();
  555. return hrOK;
  556. }
  557. /*!--------------------------------------------------------------------------
  558. CMTHandler::OnExpand
  559. Default implementation for the refresh functionality
  560. Author: EricDav
  561. ---------------------------------------------------------------------------*/
  562. HRESULT
  563. CMTHandler::OnExpand
  564. (
  565. ITFSNode * pNode,
  566. LPDATAOBJECT pDataObject,
  567. DWORD dwType,
  568. LPARAM arg,
  569. LPARAM param
  570. )
  571. {
  572. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  573. HRESULT hr = hrOK;
  574. SPITFSNode spNode;
  575. SPITFSNodeHandler spHandler;
  576. ITFSQueryObject * pQuery = NULL;
  577. if (m_bExpanded)
  578. {
  579. return hr;
  580. }
  581. Lock();
  582. OnChangeState(pNode);
  583. pQuery = OnCreateQuery(pNode);
  584. Assert(pQuery);
  585. // notify the UI to change icon, if needed
  586. //Verify(SUCCEEDED(pComponentData->ChangeNode(this, SCOPE_PANE_CHANGE_ITEM_ICON)));
  587. Verify(StartBackgroundThread(pNode, m_spTFSCompData->GetHiddenWnd(), pQuery));
  588. pQuery->Release();
  589. m_bExpanded = TRUE;
  590. return hrOK;
  591. }
  592. /*!--------------------------------------------------------------------------
  593. CMTHandler::OnRefresh
  594. Default implementation for the refresh functionality
  595. Author: EricDav
  596. ---------------------------------------------------------------------------*/
  597. HRESULT
  598. CMTHandler::OnRefresh
  599. (
  600. ITFSNode * pNode,
  601. LPDATAOBJECT pDataObject,
  602. DWORD dwType,
  603. LPARAM arg,
  604. LPARAM param
  605. )
  606. {
  607. HRESULT hr = hrOK;
  608. if (m_bExpanded == FALSE)
  609. {
  610. // we cannot refresh/add items to a node that hasn't been expanded yet.
  611. return hr;
  612. }
  613. BOOL bLocked = IsLocked();
  614. if (bLocked)
  615. {
  616. // cannot do refresh on locked node, the UI should prevent this
  617. return hr;
  618. }
  619. pNode->DeleteAllChildren(TRUE);
  620. int nVisible, nTotal;
  621. pNode->GetChildCount(&nVisible, &nTotal);
  622. Assert(nVisible == 0);
  623. Assert(nTotal == 0);
  624. m_bExpanded = FALSE;
  625. OnExpand(pNode, pDataObject, dwType, arg, param); // will spawn a thread to do enumeration
  626. return hr;
  627. }
  628. /*!--------------------------------------------------------------------------
  629. CMTHandler::OnNotifyError
  630. Implementation of ThreadHandler::OnNotifyError
  631. Author: KennT
  632. ---------------------------------------------------------------------------*/
  633. HRESULT
  634. CMTHandler::OnNotifyError
  635. (
  636. LPARAM lParam
  637. )
  638. {
  639. HRESULT hr = hrOK;
  640. COM_PROTECT_TRY
  641. {
  642. OnError((DWORD) lParam);
  643. }
  644. COM_PROTECT_CATCH
  645. return hrOK;
  646. }
  647. /*!--------------------------------------------------------------------------
  648. CMTHandler::OnNotifyHaveData
  649. -
  650. Author: KennT
  651. ---------------------------------------------------------------------------*/
  652. HRESULT
  653. CMTHandler::OnNotifyHaveData
  654. (
  655. LPARAM lParam
  656. )
  657. {
  658. // For these nodes, assume that the lParam is a CNodeQueryObject *
  659. CNodeQueryObject * pQuery;
  660. LPQUEUEDATA pQD;
  661. ITFSNode * p;
  662. HRESULT hr = hrOK;
  663. COM_PROTECT_TRY
  664. {
  665. pQuery = (CNodeQueryObject *) lParam;
  666. Assert(pQuery);
  667. if (pQuery)
  668. pQuery->AddRef();
  669. while (pQD = pQuery->RemoveFromQueue())
  670. {
  671. if (pQD->Type == QDATA_PNODE)
  672. {
  673. // this is the normal case. The handler just expects nodes
  674. // to be handed back from the background thread
  675. p = reinterpret_cast<ITFSNode *>(pQD->Data);
  676. OnHaveData(m_spNode, p);
  677. p->Release();
  678. }
  679. else
  680. {
  681. // custom case here. The user provided their own data
  682. // type. Call the appropriate hander for this.
  683. OnHaveData(m_spNode, pQD->Data, pQD->Type);
  684. }
  685. delete pQD;
  686. }
  687. if (pQuery)
  688. pQuery->Release();
  689. }
  690. COM_PROTECT_CATCH
  691. return hrOK;
  692. }
  693. /*!--------------------------------------------------------------------------
  694. CMTHandler::OnNotifyExiting
  695. Implementation of ThreadHandler::OnNotifyExiting
  696. Author: KennT
  697. ---------------------------------------------------------------------------*/
  698. HRESULT
  699. CMTHandler::OnNotifyExiting
  700. (
  701. LPARAM lParam
  702. )
  703. {
  704. CNodeQueryObject * pQuery;
  705. HRESULT hr = hrOK;
  706. COM_PROTECT_TRY
  707. {
  708. pQuery = (CNodeQueryObject *) lParam;
  709. Assert(pQuery);
  710. if (pQuery)
  711. pQuery->AddRef();
  712. OnChangeState(m_spNode);
  713. ReleaseThreadHandler();
  714. Unlock();
  715. if (pQuery)
  716. pQuery->Release();
  717. }
  718. COM_PROTECT_CATCH
  719. return hrOK;
  720. }