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.

626 lines
21 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. /*++
  3. Copyright (C) Microsoft Corporation
  4. Module Name:
  5. NodeWithResultChildrenList.cpp
  6. Abstract:
  7. Implementation file for the CNodeWithResultChildrenList subnode.
  8. This is the implementation portion of an inline template class.
  9. Include it in the .cpp file of the class in which you want to
  10. use the template.
  11. Author:
  12. Michael A. Maguire 01/19/98
  13. Revision History:
  14. mmaguire 01/19/98 - created based on old ClientsNode.h
  15. --*/
  16. //////////////////////////////////////////////////////////////////////////////
  17. //////////////////////////////////////////////////////////////////////////////
  18. // BEGIN INCLUDES
  19. //
  20. // standard includes:
  21. //
  22. //
  23. // where we can find declaration for main class in this file:
  24. //
  25. #include "NodeWithResultChildrenList.h"
  26. //
  27. //
  28. // where we can find declarations needed in this file:
  29. //
  30. #include "SnapinNode.cpp" // Template class implementation
  31. #include "ChangeNotification.h"
  32. //
  33. // END INCLUDES
  34. //////////////////////////////////////////////////////////////////////////////
  35. //////////////////////////////////////////////////////////////////////////////
  36. /*++
  37. CNodeWithResultChildrenList::AddSingleChildToListAndCauseViewUpdate
  38. Adds a child to the list of children and calls UpdateAllViews
  39. Use this when the user wants to add a new child node to the list and you
  40. need to add that node to the list and cause a view update to be done across
  41. all views.
  42. This has to be public so that it can be accessed from the Add Client dialog.
  43. Note: In any Add Client method which uses this method, make sure that you
  44. have initially called your PopulateResultChildrenList method before you call this method.
  45. Otherwise, when EnumerateResultChildrenList gets called, it will check the
  46. m_bResultChildrenListPopulated variable, find that it's false, and think that
  47. no items have yet been added to the list. So it will call your PopulateResultChildrenList
  48. method to populate the list from your underlying data source, potentially causing
  49. the newly added item to show up in the list twice.
  50. --*/
  51. //////////////////////////////////////////////////////////////////////////////
  52. template <class T, class CChildNode, class TArray, class TComponentData, class TComponent>
  53. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::AddSingleChildToListAndCauseViewUpdate( CChildNode * pChildNode )
  54. {
  55. ATLTRACE(_T("# CNodeWithResultChildrenList::AddSingleChildToListAndCauseViewUpdate\n"));
  56. // Check for preconditions:
  57. // None.
  58. HRESULT hr = S_OK;
  59. if( m_ResultChildrenList.Add( pChildNode ) )
  60. {
  61. // We don't add the item directly into the result pane now
  62. // using IResultData->InsertItem, as we have no way of
  63. // adding it into all the possible views.
  64. // Instead, we call IConsole->UpdateAllViews which will
  65. // cause MMC to call Notify on each of our IComponent objects
  66. // with the MMCN_VIEW_CHANGE notification, and we will
  67. // repopulate the result view when we handle that notification.
  68. // We weren't passed an IConsole pointer here, so
  69. // we use the one we saved in out CComponentData object.
  70. TComponentData * pComponentData = GetComponentData();
  71. _ASSERTE( pComponentData != NULL );
  72. _ASSERTE( pComponentData->m_spConsole != NULL );
  73. // We pass in a pointer to 'this' because we want each
  74. // of our CComponent objects to update its result pane
  75. // view if 'this' node is the same as the saved currently
  76. // selected node.
  77. // We want to make sure all views get updated.
  78. CChangeNotification *pChangeNotification = new CChangeNotification();
  79. pChangeNotification->m_dwFlags = CHANGE_UPDATE_CHILDREN_OF_THIS_NODE;
  80. pChangeNotification->m_pNode = this;
  81. hr = pComponentData->m_spConsole->UpdateAllViews( NULL, (LPARAM) pChangeNotification, 0);
  82. pChangeNotification->Release();
  83. }
  84. else
  85. {
  86. // Failed to add => out of memory
  87. hr = E_OUTOFMEMORY;
  88. }
  89. return hr;
  90. }
  91. //////////////////////////////////////////////////////////////////////////////
  92. /*++
  93. CNodeWithResultChildrenList::RemoveChild
  94. Removes a child from the list of children.
  95. This is declared public because it must be accessed from a child node when that
  96. node receives the MMCN_DELETE message and tries to delete itself.
  97. --*/
  98. //////////////////////////////////////////////////////////////////////////////
  99. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent>
  100. HRESULT CNodeWithResultChildrenList<T,CChildNode, TArray, TComponentData, TComponent>::RemoveChild( CChildNode * pChildNode )
  101. {
  102. ATLTRACE(_T("# CNodeWithResultChildrenList::RemoveChild\n"));
  103. // Check for preconditions:
  104. // None.
  105. HRESULT hr = S_OK;
  106. if( m_ResultChildrenList.Remove( pChildNode ) )
  107. {
  108. // We don't remove the item directly from the result pane now
  109. // using IResultData->RemoveItem, as we have no way of
  110. // removing it from all the possible views.
  111. // Instead, we call IConsole->UpdateAllViews which will
  112. // cause MMC to call Notify on each of our IComponent objects
  113. // with the MMCN_VIEW_CHANGE notification, and we will
  114. // repopulate the result view when we handle that notification.
  115. // We weren't passed an IConsole pointer here, so
  116. // we use the one we saved in out CComponentData object.
  117. TComponentData * pComponentData = GetComponentData();
  118. _ASSERTE( pComponentData != NULL );
  119. _ASSERTE( pComponentData->m_spConsole != NULL );
  120. // We pass in a pointer to 'this' because we want each
  121. // of our CComponent objects to update its result pane
  122. // view if 'this' node is the same as the saved currently
  123. // selected node.
  124. // We want to make sure all views get updated.
  125. CChangeNotification *pChangeNotification = new CChangeNotification();
  126. pChangeNotification->m_dwFlags = CHANGE_UPDATE_CHILDREN_OF_THIS_NODE;
  127. pChangeNotification->m_pNode = this;
  128. hr = pComponentData->m_spConsole->UpdateAllViews( NULL, (LPARAM) pChangeNotification, 0);
  129. pChangeNotification->Release();
  130. }
  131. else
  132. {
  133. // If we failed to remove, probably the child was never in the list
  134. // ISSUE: determine what do here -- this should never happen
  135. _ASSERTE( FALSE );
  136. hr = S_FALSE;
  137. }
  138. return hr;
  139. }
  140. //////////////////////////////////////////////////////////////////////////////
  141. /*++
  142. CNodeWithResultChildrenList::InsertColumns
  143. Override this in your derived class.
  144. This method is called by OnShow when it needs you to set the appropriate
  145. column headers to be displayed in the result pane for this node.
  146. --*/
  147. //////////////////////////////////////////////////////////////////////////////
  148. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent>
  149. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::InsertColumns( IHeaderCtrl* pHeaderCtrl )
  150. {
  151. ATLTRACE(_T("# CNodeWithResultChildrenList::InsertColumns -- override in your derived class\n"));
  152. // Check for preconditions:
  153. _ASSERTE( pHeaderCtrl );
  154. HRESULT hr;
  155. // override in your derived class and do something like:
  156. hr = pHeaderCtrl->InsertColumn( 0, L"@Column 1 -- override CNodeWithResultChildrenList::OnShowInsertColumns", 0, 120 );
  157. _ASSERT( S_OK == hr );
  158. hr = pHeaderCtrl->InsertColumn( 1, L"@Column 2 -- override CNodeWithResultChildrenList::OnShowInsertColumns", 0, 300 );
  159. _ASSERT( S_OK == hr );
  160. return hr;
  161. }
  162. //////////////////////////////////////////////////////////////////////////////
  163. /*++
  164. CNodeWithResultChildrenList::PopulateResultChildrenList
  165. Override this in your derived class.
  166. This is called by EnumerateResultChildren which is called by OnShow when
  167. you need to populate the list of children of this node.
  168. --*/
  169. //////////////////////////////////////////////////////////////////////////////
  170. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent>
  171. HRESULT CNodeWithResultChildrenList<T,CChildNode, TArray, TComponentData, TComponent>::PopulateResultChildrenList( void )
  172. {
  173. ATLTRACE(_T("# CNodeWithResultChildrenList::PopulateResultChildrenList -- override in your derived class\n"));
  174. // Check for preconditions:
  175. // None.
  176. // override in your derived class and do something like:
  177. /*
  178. CSomeChildNode *myChild1 = new CSomeChildNode();
  179. AddChildToList(myChild1);
  180. CSomeChildNode *myChild2 = new CSomeChildNode();
  181. AddChildToList(myChild2);
  182. CSomeChildNode *myChild3 = new CSomeChildNode();
  183. AddChildToList(myChild3);
  184. */
  185. return S_OK;
  186. }
  187. //////////////////////////////////////////////////////////////////////////////
  188. /*++
  189. CNodeWithResultChildrenList::RepopulateResultChildrenList
  190. DON'T Override this in your derived class.
  191. Call this to empty the list of children and repopulate it.
  192. This method will call PopulateResultChildrenList, which you should override.
  193. --*/
  194. //////////////////////////////////////////////////////////////////////////////
  195. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  196. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::RepopulateResultChildrenList()
  197. {
  198. ATLTRACE(_T("# CNodeWithResultChildrenList::RepopulateResultChildrenList -- DON'T override in your derived class\n"));
  199. // Check for preconditions:
  200. // None.
  201. HRESULT hr;
  202. // Get rid of what we had.
  203. // Delete each node in the list of children
  204. CChildNode* pChildNode;
  205. int iSize = m_ResultChildrenList.GetSize();
  206. for (int i = 0; i < iSize; i++)
  207. {
  208. pChildNode = m_ResultChildrenList[i];
  209. delete pChildNode;
  210. }
  211. // Empty the list
  212. m_ResultChildrenList.RemoveAll();
  213. // We no longer have a populated list.
  214. m_bResultChildrenListPopulated = FALSE;
  215. // Repopulate the list.
  216. hr = PopulateResultChildrenList();
  217. if( FAILED(hr) )
  218. {
  219. return( hr );
  220. }
  221. // We've already loaded our children ClientNode objects with
  222. // data necessary to populate the result pane.
  223. m_bResultChildrenListPopulated = TRUE; // We only want to do this once.
  224. return hr;
  225. }
  226. //////////////////////////////////////////////////////////////////////////////
  227. /*++
  228. CNodeWithResultChildrenList::CNodeWithResultChildrenList
  229. Constructor
  230. --*/
  231. //////////////////////////////////////////////////////////////////////////////
  232. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent>
  233. CNodeWithResultChildrenList<T,CChildNode, TArray, TComponentData, TComponent>::CNodeWithResultChildrenList(
  234. CSnapInItem* pParentNode,
  235. unsigned int helpIndex
  236. )
  237. :CSnapinNode<T, TComponentData, TComponent>(pParentNode, helpIndex)
  238. {
  239. ATLTRACE(_T("# +++ CNodeWithResultChildrenList::CNodeWithResultChildrenList\n"));
  240. // Check for preconditions:
  241. // None.
  242. // We have not yet loaded the child nodes' data
  243. m_bResultChildrenListPopulated = FALSE;
  244. }
  245. //////////////////////////////////////////////////////////////////////////////
  246. /*++
  247. CNodeWithResultChildrenList::~CNodeWithResultChildrenList
  248. Destructor
  249. --*/
  250. //////////////////////////////////////////////////////////////////////////////
  251. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  252. CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::~CNodeWithResultChildrenList()
  253. {
  254. ATLTRACE(_T("# --- CNodeWithResultChildrenList::~CNodeWithResultChildrenList\n"));
  255. // Check for preconditions:
  256. // None.
  257. // Delete each node in the list of children
  258. CChildNode* pChildNode;
  259. int iSize = m_ResultChildrenList.GetSize();
  260. for (int i = 0; i < iSize; i++)
  261. {
  262. pChildNode = m_ResultChildrenList[i];
  263. delete pChildNode;
  264. }
  265. // Empty the list
  266. m_ResultChildrenList.RemoveAll();
  267. }
  268. //////////////////////////////////////////////////////////////////////////////
  269. /*++
  270. CNodeWithResultChildrenList::AddChildToList
  271. Adds a child to the list of children. Does not cause a view update.
  272. Use this in your PopulateResultChildrenList method.
  273. --*/
  274. //////////////////////////////////////////////////////////////////////////////
  275. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  276. HRESULT CNodeWithResultChildrenList<T,CChildNode, TArray, TComponentData, TComponent>::AddChildToList( CChildNode * pChildNode )
  277. {
  278. // Check for preconditions:
  279. // None.
  280. HRESULT hr = S_OK;
  281. if( m_ResultChildrenList.Add( pChildNode ) )
  282. {
  283. hr = S_OK;
  284. }
  285. else
  286. {
  287. // Failed to add => out of memory
  288. hr = E_OUTOFMEMORY;
  289. }
  290. return hr;
  291. }
  292. //////////////////////////////////////////////////////////////////////////////
  293. /*++
  294. CNodeWithResultChildrenList::OnShow
  295. Don't override this in your derived class. Instead, override methods
  296. which it calls: InsertColumns and (indirectly) PopulateResultChildrenList
  297. This method is an override of CSnapinNode::OnShow. When MMC passes the
  298. MMCN_SHOW method for this node, we are to add children into the
  299. result pane. In this class we add them from a list we maintain.
  300. For more information, see CSnapinNode::OnShow.
  301. --*/
  302. //////////////////////////////////////////////////////////////////////////////
  303. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  304. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::OnShow(
  305. LPARAM arg
  306. , LPARAM param
  307. , IComponentData * pComponentData
  308. , IComponent * pComponent
  309. , DATA_OBJECT_TYPES type
  310. )
  311. {
  312. ATLTRACE(_T("# CNodeWithResultChildrenList::OnShow\n"));
  313. // Check for preconditions:
  314. _ASSERTE( pComponentData != NULL || pComponent != NULL );
  315. HRESULT hr = S_FALSE;
  316. T * pT = static_cast<T*>( this );
  317. //ISSUE: only do this if selected (arg = TRUE) -- what should we do if not selected?
  318. // See sburns' localsec example
  319. if( arg )
  320. {
  321. // arg <> 0 => we are being selected.
  322. // Note: This method will only get called with
  323. // arg <> 0 (i.e. selected) if you responded appropriately to
  324. // the MMCN_ADD_IMAGES method
  325. // We have been asked to display result pane nodes belonging under this node.
  326. // It appears we must do IResultData->InsertItems each time we receive
  327. // the MMCN_SHOW message -- MMC doesn't remember what nodes
  328. // we have previously inserted.
  329. // Set the column headers in the results pane
  330. // Note: if you don't set these, MMC will never
  331. // bother to put up your result-pane only items
  332. // When this Notify method is called from IComponentDataImpl, we
  333. // get pHeader (and pToolbar) passed in as NULL, so we aren't
  334. // going to bother using it and will instead always
  335. // QI pConsole for this pointer
  336. // Need IHeaderCtrl.
  337. // But to get that, first we need IConsole
  338. CComPtr<IConsole> spConsole;
  339. if( pComponentData != NULL )
  340. {
  341. spConsole = ((TComponentData*)pComponentData)->m_spConsole;
  342. }
  343. else
  344. {
  345. // We should have a non-null pComponent
  346. spConsole = ((TComponent*)pComponent)->m_spConsole;
  347. }
  348. _ASSERTE( spConsole != NULL );
  349. CComQIPtr<IHeaderCtrl, &IID_IHeaderCtrl> spHeaderCtrl(spConsole);
  350. _ASSERT( spHeaderCtrl != NULL );
  351. hr = pT->InsertColumns( spHeaderCtrl );
  352. _ASSERT( S_OK == hr );
  353. // Display our list of children in the result pane
  354. // Need IResultData
  355. CComQIPtr<IResultData, &IID_IResultData> spResultData(spConsole);
  356. _ASSERT( spResultData != NULL );
  357. hr = pT->EnumerateResultChildren( spResultData );
  358. }
  359. return hr;
  360. }
  361. /////////////////////////////////////////////////////////////////////////////
  362. /*++
  363. CNodeWithResultChildrenList::OnRefresh
  364. You shouldn't need to override this in your derived method. Simply
  365. enable the MMC_VERB_REFRESH for your node.
  366. In our implementation, this method gets called when the MMCN_REFRESH
  367. Notify message is sent for this node.
  368. For more information, see CSnapinNode::OnRefresh.
  369. --*/
  370. //////////////////////////////////////////////////////////////////////////////
  371. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  372. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::OnRefresh(
  373. LPARAM arg
  374. , LPARAM param
  375. , IComponentData * pComponentData
  376. , IComponent * pComponent
  377. , DATA_OBJECT_TYPES type
  378. )
  379. {
  380. ATLTRACE(_T("# CNodeWithResultChildrenList::OnRefresh\n"));
  381. // Update the views.
  382. // We weren't passed an IConsole pointer here, so
  383. // we use the one we saved in out CComponentData object.
  384. TComponentData * pMyComponentData = GetComponentData();
  385. _ASSERTE( pMyComponentData != NULL );
  386. _ASSERTE( pMyComponentData->m_spConsole != NULL );
  387. // We pass in a pointer to 'this' because we want each
  388. // of our CComponent objects to update its result pane
  389. // view if 'this' node is the same as the saved currently
  390. // selected node.
  391. // We want to make sure all views get updated.
  392. m_bResultChildrenListPopulated = FALSE;
  393. CChangeNotification *pChangeNotification = new CChangeNotification();
  394. pChangeNotification->m_dwFlags = CHANGE_UPDATE_CHILDREN_OF_THIS_NODE;
  395. pChangeNotification->m_pNode = this;
  396. HRESULT hr = pMyComponentData->m_spConsole->UpdateAllViews( NULL, (LPARAM) pChangeNotification, 0);
  397. pChangeNotification->Release();
  398. return hr;
  399. }
  400. //////////////////////////////////////////////////////////////////////////////
  401. /*++
  402. CNodeWithResultChildrenList::EnumerateResultChildren
  403. Don't override this in your derived class. Instead, override the method
  404. it calls, PopulateResultChildrenList.
  405. This is called by the OnShow method.
  406. --*/
  407. //////////////////////////////////////////////////////////////////////////////
  408. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  409. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::EnumerateResultChildren( IResultData * pResultData )
  410. {
  411. ATLTRACE(_T("# CNodeWithResultChildrenList::EnumerateResultChildren\n"));
  412. // Check for preconditions:
  413. _ASSERTE( pResultData != NULL );
  414. // need to first remove all items from result pane
  415. HRESULT hr = pResultData->DeleteAllRsltItems();
  416. if( FAILED(hr) )
  417. {
  418. return hr;
  419. }
  420. T * pT = static_cast<T*> (this);
  421. if ( FALSE == m_bResultChildrenListPopulated )
  422. {
  423. // We have not yet loaded all of our children into our list.
  424. // This call will add items to the list from whatever data source.
  425. hr = pT->PopulateResultChildrenList();
  426. if( FAILED(hr) )
  427. {
  428. return( hr );
  429. }
  430. // We've already loaded our children ClientNode objects with
  431. // data necessary to populate the result pane.
  432. m_bResultChildrenListPopulated = TRUE; // We only want to do this once.
  433. }
  434. // The ResultChildrenList is already populated, so we
  435. // just need to show the CChildNode objects to the world
  436. // by populating the result pane.
  437. CChildNode* pChildNode;
  438. for (int i = 0; i < m_ResultChildrenList.GetSize(); i++)
  439. {
  440. pChildNode = m_ResultChildrenList[i];
  441. if ( NULL == pChildNode )
  442. {
  443. continue;
  444. }
  445. // Insert the item into the result pane.
  446. hr = pResultData->InsertItem( &(pChildNode->m_resultDataItem) );
  447. if (FAILED(hr))
  448. {
  449. return hr;
  450. }
  451. // for some reason the item isn't showing up correctly in the result pane...
  452. // call this to force and upate of this item
  453. hr = pResultData->UpdateItem( pChildNode->m_resultDataItem.itemID );
  454. // Check: On return, the itemID member of 'm_resultDataItem'
  455. // contains the handle to the newly inserted item.
  456. _ASSERT( NULL != pChildNode->m_resultDataItem.itemID );
  457. }
  458. return hr;
  459. }
  460. template < class T, class CChildNode, class TArray, class TComponentData, class TComponent >
  461. HRESULT CNodeWithResultChildrenList<T, CChildNode, TArray, TComponentData, TComponent>::UpdateResultPane( IResultData * pResultData )
  462. {
  463. return EnumerateResultChildren(pResultData);
  464. }