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.

717 lines
22 KiB

  1. // This is a part of the Microsoft Management Console.
  2. // Copyright (C) Microsoft Corporation, 1995 - 1999
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Management Console and related
  7. // electronic documentation provided with the interfaces.
  8. #ifndef _TREEDATA_H
  9. #define _TREEDATA_H
  10. /////////////////////////////////////////////////////////////////////////////
  11. // Miscellanea
  12. extern LPCWSTR g_lpszNullString;
  13. /////////////////////////////////////////////////////////////////////////////
  14. // Generic Helper functions
  15. template<class TYPE>
  16. inline void SAFE_RELEASE(TYPE*& pObj)
  17. {
  18. if (pObj != NULL)
  19. {
  20. pObj->Release();
  21. pObj = NULL;
  22. }
  23. else
  24. {
  25. TRACE(_T("Release called on NULL interface ptr"));
  26. }
  27. }
  28. ///////////////////////////////////////////////////////////////////
  29. // Context Menu data structures and macros
  30. #define MAX_CONTEXT_MENU_STRLEN 128
  31. struct MENUDATARES
  32. {
  33. WCHAR szBuffer[MAX_CONTEXT_MENU_STRLEN*2];
  34. UINT uResID;
  35. };
  36. struct MENUMAP
  37. {
  38. MENUDATARES* dataRes;
  39. CONTEXTMENUITEM2* ctxMenu;
  40. };
  41. #define DECLARE_MENU(theClass) \
  42. class theClass \
  43. { \
  44. public: \
  45. static LPCONTEXTMENUITEM2 GetContextMenuItem() { return GetMenuMap()->ctxMenu; }; \
  46. static MENUMAP* GetMenuMap(); \
  47. };
  48. #define BEGIN_MENU(theClass) \
  49. MENUMAP* theClass::GetMenuMap() {
  50. #define BEGIN_CTX static CONTEXTMENUITEM2 ctx[] = {
  51. #define CTX_ENTRY_TOP(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0, languageIndependantStringID},
  52. #define CTX_ENTRY_NEW(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, 0, languageIndependantStringID},
  53. #define CTX_ENTRY_TASK(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, 0, languageIndependantStringID},
  54. #define CTX_ENTRY_VIEW(cmdID, languageIndependantStringID) { L"",L"", cmdID, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0, languageIndependantStringID},
  55. #define END_CTX { NULL, NULL, 0, 0, 0, 0} };
  56. #define BEGIN_RES static MENUDATARES dataRes[] = {
  57. #define RES_ENTRY(resID) {L"", resID },
  58. #define END_RES { NULL, 0 } };
  59. #define END_MENU \
  60. static MENUMAP menuMap = { dataRes, ctx }; \
  61. return &menuMap; }
  62. BOOL LoadContextMenuResources(MENUMAP* pMenuMap);
  63. //
  64. // Toolbar macros
  65. //
  66. #define DECLARE_TOOLBAR_MAP() \
  67. public: \
  68. virtual HRESULT ToolbarNotify(int event, \
  69. CComponentDataObject* pComponentData, \
  70. CNodeList* pNodeList);
  71. #define BEGIN_TOOLBAR_MAP(theClass) \
  72. HRESULT theClass::ToolbarNotify(int event, \
  73. CComponentDataObject* pComponentData, \
  74. CNodeList* pNodeList) \
  75. { \
  76. HRESULT hr = S_OK; \
  77. event; \
  78. pComponentData; \
  79. pNodeList;
  80. #define TOOLBAR_EVENT(toolbar_event, function) \
  81. if (event == toolbar_event) \
  82. { \
  83. hr = function(pComponentData, pNodeList); \
  84. }
  85. #define END_TOOLBAR_MAP() \
  86. return hr; \
  87. }
  88. #define DECLARE_TOOLBAR_EVENT(toolbar_event, value) \
  89. static const int toolbar_event = value;
  90. ////////////////////////////////////////////////////////////
  91. // header control resources data structures
  92. #define MAX_RESULT_HEADER_STRLEN 128
  93. struct RESULT_HEADERMAP
  94. {
  95. WCHAR szBuffer[MAX_RESULT_HEADER_STRLEN];
  96. UINT uResID;
  97. int nFormat;
  98. int nWidth;
  99. };
  100. BOOL LoadResultHeaderResources(RESULT_HEADERMAP* pHeaderMap, int nCols);
  101. ////////////////////////////////////////////////////////////
  102. // bitmap strips resources data structures
  103. template <UINT nResID> class CBitmapHolder : public CBitmap
  104. {
  105. public:
  106. BOOL LoadBitmap() { return CBitmap::LoadBitmap(nResID);}
  107. };
  108. ///////////////////////////////////////////////////////////////////////////////
  109. // FORWARD DECLARATIONS
  110. class CComponentDataObject;
  111. class CContainerNode;
  112. class CMTContainerNode;
  113. class CLeafNode;
  114. class CPropertyPageHolderBase;
  115. class CBackgroundThread;
  116. class CQueryObj;
  117. /////////////////////////////////////////////////////////////////////
  118. // CObjBase
  119. // base class for all objects relying on RTTI and class type info
  120. class CObjBase
  121. {
  122. public:
  123. CObjBase() {}
  124. virtual ~CObjBase() {}
  125. };
  126. /////////////////////////////////////////////////////////////////////
  127. // CTreeNode
  128. // cannot construct objects of this class, have to derive from it
  129. #define DECLARE_NODE_GUID() \
  130. static const GUID NodeTypeGUID; \
  131. virtual const GUID* GetNodeType() { return &NodeTypeGUID;}
  132. // use the HIWORD for generic flags and leave the LOWORD for application specific data
  133. #define TN_FLAG_HIDDEN (0x00010000) // does not appear in the UI
  134. #define TN_FLAG_NO_WRITE (0x00020000) // cannot edit or create
  135. #define TN_FLAG_NO_DELETE (0x00040000) // cannot delete
  136. #define TN_FLAG_HAS_SHEET (0x00080000) // this node or a child has a property sheet up
  137. #define TN_FLAG_CONTAINER (0x00100000) // container (i.e. not leaf)
  138. #define TN_FLAG_CONTAINER_ENUM (0x00200000) // container node has been enumerated (back end)
  139. #define TN_FLAG_CONTAINER_EXP (0x00400000) // container node has been expanded (UI node)
  140. class CTreeNode : public CObjBase
  141. {
  142. public:
  143. virtual ~CTreeNode() {}
  144. CContainerNode* GetContainer() { return m_pContainer; }
  145. void SetContainer(CContainerNode* pContainer) { m_pContainer = pContainer; }
  146. BOOL HasContainer(CContainerNode* pContainerNode);
  147. virtual LPCWSTR GetDisplayName() { return m_szDisplayName; }
  148. virtual void SetDisplayName(LPCWSTR lpszDisplayName) { m_szDisplayName = lpszDisplayName;}
  149. //
  150. // Data Object related data
  151. //
  152. virtual const GUID* GetNodeType() { return NULL;}
  153. virtual HRESULT GetDataHere(CLIPFORMAT,
  154. LPSTGMEDIUM,
  155. CDataObject*) { return DV_E_CLIPFORMAT;}
  156. virtual HRESULT GetData(CLIPFORMAT,
  157. LPSTGMEDIUM,
  158. CDataObject*) { return DV_E_CLIPFORMAT;}
  159. virtual HRESULT GetResultViewType(CComponentDataObject* pComponentData,
  160. LPOLESTR* ppViewType,
  161. long* pViewOptions);
  162. virtual HRESULT OnShow(LPCONSOLE) { return S_OK; }
  163. //
  164. // flag manipulation API's
  165. //
  166. BOOL IsContainer() { return (m_dwNodeFlags & TN_FLAG_CONTAINER) ? TRUE : FALSE;}
  167. BOOL IsVisible() { return (m_dwNodeFlags & TN_FLAG_HIDDEN) ? FALSE : TRUE;}
  168. BOOL CanDelete() { return (m_dwNodeFlags & TN_FLAG_NO_DELETE) ? FALSE : TRUE;}
  169. virtual void SetFlagsDown(DWORD dwNodeFlags, BOOL bSet);
  170. void SetFlagsUp(DWORD dwNodeFlags, BOOL bSet);
  171. DWORD GetFlags() { return m_dwNodeFlags;}
  172. virtual BOOL CanExpandSync() { return FALSE; }
  173. virtual void Show(BOOL bShow, CComponentDataObject* pComponentData);
  174. //
  175. // Verb handlers
  176. //
  177. virtual HRESULT OnRename(CComponentDataObject*,
  178. LPWSTR) { return S_FALSE; }
  179. virtual void OnDelete(CComponentDataObject* pComponentData,
  180. CNodeList* pNodeList) = 0;
  181. virtual BOOL OnRefresh(CComponentDataObject*,
  182. CNodeList*) { return FALSE; }
  183. virtual HRESULT OnCommand(long,
  184. DATA_OBJECT_TYPES,
  185. CComponentDataObject*,
  186. CNodeList*) { return S_OK; };
  187. virtual HRESULT OnAddMenuItems(IContextMenuCallback2* pContextMenuCallback2,
  188. DATA_OBJECT_TYPES type,
  189. long *pInsertionAllowed,
  190. CNodeList* pNodeList);
  191. virtual HRESULT OnAddMenuItemsMultipleSelect(IContextMenuCallback2*,
  192. DATA_OBJECT_TYPES,
  193. long*,
  194. CNodeList*) { return S_OK; }
  195. virtual MMC_CONSOLE_VERB GetDefaultVerb(DATA_OBJECT_TYPES type,
  196. CNodeList* pNodeList);
  197. virtual void OnSetVerbState(LPCONSOLEVERB pConsoleVerb,
  198. DATA_OBJECT_TYPES type,
  199. CNodeList* pNodeList);
  200. virtual HRESULT OnSetToolbarVerbState(IToolbar* pToolbar,
  201. CNodeList* pNodeList);
  202. virtual BOOL OnSetRenameVerbState(DATA_OBJECT_TYPES type,
  203. BOOL* pbHide,
  204. CNodeList* pNodeList);
  205. virtual BOOL OnSetDeleteVerbState(DATA_OBJECT_TYPES type,
  206. BOOL* pbHide,
  207. CNodeList* pNodeList);
  208. virtual BOOL OnSetRefreshVerbState(DATA_OBJECT_TYPES type,
  209. BOOL* pbHide,
  210. CNodeList* pNodeList);
  211. virtual BOOL OnSetCutVerbState(DATA_OBJECT_TYPES type,
  212. BOOL* pbHide,
  213. CNodeList* pNodeList);
  214. virtual BOOL OnSetCopyVerbState(DATA_OBJECT_TYPES type,
  215. BOOL* pbHide,
  216. CNodeList* pNodeList);
  217. virtual BOOL OnSetPasteVerbState(DATA_OBJECT_TYPES type,
  218. BOOL* pbHide,
  219. CNodeList* pNodeList);
  220. virtual BOOL OnSetPrintVerbState(DATA_OBJECT_TYPES type,
  221. BOOL* pbHide,
  222. CNodeList* pNodeList);
  223. //
  224. // Property Page methods
  225. //
  226. virtual BOOL DelegatesPPToContainer() { return FALSE; }
  227. virtual void ShowPageForNode(CComponentDataObject* pComponentDataObject);
  228. virtual BOOL HasPropertyPages(DATA_OBJECT_TYPES type,
  229. BOOL* pbHideVerb,
  230. CNodeList* pNodeList);
  231. virtual HRESULT CreatePropertyPages(LPPROPERTYSHEETCALLBACK,
  232. LONG_PTR,
  233. CNodeList*) { return E_FAIL; }
  234. virtual void OnPropertyChange(CComponentDataObject* pComponentData,
  235. BOOL bScopePane,long changeMask);
  236. virtual BOOL CanCloseSheets() { return TRUE;}
  237. void OnCreateSheet();
  238. void OnDeleteSheet();
  239. BOOL HasSheet() { return (m_dwNodeFlags & TN_FLAG_HAS_SHEET) ? TRUE : FALSE;}
  240. BOOL GetSheetCount() { return m_nSheetCount;}
  241. virtual void IncrementSheetLockCount();
  242. virtual void DecrementSheetLockCount();
  243. BOOL IsSheetLocked() { return m_nSheetLockCount > 0;}
  244. //
  245. // Misc.
  246. //
  247. virtual LPWSTR GetDescriptionBarText() { return L""; }
  248. virtual LPCWSTR GetString(int nCol) = 0;
  249. virtual int GetImageIndex(BOOL bOpenImage) = 0;
  250. virtual void Trace() { TRACE(_T("Name %s "), (LPCTSTR)m_szDisplayName);}
  251. void DeleteHelper(CComponentDataObject* pComponentData);
  252. protected:
  253. CString m_szDisplayName; // name of the item
  254. CContainerNode* m_pContainer; // back pointer to the container the node is in
  255. DWORD m_dwNodeFlags;
  256. LONG m_nSheetLockCount; // keeps track if a node has been locked by a property sheet
  257. LONG m_nSheetCount; // keeps track of the # of sheets the node has up
  258. CTreeNode()
  259. {
  260. m_pContainer = NULL;
  261. m_nSheetLockCount = 0;
  262. m_dwNodeFlags = 0x0; //m_dwNodeFlags |= TN_FLAG_HIDDEN;
  263. m_nSheetCount = 0;
  264. }
  265. virtual LPCONTEXTMENUITEM2 OnGetContextMenuItemTable() { return NULL;}
  266. virtual BOOL OnAddMenuItem(LPCONTEXTMENUITEM2,
  267. long*) { return TRUE;}
  268. friend class CContainerNode; // to get access to the m_pContainer member
  269. //
  270. // Provides a default implementation for toolbar support
  271. //
  272. DECLARE_TOOLBAR_MAP()
  273. };
  274. ///////////////////////////////////////////////////////////////////////
  275. // CNodeList
  276. // collection of nodes
  277. typedef CList<CTreeNode*,CTreeNode*> CNodeListBase;
  278. class CNodeList : public CNodeListBase
  279. {
  280. public:
  281. BOOL RemoveNode(CTreeNode* p)
  282. {
  283. POSITION pos = Find(p);
  284. if (pos == NULL)
  285. return FALSE;
  286. RemoveAt(pos);
  287. return TRUE;
  288. }
  289. void RemoveAllNodes()
  290. {
  291. while (!IsEmpty())
  292. delete RemoveTail();
  293. }
  294. BOOL HasNode(CTreeNode* p)
  295. {
  296. return NULL != Find(p);
  297. }
  298. };
  299. ////////////////////////////////////////////////////////////////////////
  300. // CContainerNode
  301. // node that can be a container of other nodes
  302. class CContainerNode : public CTreeNode
  303. {
  304. public:
  305. CContainerNode()
  306. {
  307. m_ID = 0;
  308. m_dwNodeFlags |= TN_FLAG_CONTAINER;
  309. m_nState = -1;
  310. m_dwErr = 0x0;
  311. m_nThreadLockCount = 0;
  312. }
  313. virtual ~CContainerNode() { ASSERT(m_nSheetLockCount == 0); RemoveAllChildrenFromList(); }
  314. CContainerNode* GetRootContainer()
  315. { return (m_pContainer != NULL) ? m_pContainer->GetRootContainer() : this; }
  316. //
  317. // Thread Helpers
  318. //
  319. void IncrementThreadLockCount();
  320. void DecrementThreadLockCount();
  321. BOOL IsThreadLocked() { return m_nThreadLockCount > 0;}
  322. virtual BOOL OnEnumerate(CComponentDataObject*, BOOL bAsync = TRUE)
  323. { bAsync; return TRUE;} // TRUE = add children in the list to UI
  324. //
  325. // Node state helpers
  326. //
  327. BOOL HasChildren() { return !m_containerChildList.IsEmpty() || !m_leafChildList.IsEmpty(); }
  328. void ForceEnumeration(CComponentDataObject* pComponentData);
  329. void MarkEnumerated(BOOL bEnum = TRUE);
  330. BOOL IsEnumerated() { ASSERT(IsContainer()); return (m_dwNodeFlags & TN_FLAG_CONTAINER_ENUM) ? TRUE : FALSE;}
  331. void MarkExpanded() { ASSERT(IsContainer()); m_dwNodeFlags |= TN_FLAG_CONTAINER_EXP; }
  332. BOOL IsExpanded() { ASSERT(IsContainer()); return (m_dwNodeFlags & TN_FLAG_CONTAINER_EXP) ? TRUE : FALSE;}
  333. void MarkEnumeratedAndLoaded(CComponentDataObject* pComponentData);
  334. void SetScopeID(HSCOPEITEM ID) { m_ID = ID;}
  335. HSCOPEITEM GetScopeID() { return m_ID;}
  336. BOOL AddedToScopePane() { return GetScopeID() != 0;}
  337. virtual CColumnSet* GetColumnSet() = 0;
  338. virtual LPCWSTR GetColumnID() = 0;
  339. virtual void SetFlagsDown(DWORD dwNodeFlags, BOOL bSet);
  340. void SetFlagsOnNonContainers(DWORD dwNodeFlags,BOOL bSet);
  341. //
  342. // child list mainpulation API's
  343. //
  344. CNodeList* GetContainerChildList() { return &m_containerChildList; }
  345. CNodeList* GetLeafChildList() { return &m_leafChildList; }
  346. BOOL AddChildToList(CTreeNode* p);
  347. BOOL AddChildToListSorted(CTreeNode* p, CComponentDataObject* pComponentData);
  348. BOOL RemoveChildFromList(CTreeNode* p);
  349. void RemoveAllChildrenFromList();
  350. void RemoveAllContainersFromList() { m_containerChildList.RemoveAllNodes(); }
  351. void RemoveAllLeavesFromList() { m_leafChildList.RemoveAllNodes(); }
  352. //
  353. // given a node, it searches for it recursively and if successful it returns the
  354. // container the node is in
  355. //
  356. BOOL FindChild(CTreeNode* pNode, CTreeNode** ppContainer);
  357. BOOL AddChildToListAndUI(CTreeNode* pChildToAdd, CComponentDataObject* pComponentData);
  358. BOOL AddChildToListAndUISorted(CTreeNode* pChildToAdd, CComponentDataObject* pComponentData);
  359. virtual int Compare(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol, LPARAM lUserParam);
  360. virtual HRESULT CreatePropertyPagesHelper(LPPROPERTYSHEETCALLBACK,
  361. LONG_PTR,
  362. long) { return E_FAIL;}
  363. virtual BOOL OnRefresh(CComponentDataObject* pComponentData,
  364. CNodeList* pNodeList);
  365. virtual void OnColumnsChanged(int*, int) {}
  366. void RemoveAllChildrenHelper(CComponentDataObject* pComponentData);
  367. protected:
  368. virtual void OnChangeState(CComponentDataObject*) {}
  369. void AddCurrentChildrenToUI(CComponentDataObject* pComponentData);
  370. LONG m_nThreadLockCount;
  371. CNodeList m_leafChildList; // leaf contents of the node
  372. CNodeList m_containerChildList; // container contents of the node
  373. HSCOPEITEM m_ID; // ID when the item is inserted in the master tree
  374. int m_nState; // for general purpose finite state machine implementation
  375. DWORD m_dwErr; // for general purpose error handling
  376. };
  377. ////////////////////////////////////////////////////////////////////////
  378. // CLeafNode
  379. // node that is not a container of other nodes
  380. class CLeafNode : public CTreeNode
  381. {
  382. public:
  383. };
  384. ///////////////////////////////////////////////////////////////////
  385. // data nodes
  386. // the root, with folders in it
  387. class CRootData : public CContainerNode
  388. {
  389. public:
  390. CRootData(CComponentDataObject* pComponentData)
  391. {
  392. ASSERT(pComponentData != NULL);
  393. m_pComponentData = pComponentData;
  394. m_bDirty = FALSE;
  395. }
  396. virtual LPCWSTR GetString(int nCol)
  397. {
  398. if (nCol == 0)
  399. return GetDisplayName();
  400. return g_lpszNullString;
  401. }
  402. CComponentDataObject* GetComponentDataObject(){ return m_pComponentData;}
  403. CTreeNode* GetNodeFromCookie(MMC_COOKIE cookie)
  404. {
  405. // cookie == 0 means root to enumerate
  406. if (cookie == NULL)
  407. {
  408. return (CTreeNode*)this;
  409. }
  410. else
  411. {
  412. CTreeNode* pNode = (CTreeNode*)cookie;
  413. CTreeNode* pContainer;
  414. if (FindChild(pNode,&pContainer))
  415. {
  416. return pNode;
  417. }
  418. }
  419. return NULL;
  420. }
  421. // IStream manipulation helpers
  422. virtual HRESULT IsDirty() { return m_bDirty ? S_OK : S_FALSE; }
  423. virtual HRESULT Load(IStream*) { return S_OK; }
  424. virtual HRESULT Save(IStream*, BOOL) { return S_OK; }
  425. void SetDirtyFlag(BOOL bDirty) { m_bDirty = bDirty ;}
  426. private:
  427. CComponentDataObject* m_pComponentData;
  428. BOOL m_bDirty;
  429. CString m_szSnapinType; // constant part of the name loaded from resources
  430. };
  431. //////////////////////////////////////////////////////////////////////
  432. // CBackgroundThread
  433. class CBackgroundThread : public CWinThread
  434. {
  435. public:
  436. CBackgroundThread();
  437. virtual ~CBackgroundThread();
  438. void SetQueryObj(CQueryObj* pQueryObj);
  439. BOOL Start(CMTContainerNode* pNode, CComponentDataObject* pComponentData);
  440. virtual BOOL InitInstance() { return TRUE; } // MFC override
  441. virtual int Run(); // MFC override
  442. void Lock() { ::EnterCriticalSection(&m_cs); }
  443. void Unlock() { ::LeaveCriticalSection(&m_cs); }
  444. void Abandon();
  445. BOOL IsAbandoned();
  446. BOOL OnAddToQueue(INT_PTR nCount);
  447. CObjBase* RemoveFromQueue();
  448. BOOL IsQueueEmpty();
  449. BOOL PostHaveData();
  450. BOOL PostError(DWORD dwErr);
  451. BOOL PostExiting();
  452. void AcknowledgeExiting() { VERIFY(0 != ::SetEvent(m_hEventHandle));}
  453. private:
  454. // communication with ComponentData object
  455. BOOL PostMessageToComponentDataRaw(UINT Msg, WPARAM wParam, LPARAM lParam);
  456. void WaitForExitAcknowledge();
  457. CRITICAL_SECTION m_cs; // critical section to sync access to data
  458. HANDLE m_hEventHandle; // syncronization handle for shutdown notification
  459. CMTContainerNode* m_pContNode; // back pointer to node the thread is executing for
  460. CQueryObj* m_pQueryObj; // query object the thread is executing
  461. INT_PTR m_nQueueCountMax; // max size of the queue
  462. HWND m_hHiddenWnd; // handle to window to post messages
  463. BOOL m_bAbandoned;
  464. };
  465. //////////////////////////////////////////////////////////////////////
  466. // CQueryObj
  467. typedef CList<CObjBase*,CObjBase*> CObjBaseList;
  468. class CQueryObj
  469. {
  470. public:
  471. CQueryObj() { m_dwErr = 0; m_pThread = NULL;}
  472. virtual ~CQueryObj()
  473. {
  474. while (!m_objQueue.IsEmpty())
  475. delete m_objQueue.RemoveTail();
  476. };
  477. void SetThread(CBackgroundThread* pThread)
  478. {
  479. ASSERT(pThread != NULL);
  480. m_pThread = pThread;
  481. }
  482. CBackgroundThread* GetThread() {return m_pThread;}
  483. virtual BOOL Enumerate() { return FALSE;}
  484. virtual BOOL AddQueryResult(CObjBase* pObj)
  485. {
  486. BOOL bRes = FALSE;
  487. if (m_pThread != NULL)
  488. {
  489. BOOL bPostedHaveDataMessage = FALSE;
  490. m_pThread->Lock();
  491. bRes = NULL != m_objQueue.AddTail(pObj);
  492. bPostedHaveDataMessage = m_pThread->OnAddToQueue(m_objQueue.GetCount());
  493. m_pThread->Unlock();
  494. // wait for the queue length to go down to zero
  495. if (bPostedHaveDataMessage)
  496. {
  497. INT_PTR nQueueCount = 0;
  498. do
  499. {
  500. m_pThread->Lock();
  501. nQueueCount = m_objQueue.GetCount();
  502. m_pThread->Unlock();
  503. if (m_pThread->IsAbandoned())
  504. {
  505. break;
  506. }
  507. if (nQueueCount > 0)
  508. {
  509. ::Sleep(100);
  510. }
  511. }
  512. while (nQueueCount > 0);
  513. } // if
  514. }
  515. else
  516. {
  517. bRes = NULL != m_objQueue.AddTail(pObj);
  518. }
  519. ASSERT(bRes);
  520. return bRes;
  521. }
  522. virtual void OnError(DWORD dwErr)
  523. {
  524. if (m_pThread != NULL)
  525. {
  526. m_pThread->Lock();
  527. m_dwErr = dwErr;
  528. m_pThread->Unlock();
  529. m_pThread->PostError(dwErr);
  530. }
  531. else
  532. {
  533. m_dwErr = dwErr;
  534. }
  535. }
  536. CObjBaseList* GetQueue() { return &m_objQueue;}
  537. DWORD GetError()
  538. {
  539. if (m_pThread != NULL)
  540. {
  541. m_pThread->Lock();
  542. DWORD dwErr = m_dwErr;
  543. m_pThread->Unlock();
  544. return dwErr;
  545. }
  546. else
  547. {
  548. return m_dwErr;
  549. }
  550. }
  551. private:
  552. CBackgroundThread* m_pThread; // back pointer, if in the context of a thread
  553. CObjBaseList m_objQueue; // queue for results
  554. DWORD m_dwErr; // error code, if any
  555. };
  556. ////////////////////////////////////////////////////////////////////////
  557. // CMTContainerNode
  558. // container that can do operations from a secondary thread
  559. class CMTContainerNode : public CContainerNode
  560. {
  561. public:
  562. CMTContainerNode()
  563. {
  564. m_pThread = NULL;
  565. }
  566. virtual ~CMTContainerNode();
  567. virtual BOOL OnEnumerate(CComponentDataObject* pComponentData, BOOL bAsync = TRUE);
  568. virtual BOOL OnRefresh(CComponentDataObject* pComponentData,
  569. CNodeList* pNodeList);
  570. protected:
  571. // thread creation
  572. virtual CBackgroundThread* CreateThreadObject()
  573. {
  574. return new CBackgroundThread; // override if need derived tipe of object
  575. }
  576. // query creation
  577. virtual CQueryObj* OnCreateQuery() // override to create a user defined query object
  578. {
  579. return new CQueryObj(); // return a do-nothing query
  580. }
  581. // main message handler for thread messages
  582. virtual void OnThreadHaveDataNotification(CComponentDataObject* pComponentDataObject);
  583. virtual void OnThreadErrorNotification(DWORD dwErr, CComponentDataObject* pComponentDataObject);
  584. virtual void OnThreadExitingNotification(CComponentDataObject* pComponentDataObject);
  585. virtual void OnHaveData(CObjBase*, CComponentDataObject*) {}
  586. virtual void OnError(DWORD dwErr) { m_dwErr = dwErr; }
  587. BOOL StartBackgroundThread(CComponentDataObject* pComponentData, BOOL bAsync = TRUE);
  588. CBackgroundThread* GetThread() { ASSERT(m_pThread != NULL); return m_pThread;}
  589. void AbandonThread(CComponentDataObject* pComponentData);
  590. private:
  591. CBackgroundThread* m_pThread; // pointer to thread object executing the code
  592. friend class CHiddenWnd; // to get OnThreadNotification()
  593. friend class CRunningThreadTable; // to get AbandonThread()
  594. };
  595. #endif // _TREEDATA_H