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.

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