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.

712 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: bennodes.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // BenefitsNodes.cpp
  11. //
  12. //////////////////////////////////////////////////////////////////////
  13. #include "stdafx.h"
  14. #include "resource.h"
  15. #include "BenNodes.h"
  16. #include "Dialogs.h"
  17. static const GUID CBuildingNodeGUID_NODETYPE =
  18. { 0xec362ef4, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } };
  19. const GUID* CBuildingNode::m_NODETYPE = &CBuildingNodeGUID_NODETYPE;
  20. const TCHAR* CBuildingNode::m_SZNODETYPE = _T("EC362EF4-D94D-11D1-8474-00104B211BE5");
  21. const TCHAR* CBuildingNode::m_SZDISPLAY_NAME = _T("Building");
  22. const CLSID* CBuildingNode::m_SNAPIN_CLASSID = &CLSID_Benefits;
  23. //
  24. // The following constructor initialiazes its base-class members and
  25. // initializes the building name, location, etc.
  26. //
  27. CBuildingNode::CBuildingNode( CKeyNode* pParentNode, BSTR strName, BSTR bstrLocation ) : CBenefitsData< CBuildingNode >( NULL )
  28. {
  29. _ASSERTE( pParentNode != NULL );
  30. m_resultDataItem.nImage = 3;
  31. m_bstrDisplayName = strName;
  32. m_bstrLocation = bstrLocation;
  33. //
  34. // Save the parent node for deletion purposes.
  35. //
  36. m_pParentNode = pParentNode;
  37. }
  38. //
  39. // Copy constructor.
  40. //
  41. CBuildingNode::CBuildingNode( const CBuildingNode &inNode ) : CBenefitsData< CBuildingNode >( NULL )
  42. {
  43. m_resultDataItem.nImage = inNode.m_resultDataItem.nImage;
  44. m_bstrDisplayName = inNode.m_bstrDisplayName;
  45. m_bstrLocation = inNode.m_bstrLocation;
  46. m_pParentNode = inNode.m_pParentNode;
  47. }
  48. //
  49. // Overridden to provide strings for various columns.
  50. //
  51. LPOLESTR CBuildingNode::GetResultPaneColInfo(int nCol)
  52. {
  53. CComBSTR szText;
  54. // The following switch statement dispatches to the
  55. // appropriate column index and loads the necessary
  56. // string.
  57. switch ( nCol )
  58. {
  59. case 0:
  60. szText = m_bstrDisplayName;
  61. break;
  62. case 1:
  63. szText = m_bstrLocation;
  64. break;
  65. default:
  66. ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" );
  67. }
  68. return( szText.Copy() );
  69. }
  70. static const GUID CRetirementNodeGUID_NODETYPE =
  71. { 0xec362ef2, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } };
  72. const GUID* CRetirementNode::m_NODETYPE = &CRetirementNodeGUID_NODETYPE;
  73. const TCHAR* CRetirementNode::m_SZNODETYPE = _T("EC362EF2D94D-11D1-8474-00104B211BE5");
  74. const TCHAR* CRetirementNode::m_SZDISPLAY_NAME = _T("401K Plan");
  75. const CLSID* CRetirementNode::m_SNAPIN_CLASSID = &CLSID_Benefits;
  76. //
  77. // The following constructor initialiazes its base-class members with
  78. // hard-coded values for display purposes. Since these are static nodes,
  79. // hard-coded values can be used for the following values.
  80. //
  81. CRetirementNode::CRetirementNode( CEmployee* pCurEmployee ) : CBenefitsData< CRetirementNode > ( pCurEmployee )
  82. {
  83. m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 0;
  84. m_scopeDataItem.cChildren = 0; // Not necessary unless modified.
  85. }
  86. CRetirementNode::~CRetirementNode()
  87. {
  88. }
  89. //
  90. // Specifies that the results should display a web page as its results. In
  91. // addition, the view options should be set so that standard lists, which
  92. // won't be applicable to this node, should not be available to the user.
  93. //
  94. STDMETHODIMP CRetirementNode::GetResultViewType( LPOLESTR* ppViewType, long* pViewOptions )
  95. {
  96. USES_CONVERSION;
  97. //
  98. // For this example to work, the sample control must be installed.
  99. //
  100. TCHAR* pszControl = _T( "{FE148827-3093-11D2-8494-00104B211BE5}" );
  101. // CoTaskMemAlloc(...) must be used since the MMC client frees the space using
  102. // CoTaskMemFree(...). Include enough space for NULL.
  103. //
  104. *ppViewType = (LPOLESTR) CoTaskMemAlloc( ( _tcslen( pszControl ) + 1 ) * sizeof( OLECHAR ) );
  105. _ASSERTE( *ppViewType != NULL );
  106. ocscpy( *ppViewType, T2OLE( pszControl ) );
  107. //
  108. // Set the view options so that no lists are displayed.
  109. //
  110. *pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
  111. return( S_OK );
  112. }
  113. //
  114. // Overridden to provide strings for various columns.
  115. //
  116. LPOLESTR CRetirementNode::GetResultPaneColInfo(int nCol)
  117. {
  118. CComBSTR szText;
  119. // The following switch statement dispatches to the
  120. // appropriate column index and loads the necessary
  121. // string.
  122. switch ( nCol )
  123. {
  124. case 0:
  125. szText = m_bstrDisplayName;
  126. break;
  127. case 1:
  128. szText.LoadString( _Module.GetResourceInstance(), IDS_RETIREMENT_DESC );
  129. break;
  130. default:
  131. ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" );
  132. }
  133. return( szText.Copy() );
  134. }
  135. //
  136. // Command handler for "Enroll" functionality.
  137. //
  138. STDMETHODIMP CRetirementNode::OnEnroll( bool& bHandled, CSnapInObjectRootBase* pObj )
  139. {
  140. UNUSED_ALWAYS( bHandled );
  141. UNUSED_ALWAYS( pObj );
  142. #ifdef _BENEFITS_DIALOGS
  143. CRetirementEnrollDialog dlg;
  144. dlg.SetEmployee( m_pEmployee );
  145. dlg.DoModal();
  146. #else
  147. CComPtr<IConsole> spConsole;
  148. int nResult;
  149. //
  150. // Retrieve the appropriate console.
  151. //
  152. GetConsole( pObj, &spConsole );
  153. spConsole->MessageBox( L"Enrolled",
  154. L"Benefits",
  155. MB_ICONINFORMATION | MB_OK,
  156. &nResult );
  157. #endif
  158. return( S_OK );
  159. }
  160. //
  161. // Command handler for "Update" functionality. Demonstrates calling a
  162. // displayed OCX's method.
  163. //
  164. STDMETHODIMP CRetirementNode::OnUpdate( bool& bHandled, CSnapInObjectRootBase* pObj )
  165. {
  166. UNUSED_ALWAYS( bHandled );
  167. UNUSED_ALWAYS( pObj );
  168. HRESULT hr = E_FAIL;
  169. if ( m_spControl )
  170. {
  171. //
  172. // This should trigger the OCX to refresh its historical information.
  173. //
  174. hr = m_spControl->Refresh();
  175. }
  176. return( hr );
  177. }
  178. static const GUID CHealthNodeGUID_NODETYPE =
  179. { 0xec362ef1, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } };
  180. const GUID* CHealthNode::m_NODETYPE = &CHealthNodeGUID_NODETYPE;
  181. const TCHAR* CHealthNode::m_SZNODETYPE = _T("EC362EF1D94D-11D1-8474-00104B211BE5");
  182. const TCHAR* CHealthNode::m_SZDISPLAY_NAME = _T("Health & Dental Plan");
  183. const CLSID* CHealthNode::m_SNAPIN_CLASSID = &CLSID_Benefits;
  184. //
  185. // Hard coded tasks to be associated with the health node.
  186. //
  187. MMC_TASK g_HealthTasks[ 3 ] =
  188. {
  189. { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\WebPage.gif", L"img\\WebPage.gif", L"Microsoft", L"General Microsoft resources", MMC_ACTION_LINK, (long) L"http://www.microsoft.com" },
  190. { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\WebPage.gif", L"img\\WebPage.gif", L"Microsoft Management Site", L"More MMC oriented resources", MMC_ACTION_LINK, (long) L"http://www.microsoft.com/management" },
  191. { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\Query.gif", L"img\\Query.gif", L"Local Query", L"Start query on local database", MMC_ACTION_ID, TASKPAD_LOCALQUERY },
  192. };
  193. //
  194. // The following constructor initialiazes its base-class members with
  195. // hard-coded values for display purposes. Since these are static nodes,
  196. // hard-coded values can be used for the following values.
  197. //
  198. CHealthNode::CHealthNode( CEmployee* pCurEmployee ) : CBenefitsData<CHealthNode> ( pCurEmployee )
  199. {
  200. m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 1;
  201. m_scopeDataItem.cChildren = 0; // Not necessary unless modified.
  202. m_fTaskpad = FALSE;
  203. }
  204. CHealthNode::~CHealthNode()
  205. {
  206. }
  207. //
  208. // Specifies that the results should display a web page as its results. In
  209. // addition, the view options should be set so that standard lists, which
  210. // won't be applicable to this node, should not be available to the user.
  211. //
  212. STDMETHODIMP CHealthNode::GetResultViewType( LPOLESTR* ppViewType, long* pViewOptions )
  213. {
  214. USES_CONVERSION;
  215. TCHAR szPath[ _MAX_PATH ];
  216. TCHAR szModulePath[ _MAX_PATH ];
  217. //
  218. // Set the view options to no preferences.
  219. //
  220. *pViewOptions = MMC_VIEW_OPTIONS_NONE;
  221. if ( m_fTaskpad )
  222. {
  223. //
  224. // In the taskpad case, the module path of MMC.EXE should be
  225. // obtained. Use the template contained therein.
  226. //
  227. GetModuleFileName( NULL, szModulePath, _MAX_PATH );
  228. //
  229. // Append the necessary decorations for correct access.
  230. //
  231. _tcscpy( szPath, _T( "res://" ) );
  232. _tcscat( szPath, szModulePath );
  233. _tcscat( szPath, _T( "/default.htm" ) );
  234. }
  235. else
  236. {
  237. //
  238. // Use the HTML page that is embedded as a resource of
  239. // this module for display purposes.
  240. //
  241. GetModuleFileName( _Module.GetModuleInstance(), szModulePath, _MAX_PATH );
  242. //
  243. // Append the necessary decorations for correct access.
  244. //
  245. _tcscpy( szPath, _T( "res://" ) );
  246. _tcscat( szPath, szModulePath );
  247. _tcscat( szPath, _T( "/health.htm" ) );
  248. }
  249. //
  250. // CoTaskMemAlloc(...) must be used since the MMC client frees the space using
  251. // CoTaskMemFree(...). Include enough space for NULL.
  252. //
  253. *ppViewType = (LPOLESTR) CoTaskMemAlloc( ( _tcslen( szPath ) + 1 ) * sizeof( OLECHAR ) );
  254. _ASSERTE( *ppViewType != NULL );
  255. ocscpy( *ppViewType, T2OLE( szPath ) );
  256. return( S_OK );
  257. }
  258. //
  259. // Overridden to provide strings for various columns.
  260. //
  261. LPOLESTR CHealthNode::GetResultPaneColInfo(int nCol)
  262. {
  263. USES_CONVERSION;
  264. CComBSTR szText;
  265. // The following switch statement dispatches to the
  266. // appropriate column index and loads the necessary
  267. // string.
  268. switch ( nCol )
  269. {
  270. case 0:
  271. szText = m_bstrDisplayName;
  272. break;
  273. case 1:
  274. szText.LoadString( _Module.GetResourceInstance(), IDS_HEALTH_DESC );
  275. break;
  276. default:
  277. ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" );
  278. }
  279. return( szText.Copy() );
  280. }
  281. //
  282. // Command handler for "Enroll" functionality.
  283. //
  284. STDMETHODIMP CHealthNode::OnEnroll( bool& bHandled, CSnapInObjectRootBase* pObj )
  285. {
  286. UNUSED_ALWAYS( bHandled );
  287. UNUSED_ALWAYS( pObj );
  288. #ifdef _BENEFITS_DIALOGS
  289. CHealthEnrollDialog dlg;
  290. dlg.SetEmployee( m_pEmployee );
  291. dlg.DoModal();
  292. #else
  293. CComPtr<IConsole> spConsole;
  294. int nResult;
  295. //
  296. // Retrieve the appropriate console.
  297. //
  298. GetConsole( pObj, &spConsole );
  299. spConsole->MessageBox( L"Enrolled",
  300. L"Benefits",
  301. MB_ICONINFORMATION | MB_OK,
  302. &nResult );
  303. #endif
  304. return( S_OK );
  305. }
  306. //
  307. // Restores any state, especially in the case of using a
  308. // taskpad, when the back and forward buttons are used by
  309. // the user for navigation.
  310. //
  311. STDMETHODIMP CHealthNode::OnRestoreView( MMC_RESTORE_VIEW* pRestoreView, BOOL* pfHandled )
  312. {
  313. _ASSERTE( pRestoreView->dwSize == sizeof( MMC_RESTORE_VIEW ) );
  314. *pfHandled = TRUE;
  315. return( S_OK );
  316. }
  317. //
  318. // Called when one of the tasks is clicked.
  319. //
  320. STDMETHODIMP CHealthNode::TaskNotify( IConsole* pConsole, VARIANT* arg, VARIANT* param )
  321. {
  322. UNUSED_ALWAYS( arg );
  323. UNUSED_ALWAYS( param );
  324. HRESULT hr = E_FAIL;
  325. //
  326. // Determine if the given notification is for the
  327. // start query button.
  328. //
  329. if ( arg->lVal == TASKPAD_LOCALQUERY )
  330. {
  331. CComPtr<IConsole> spConsole = pConsole;
  332. int nResult;
  333. //
  334. // Display a message box to demonstrate the
  335. // handling of the taskpad notification.
  336. //
  337. spConsole->MessageBox( L"Local query started",
  338. L"Health Taskpad",
  339. MB_ICONINFORMATION | MB_OK,
  340. &nResult );
  341. hr = S_OK;
  342. }
  343. return( hr );
  344. }
  345. //
  346. // Returns an enumerator for all of these tasks.
  347. //
  348. STDMETHODIMP CHealthNode::EnumTasks( LPOLESTR szTaskGroup, IEnumTASK** ppEnumTASK )
  349. {
  350. UNUSED_ALWAYS( szTaskGroup );
  351. MMC_TASK CoTasks[ sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ];
  352. typedef CComObject< CComEnum< IEnumTASK, &IID_IEnumTASK, MMC_TASK, _Copy<MMC_TASK> > > enumvar;
  353. enumvar* p = new enumvar;
  354. //
  355. // Copy the local tasks to our temporary task structures. This
  356. // performs the CoTaskMemAlloc for the strings, etc. It also
  357. // maps image type resources to the local module name.
  358. //
  359. if ( CoTasksDup( CoTasks, g_HealthTasks, sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ) )
  360. {
  361. p->Init( &CoTasks[ 0 ], &CoTasks[ sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ], NULL, AtlFlagCopy);
  362. return( p->QueryInterface( IID_IEnumTASK, (void**) ppEnumTASK ) );
  363. }
  364. return( E_FAIL );
  365. }
  366. static const GUID CKeyNodeGUID_NODETYPE =
  367. { 0xec362ef3, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } };
  368. const GUID* CKeyNode::m_NODETYPE = &CKeyNodeGUID_NODETYPE;
  369. const TCHAR* CKeyNode::m_SZNODETYPE = _T("EC362EF3D94D-11D1-8474-00104B211BE5");
  370. const TCHAR* CKeyNode::m_SZDISPLAY_NAME = _T("Card Key Permissions");
  371. const CLSID* CKeyNode::m_SNAPIN_CLASSID = &CLSID_Benefits;
  372. //
  373. // Used for the key node example.
  374. //
  375. extern BUILDINGDATA g_Buildings[ 3 ];
  376. //
  377. // The following constructor initialiazes its base-class members with
  378. // hard-coded values for display purposes. Since these are static nodes,
  379. // hard-coded values can be used for the following values.
  380. //
  381. CKeyNode::CKeyNode( CEmployee* pCurEmployee ) : CChildrenBenefitsData<CKeyNode>( pCurEmployee )
  382. {
  383. USES_CONVERSION;
  384. m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 2;
  385. m_scopeDataItem.cChildren = 0; // Not necessary unless modified.
  386. //
  387. // Populate building nodes based on this employees permissions.
  388. //
  389. for ( int i = 0; i < sizeof( g_Buildings ) / sizeof( BUILDINGDATA ); i++ )
  390. {
  391. //
  392. // Only add an item if the given employee has access to the
  393. // building.
  394. //
  395. if ( g_Buildings[ i ].dwId & pCurEmployee->m_Access.dwAccess )
  396. {
  397. CSnapInItem* pItem;
  398. pItem = new CBuildingNode( this, W2BSTR( g_Buildings[ i ].pstrName ), W2BSTR( g_Buildings[ i ].pstrLocation ) );
  399. m_Nodes.Add( pItem );
  400. }
  401. }
  402. }
  403. CKeyNode::~CKeyNode()
  404. {
  405. }
  406. //
  407. // Overridden to provide strings for various columns.
  408. //
  409. LPOLESTR CKeyNode::GetResultPaneColInfo(int nCol)
  410. {
  411. CComBSTR szText;
  412. // The following switch statement dispatches to the
  413. // appropriate column index and loads the necessary
  414. // string.
  415. switch ( nCol )
  416. {
  417. case 0:
  418. szText = m_bstrDisplayName;
  419. break;
  420. case 1:
  421. szText.LoadString( _Module.GetResourceInstance(), IDS_KEY_DESC );
  422. break;
  423. default:
  424. ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" );
  425. }
  426. return( szText.Copy() );
  427. }
  428. //
  429. // Overridden to add new columns to the results
  430. // display.
  431. //
  432. STDMETHODIMP CKeyNode::OnShowColumn( IHeaderCtrl* pHeader )
  433. {
  434. USES_CONVERSION;
  435. HRESULT hr = E_FAIL;
  436. CComPtr<IHeaderCtrl> spHeader( pHeader );
  437. // Add two columns: one with the name of the object and one with
  438. // the description of the node. Use the value of 100 pixels as the size.
  439. hr = spHeader->InsertColumn( 0, T2OLE( _T( "Building" ) ), LVCFMT_LEFT, 200 );
  440. _ASSERTE( SUCCEEDED( hr ) );
  441. // Add the second column. Use the value of 200 pixels as the size.
  442. hr = spHeader->InsertColumn( 1, T2OLE( _T( "Location" ) ), LVCFMT_LEFT, 350 );
  443. _ASSERTE( SUCCEEDED( hr ) );
  444. return( hr );
  445. }
  446. //
  447. // Command handler for "Grant Access" functionality.
  448. //
  449. STDMETHODIMP CKeyNode::OnGrantAccess( bool& bHandled, CSnapInObjectRootBase* pObj )
  450. {
  451. UNUSED_ALWAYS( bHandled );
  452. UNUSED_ALWAYS( pObj );
  453. #ifdef _BENEFITS_DIALOGS
  454. CBuildingAccessDialog dlg;
  455. dlg.SetEmployee( m_pEmployee );
  456. dlg.DoModal();
  457. #else
  458. CComPtr<IConsole> spConsole;
  459. int nResult;
  460. //
  461. // Retrieve the appropriate console.
  462. //
  463. GetConsole( pObj, &spConsole );
  464. spConsole->MessageBox( L"Access granted",
  465. L"Benefits",
  466. MB_ICONINFORMATION | MB_OK,
  467. &nResult );
  468. #endif
  469. return( S_OK );
  470. }
  471. //
  472. // Called by the console to determine if we can paste the
  473. // specified node.
  474. //
  475. STDMETHODIMP CKeyNode::OnQueryPaste( LPDATAOBJECT pDataObject )
  476. {
  477. HRESULT hr;
  478. //
  479. // Determine if the type of object being pasted is the right
  480. // type.
  481. //
  482. hr = IsClipboardDataType( pDataObject, CBuildingNodeGUID_NODETYPE );
  483. if ( SUCCEEDED( hr ) )
  484. {
  485. CBuildingNode* pItem;
  486. DATA_OBJECT_TYPES Type;
  487. //
  488. // Loop through all of currently contained nodes and
  489. // determine if we already contain the specified building
  490. // by comparing building names.
  491. //
  492. hr = CSnapInItem::GetDataClass( pDataObject, (CSnapInItem**) &pItem, &Type );
  493. if ( SUCCEEDED( hr ) )
  494. {
  495. for ( int i = 0; i < m_Nodes.GetSize(); i++ )
  496. {
  497. CBuildingNode* pTemp;
  498. CComBSTR bstrTemp;
  499. //
  500. // Retrieve the node from our internal list.
  501. //
  502. pTemp = dynamic_cast<CBuildingNode*>( m_Nodes[ i ] );
  503. _ASSERTE( pTemp != NULL );
  504. //
  505. // If the names are equal, indicate failure
  506. // and break out.
  507. //
  508. if ( wcscmp( pItem->m_bstrDisplayName, pTemp->m_bstrDisplayName ) == 0 )
  509. {
  510. hr = S_FALSE;
  511. break;
  512. }
  513. }
  514. }
  515. }
  516. return( hr );
  517. }
  518. //
  519. // Called by MMC when the item should be pasted.
  520. //
  521. STDMETHODIMP CKeyNode::OnPaste( IConsole* pConsole, LPDATAOBJECT pDataObject, LPDATAOBJECT* ppDataObject )
  522. {
  523. HRESULT hr;
  524. //
  525. // Ensure the data is of the correct type.
  526. //
  527. hr = IsClipboardDataType( pDataObject, CBuildingNodeGUID_NODETYPE );
  528. if ( SUCCEEDED( hr ) )
  529. {
  530. try
  531. {
  532. CBuildingNode* pItem;
  533. DATA_OBJECT_TYPES Type;
  534. //
  535. // Retrieve the passed in item.
  536. //
  537. hr = CSnapInItem::GetDataClass( pDataObject, (CSnapInItem**) &pItem, &Type );
  538. if ( FAILED( hr ) )
  539. throw;
  540. //
  541. // Allocate a new building node. The constructor
  542. // copies the values from the input node.
  543. //
  544. CSnapInItem* pNewNode = new CBuildingNode( *pItem );
  545. if ( pNewNode == NULL )
  546. throw;
  547. //
  548. // Add the node to the end of our internal array.
  549. //
  550. m_Nodes.Add( pNewNode );
  551. //
  552. // Reselect ourselves to cause a refresh.
  553. //
  554. pConsole->SelectScopeItem( m_scopeDataItem.ID );
  555. //
  556. // Put the given data object into the returned dataobject
  557. // so that MMC may complete its cut tasks.
  558. //
  559. *ppDataObject = pDataObject;
  560. hr = S_OK;
  561. }
  562. catch( ... )
  563. {
  564. //
  565. // Assume all failures are total.
  566. //
  567. hr = E_FAIL;
  568. }
  569. }
  570. return( hr );
  571. }
  572. //
  573. // Called by one of our children nodes to inform us that
  574. // they should be deleted. This occurs when the user selects
  575. // a delete action on the building. This function should not
  576. // only delete the building, but also handle the refresh of
  577. // the result display.
  578. //
  579. STDMETHODIMP CKeyNode::OnDeleteBuilding( IConsole* pConsole, CBuildingNode* pChildNode )
  580. {
  581. _ASSERTE( pConsole != NULL );
  582. _ASSERTE( pChildNode != NULL );
  583. HRESULT hr = E_FAIL;
  584. //
  585. // First, loop through all of our contained members and
  586. // remove it from the contained list.
  587. //
  588. for ( int i = 0; i < m_Nodes.GetSize(); i++ )
  589. {
  590. if ( m_Nodes[ i ] == pChildNode )
  591. {
  592. //
  593. // We have found a match. Remove it from the
  594. // contained list.
  595. //
  596. m_Nodes.RemoveAt( i );
  597. //
  598. // Reselect ourselves to cause a refresh.
  599. //
  600. pConsole->SelectScopeItem( m_scopeDataItem.ID );
  601. //
  602. // Since there should only be one match, break out
  603. // of the find process. Indicate success.
  604. //
  605. hr = S_OK;
  606. break;
  607. }
  608. }
  609. return( hr );
  610. }