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.

1667 lines
41 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name :
  4. app_pools.cpp
  5. Abstract:
  6. IIS Application Pools nodes
  7. Author:
  8. Sergei Antonov (sergeia)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. 11/03/2000 sergeia Initial creation
  13. --*/
  14. #include "stdafx.h"
  15. #include "common.h"
  16. #include "inetprop.h"
  17. #include "InetMgrApp.h"
  18. #include "iisobj.h"
  19. #include "shts.h"
  20. #include "app_sheet.h"
  21. #include "app_pool_sheet.h"
  22. #include "tracker.h"
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif
  27. #define new DEBUG_NEW
  28. extern CPropertySheetTracker g_OpenPropertySheetTracker;
  29. CAppPoolsContainer::CAppPoolsContainer(
  30. CIISMachine * pOwner,
  31. CIISService * pService
  32. )
  33. : CIISMBNode(pOwner, SZ_MBN_APP_POOLS),
  34. m_pWebService(pService)
  35. {
  36. VERIFY(m_bstrDisplayName.LoadString(IDS_APP_POOLS));
  37. }
  38. CAppPoolsContainer::~CAppPoolsContainer()
  39. {
  40. }
  41. /*virtual*/
  42. HRESULT
  43. CAppPoolsContainer::RefreshData()
  44. {
  45. CError err;
  46. CComBSTR bstrPath;
  47. err = BuildMetaPath(bstrPath);
  48. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath);
  49. if (!IsLostInterface(err))
  50. {
  51. // reset error if an other error other than No interface
  52. err.Reset();
  53. }
  54. if (err.Succeeded())
  55. {
  56. return CIISMBNode::RefreshData();
  57. }
  58. DisplayError(err);
  59. return err;
  60. }
  61. HRESULT
  62. CAppPoolsContainer::RefreshDataChildren(CString AppPoolToRefresh,BOOL bVerifyChildren)
  63. {
  64. IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  65. HSCOPEITEM hChildItem = NULL;
  66. LONG_PTR cookie;
  67. BOOL bMyVerifyChildren = FALSE;
  68. HRESULT hr = pConsoleNameSpace->GetChildItem(m_hScopeItem, &hChildItem, &cookie);
  69. if (AppPoolToRefresh.IsEmpty())
  70. {
  71. // don't verify children when they ask for *.*
  72. bMyVerifyChildren = FALSE;
  73. }
  74. else
  75. {
  76. bMyVerifyChildren = TRUE;
  77. }
  78. if (bVerifyChildren)
  79. {
  80. bMyVerifyChildren = TRUE;
  81. }
  82. while(SUCCEEDED(hr) && hChildItem)
  83. {
  84. CAppPoolNode * pItem = (CAppPoolNode *)cookie;
  85. if (pItem)
  86. {
  87. if (pItem->IsExpanded())
  88. {
  89. if (AppPoolToRefresh.IsEmpty())
  90. {
  91. pItem->RefreshData(TRUE,bMyVerifyChildren);
  92. pItem->RefreshDisplay(FALSE);
  93. }
  94. else
  95. {
  96. if (0 == AppPoolToRefresh.CompareNoCase(pItem->QueryDisplayName()))
  97. {
  98. pItem->RefreshData(TRUE,bMyVerifyChildren);
  99. pItem->RefreshDisplay(FALSE);
  100. }
  101. }
  102. }
  103. }
  104. hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
  105. }
  106. return hr;
  107. }
  108. /* virtual */
  109. HRESULT
  110. CAppPoolsContainer::EnumerateScopePane(HSCOPEITEM hParent)
  111. {
  112. CPoolList list;
  113. CError err = EnumerateAppPools(&list);
  114. if (err.Succeeded())
  115. {
  116. POSITION pos = list.GetHeadPosition();
  117. while (pos)
  118. {
  119. CAppPoolNode * pool = list.GetNext(pos);
  120. pool->AddRef();
  121. err = pool->AddToScopePane(hParent);
  122. if (err.Failed())
  123. {
  124. pool->Release();
  125. break;
  126. }
  127. }
  128. }
  129. list.RemoveAll();
  130. DisplayError(err);
  131. return err;
  132. }
  133. /* virtual */
  134. LPOLESTR
  135. CAppPoolsContainer::GetResultPaneColInfo(int nCol)
  136. {
  137. if (nCol == 0)
  138. {
  139. return QueryDisplayName();
  140. }
  141. return OLESTR("");
  142. }
  143. HRESULT
  144. CAppPoolsContainer::EnumerateAppPools(CPoolList * pList)
  145. {
  146. ASSERT(pList != NULL);
  147. CString strPool;
  148. CComBSTR bstrPath;
  149. CError err;
  150. DWORD dwState;
  151. do
  152. {
  153. err = BuildMetaPath(bstrPath);
  154. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath);
  155. BREAK_ON_ERR_FAILURE(err)
  156. CMetaKey mk(QueryInterface(), bstrPath, METADATA_PERMISSION_READ);
  157. err = mk.QueryResult();
  158. BREAK_ON_ERR_FAILURE(err)
  159. CStringListEx list;
  160. err = mk.GetChildPaths(list);
  161. BREAK_ON_ERR_FAILURE(err)
  162. CString key_type;
  163. POSITION pos = list.GetHeadPosition();
  164. while (err.Succeeded() && pos != NULL)
  165. {
  166. strPool = list.GetNext(pos);
  167. err = mk.QueryValue(MD_KEY_TYPE, key_type, NULL, strPool);
  168. if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND)
  169. {
  170. err.Reset();
  171. }
  172. err = mk.QueryValue(MD_APPPOOL_STATE, dwState, NULL, strPool);
  173. if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND)
  174. {
  175. // if not found then it's state is off..
  176. dwState = MD_APPPOOL_STATE_STOPPED;
  177. err.Reset();
  178. }
  179. // Get the app pool state
  180. if (err.Succeeded() && (key_type.CompareNoCase(_T("IIsApplicationPool")) == 0))
  181. {
  182. CAppPoolNode * pool;
  183. if (NULL == (pool = new CAppPoolNode(m_pOwner, this, strPool, dwState)))
  184. {
  185. err = ERROR_NOT_ENOUGH_MEMORY;
  186. break;
  187. }
  188. pList->AddTail(pool);
  189. }
  190. }
  191. } while (FALSE);
  192. return err;
  193. }
  194. /* virtual */
  195. void
  196. CAppPoolsContainer::InitializeChildHeaders(LPHEADERCTRL lpHeader)
  197. /*++
  198. Routine Description:
  199. Build result view for immediate descendant type
  200. Arguments:
  201. LPHEADERCTRL lpHeader : Header control
  202. --*/
  203. {
  204. CAppPoolNode::InitializeHeaders(lpHeader);
  205. }
  206. /* virtual */
  207. HRESULT
  208. CAppPoolsContainer::CreatePropertyPages(
  209. LPPROPERTYSHEETCALLBACK lpProvider,
  210. LONG_PTR handle,
  211. IUnknown * pUnk,
  212. DATA_OBJECT_TYPES type
  213. )
  214. /*++
  215. Routine Description:
  216. Create the property pages for the given object
  217. Arguments:
  218. LPPROPERTYSHEETCALLBACK lpProvider : Provider
  219. LONG_PTR handle : Handle.
  220. IUnknown * pUnk,
  221. DATA_OBJECT_TYPES type
  222. Return Value:
  223. HRESULT
  224. --*/
  225. {
  226. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  227. CError err;
  228. if (S_FALSE == (HRESULT)(err = CIISMBNode::CreatePropertyPages(lpProvider, handle, pUnk, type)))
  229. {
  230. return S_OK;
  231. }
  232. if (ERROR_ALREADY_EXISTS == err.Win32Error())
  233. {
  234. return S_FALSE;
  235. }
  236. if (err.Succeeded())
  237. {
  238. CComBSTR path;
  239. err = BuildMetaPath(path);
  240. if (err.Succeeded())
  241. {
  242. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,path);
  243. if (err.Succeeded())
  244. {
  245. CAppPoolSheet * pSheet = new CAppPoolSheet(
  246. QueryAuthInfo(), path, GetMainWindow(GetConsole()), (LPARAM)this,
  247. (LPARAM)GetOwner()
  248. );
  249. if (pSheet != NULL)
  250. {
  251. // cache handle for user in MMCPropertyChangeNotify
  252. m_ppHandle = handle;
  253. pSheet->SetModeless();
  254. err = AddMMCPage(lpProvider, new CAppPoolRecycle(pSheet));
  255. err = AddMMCPage(lpProvider, new CAppPoolPerf(pSheet));
  256. err = AddMMCPage(lpProvider, new CAppPoolHealth(pSheet));
  257. // err = AddMMCPage(lpProvider, new CAppPoolDebug(pSheet));
  258. err = AddMMCPage(lpProvider, new CAppPoolIdent(pSheet));
  259. // err = AddMMCPage(lpProvider, new CAppPoolCache(pSheet));
  260. // err = AddMMCPage(lpProvider, new CPoolProcessOpt(pSheet));
  261. }
  262. }
  263. }
  264. }
  265. err.MessageBoxOnFailure();
  266. return err;
  267. }
  268. /* virtual */
  269. HRESULT
  270. CAppPoolsContainer::BuildMetaPath(
  271. OUT CComBSTR & bstrPath
  272. ) const
  273. /*++
  274. Routine Description:
  275. Recursively build up the metabase path from the current node
  276. and its parents. We cannot use CIISMBNode method because AppPools
  277. is located under w3svc, but rendered after machine.
  278. Arguments:
  279. CComBSTR & bstrPath : Returns metabase path
  280. Return Value:
  281. HRESULT
  282. --*/
  283. {
  284. HRESULT hr = S_OK;
  285. ASSERT(m_pWebService != NULL);
  286. hr = m_pWebService->BuildMetaPath(bstrPath);
  287. if (SUCCEEDED(hr))
  288. {
  289. bstrPath.Append(_cszSeparator);
  290. bstrPath.Append(QueryNodeName());
  291. return hr;
  292. }
  293. //
  294. // No service node
  295. //
  296. ASSERT_MSG("No WebService pointer");
  297. return E_UNEXPECTED;
  298. }
  299. HRESULT
  300. CAppPoolsContainer::QueryDefaultPoolId(CString& id)
  301. //
  302. // Returns pool id which is set on master node for web service
  303. //
  304. {
  305. CError err;
  306. CComBSTR path;
  307. CString service;
  308. BuildMetaPath(path);
  309. CMetabasePath::GetServicePath(path, service);
  310. CMetaKey mk(QueryAuthInfo(), service, METADATA_PERMISSION_READ);
  311. err = mk.QueryResult();
  312. if (err.Succeeded())
  313. {
  314. err = mk.QueryValue(MD_APP_APPPOOL_ID, id);
  315. }
  316. return err;
  317. }
  318. /* virtual */
  319. HRESULT
  320. CAppPoolsContainer::AddMenuItems(
  321. IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
  322. IN OUT long * pInsertionAllowed,
  323. IN DATA_OBJECT_TYPES type
  324. )
  325. {
  326. ASSERT_READ_PTR(lpContextMenuCallback);
  327. //
  328. // Add base menu items
  329. //
  330. HRESULT hr = CIISObject::AddMenuItems(
  331. lpContextMenuCallback,
  332. pInsertionAllowed,
  333. type
  334. );
  335. if (SUCCEEDED(hr))
  336. {
  337. ASSERT(pInsertionAllowed != NULL);
  338. if (IsAdministrator())
  339. {
  340. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
  341. {
  342. AddMenuSeparator(lpContextMenuCallback);
  343. AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL);
  344. if (IsConfigImportExportable())
  345. {
  346. AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL_FROM_FILE);
  347. }
  348. }
  349. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
  350. {
  351. if (IsConfigImportExportable())
  352. {
  353. AddMenuSeparator(lpContextMenuCallback);
  354. AddMenuItemByCommand(lpContextMenuCallback, IDM_TASK_EXPORT_CONFIG_WIZARD);
  355. }
  356. }
  357. }
  358. }
  359. return hr;
  360. }
  361. HRESULT
  362. CAppPoolsContainer::Command(
  363. long lCommandID,
  364. CSnapInObjectRootBase * pObj,
  365. DATA_OBJECT_TYPES type
  366. )
  367. {
  368. HRESULT hr = S_OK;
  369. CString name;
  370. switch (lCommandID)
  371. {
  372. case IDM_NEW_APP_POOL:
  373. {
  374. CError err;
  375. CComBSTR bstrMetaPath;
  376. VERIFY(SUCCEEDED(BuildMetaPath(bstrMetaPath)));
  377. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
  378. if (!IsLostInterface(err))
  379. {
  380. // reset error if an other error other than No interface
  381. err.Reset();
  382. }
  383. if (err.Succeeded())
  384. {
  385. if ( SUCCEEDED(hr = AddAppPool(pObj, type, this, name))
  386. && !name.IsEmpty()
  387. )
  388. {
  389. hr = InsertNewPool(name);
  390. }
  391. }
  392. }
  393. break;
  394. //
  395. // Pass on to base class
  396. //
  397. default:
  398. hr = CIISMBNode::Command(lCommandID, pObj, type);
  399. }
  400. return hr;
  401. }
  402. HRESULT
  403. CAppPoolsContainer::InsertNewPool(CString& id)
  404. {
  405. CError err;
  406. if (!IsExpanded())
  407. {
  408. SelectScopeItem();
  409. IConsoleNameSpace2 * pConsoleNameSpace
  410. = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  411. pConsoleNameSpace->Expand(QueryScopeItem());
  412. HSCOPEITEM hChildItem = NULL;
  413. LONG_PTR cookie;
  414. HRESULT hr = pConsoleNameSpace->GetChildItem(m_hScopeItem, &hChildItem, &cookie);
  415. while(SUCCEEDED(hr) && hChildItem)
  416. {
  417. CAppPoolNode * pItem = (CAppPoolNode *)cookie;
  418. ASSERT_PTR(pItem);
  419. if (0 == id.Compare(pItem->QueryDisplayName()))
  420. {
  421. pItem->SelectScopeItem();
  422. // set status to running when creating a new apppool
  423. pItem->ChangeState(MD_APPPOOL_COMMAND_START);
  424. break;
  425. }
  426. hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
  427. }
  428. }
  429. else
  430. {
  431. // Now we should insert and select this new site
  432. CAppPoolNode * pPool = new CAppPoolNode(m_pOwner, this, id, 0);
  433. if (pPool != NULL)
  434. {
  435. err = pPool->RefreshData();
  436. if (err.Succeeded())
  437. {
  438. pPool->AddRef();
  439. err = pPool->AddToScopePaneSorted(QueryScopeItem(), FALSE);
  440. if (err.Succeeded())
  441. {
  442. VERIFY(SUCCEEDED(pPool->SelectScopeItem()));
  443. // set status to running when creating a new apppool
  444. pPool->ChangeState(MD_APPPOOL_COMMAND_START);
  445. }
  446. else
  447. {
  448. pPool->Release();
  449. }
  450. }
  451. }
  452. else
  453. {
  454. err = ERROR_NOT_ENOUGH_MEMORY;
  455. }
  456. }
  457. return err;
  458. }
  459. ////////////////////////////////////////////////////////////////////////////////
  460. // CAppPoolNode implementation
  461. //
  462. // App Pool Result View definition
  463. //
  464. /* static */ int
  465. CAppPoolNode::_rgnLabels[COL_TOTAL] =
  466. {
  467. IDS_RESULT_SERVICE_DESCRIPTION,
  468. IDS_RESULT_SERVICE_STATE,
  469. IDS_RESULT_STATUS
  470. };
  471. /* static */ int
  472. CAppPoolNode::_rgnWidths[COL_TOTAL] =
  473. {
  474. 180,
  475. 70,
  476. 200
  477. };
  478. /* static */ CComBSTR CAppPoolNode::_bstrStarted;
  479. /* static */ CComBSTR CAppPoolNode::_bstrStopped;
  480. /* static */ CComBSTR CAppPoolNode::_bstrUnknown;
  481. /* static */ CComBSTR CAppPoolNode::_bstrPending;
  482. /* static */ BOOL CAppPoolNode::_fStaticsLoaded = FALSE;
  483. CAppPoolNode::CAppPoolNode(
  484. CIISMachine * pOwner,
  485. CAppPoolsContainer * pContainer,
  486. LPCTSTR name,
  487. DWORD dwState
  488. )
  489. : CIISMBNode(pOwner, name),
  490. m_pContainer(pContainer),
  491. m_dwWin32Error(0),
  492. m_dwState(dwState)
  493. {
  494. }
  495. CAppPoolNode::~CAppPoolNode()
  496. {
  497. }
  498. #if 0
  499. // This is too expensive
  500. BOOL
  501. CAppPoolNode::IsDeletable() const
  502. {
  503. // We could delete node if it is empty and it is not default app pool
  504. BOOL bRes = TRUE;
  505. CComBSTR path;
  506. CStringListEx strListOfApps;
  507. BuildMetaPath(path);
  508. CIISMBNode * that = (CIISMBNode *)this;
  509. CIISAppPool pool(that->QueryAuthInfo(), (LPCTSTR)path);
  510. HRESULT hr = pool.EnumerateApplications(strListOfApps);
  511. bRes = (SUCCEEDED(hr) && strListOfApps.GetCount() == 0);
  512. if (bRes)
  513. {
  514. CString buf;
  515. hr = m_pContainer->QueryDefaultPoolId(buf);
  516. bRes = buf.CompareNoCase(QueryNodeName()) != 0;
  517. }
  518. return bRes;
  519. }
  520. #endif
  521. HRESULT
  522. CAppPoolNode::DeleteNode(IResultData * pResult)
  523. {
  524. CError err;
  525. // check if they have the property sheet open on it.
  526. if (IsMyPropertySheetOpen())
  527. {
  528. ::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET);
  529. return S_OK;
  530. }
  531. // this could be an orphaned property sheet
  532. // check if an orphaned property sheet is open on this item.
  533. CIISObject * pAlreadyOpenProp = NULL;
  534. if (TRUE == g_OpenPropertySheetTracker.FindAlreadyOpenPropertySheet(this,&pAlreadyOpenProp))
  535. {
  536. // Bring it to the foreground, and bail
  537. HWND hHwnd = 0;
  538. if (pAlreadyOpenProp)
  539. {
  540. if (hHwnd = pAlreadyOpenProp->IsMyPropertySheetOpen())
  541. {
  542. if (hHwnd && (hHwnd != (HWND) 1))
  543. {
  544. // Perhapse we should cancel the already
  545. // opened property sheet...just a thought
  546. if (!SetForegroundWindow(hHwnd))
  547. {
  548. // wasn't able to bring this property sheet to
  549. // the foreground, the propertysheet must not
  550. // exist anymore. let's just clean the hwnd
  551. // so that the user will be able to open propertysheet
  552. pAlreadyOpenProp->SetMyPropertySheetOpen(0);
  553. }
  554. else
  555. {
  556. ::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET);
  557. return S_OK;
  558. }
  559. }
  560. }
  561. }
  562. }
  563. CComBSTR path;
  564. BuildMetaPath(path);
  565. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,path);
  566. if (!IsLostInterface(err))
  567. {
  568. // reset error if an other error other than No interface
  569. err.Reset();
  570. }
  571. if (err.Succeeded())
  572. {
  573. if (!NoYesMessageBox(IDS_CONFIRM_DELETE))
  574. return err;
  575. CIISAppPool pool(QueryAuthInfo(), (LPCTSTR)path);
  576. err = pool.Delete(QueryNodeName());
  577. if (err.Succeeded())
  578. {
  579. err = RemoveScopeItem();
  580. }
  581. if (err.Win32Error() == ERROR_NOT_EMPTY)
  582. {
  583. CString msg;
  584. msg.LoadString(IDS_ERR_NONEMPTY_APPPOOL);
  585. AfxMessageBox(msg);
  586. }
  587. else
  588. {
  589. err.MessageBoxOnFailure();
  590. }
  591. }
  592. else
  593. {
  594. err.MessageBoxOnFailure();
  595. }
  596. return err;
  597. }
  598. /* virtual */
  599. HRESULT
  600. CAppPoolNode::BuildMetaPath(CComBSTR & bstrPath) const
  601. {
  602. HRESULT hr = S_OK;
  603. ASSERT(m_pContainer != NULL);
  604. hr = m_pContainer->BuildMetaPath(bstrPath);
  605. if (SUCCEEDED(hr))
  606. {
  607. bstrPath.Append(_cszSeparator);
  608. bstrPath.Append(QueryNodeName());
  609. return hr;
  610. }
  611. //
  612. // No service node
  613. //
  614. ASSERT_MSG("No pointer to container");
  615. return E_UNEXPECTED;
  616. }
  617. /* virtual */
  618. LPOLESTR
  619. CAppPoolNode::GetResultPaneColInfo(
  620. IN int nCol
  621. )
  622. /*++
  623. Routine Description:
  624. Return result pane string for the given column number
  625. Arguments:
  626. int nCol : Column number
  627. Return Value:
  628. String
  629. --*/
  630. {
  631. switch(nCol)
  632. {
  633. case COL_DESCRIPTION:
  634. return QueryDisplayName();
  635. case COL_STATE:
  636. switch(m_dwState)
  637. {
  638. case MD_APPPOOL_STATE_STARTED:
  639. return _bstrStarted;
  640. case MD_APPPOOL_STATE_STOPPED:
  641. return _bstrStopped;
  642. case MD_APPPOOL_STATE_STARTING:
  643. case MD_APPPOOL_STATE_STOPPING:
  644. return _bstrPending;
  645. default:
  646. return OLESTR("");
  647. }
  648. case COL_STATUS:
  649. {
  650. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  651. CError err(m_dwWin32Error);
  652. if (err.Succeeded())
  653. {
  654. return OLESTR("");
  655. }
  656. _bstrResult = err;
  657. }
  658. return _bstrResult;
  659. }
  660. ASSERT_MSG("Bad column number");
  661. return OLESTR("");
  662. }
  663. /* virtual */
  664. int
  665. CAppPoolNode::QueryImage() const
  666. {
  667. if (m_dwWin32Error != 0)
  668. {
  669. return iAppPoolErr;
  670. }
  671. else
  672. {
  673. if (m_dwState == MD_APPPOOL_STATE_STOPPED)
  674. {
  675. return iAppPoolStop;
  676. }
  677. else
  678. {
  679. return iAppPool;
  680. }
  681. }
  682. }
  683. /* virtual */
  684. LPOLESTR
  685. CAppPoolNode::QueryDisplayName()
  686. {
  687. if (m_strDisplayName.IsEmpty())
  688. {
  689. RefreshData();
  690. m_strDisplayName = QueryNodeName();
  691. }
  692. return (LPTSTR)(LPCTSTR)m_strDisplayName;
  693. }
  694. /* virtual */
  695. HRESULT
  696. CAppPoolNode::RefreshData()
  697. {
  698. CError err;
  699. CComBSTR bstrPath1;
  700. CMetaKey * pKey = NULL;
  701. do
  702. {
  703. err = BuildMetaPath(bstrPath1);
  704. if (err.Failed())
  705. {
  706. break;
  707. }
  708. BOOL fContinue = TRUE;
  709. while (fContinue)
  710. {
  711. fContinue = FALSE;
  712. if (NULL == (pKey = new CMetaKey(QueryInterface(), bstrPath1)))
  713. {
  714. TRACEEOLID("RefreshData: Out Of Memory");
  715. err = ERROR_NOT_ENOUGH_MEMORY;
  716. break;
  717. }
  718. err = pKey->QueryResult();
  719. if (IsLostInterface(err))
  720. {
  721. SAFE_DELETE(pKey);
  722. fContinue = OnLostInterface(err);
  723. }
  724. }
  725. if (err.Failed())
  726. {
  727. break;
  728. }
  729. CAppPoolProps pool(pKey, _T(""));
  730. err = pool.LoadData();
  731. if (err.Failed())
  732. {
  733. break;
  734. }
  735. // Assign the data
  736. m_dwState = pool.m_dwState;
  737. m_strDisplayName = QueryNodeName();
  738. m_dwWin32Error = pool.m_dwWin32Error;
  739. }
  740. while(FALSE);
  741. SAFE_DELETE(pKey);
  742. return err;
  743. }
  744. HRESULT
  745. CAppPoolNode::RefreshData(BOOL bRefreshChildren,BOOL bMyVerifyChildren)
  746. {
  747. CError err;
  748. // call regular refreshdata on this node...
  749. err = RefreshData();
  750. // -------------------------------------
  751. // Loop thru all of our children to make
  752. // sure they are all still jiving..
  753. // -------------------------------------
  754. if (bRefreshChildren)
  755. {
  756. CComBSTR bstrPath1;
  757. POSITION pos1 = NULL;
  758. CApplicationList MyMMCList;
  759. CApplicationNode * pItemFromMMC = NULL;
  760. // create a list of what is in mmc...
  761. MyMMCList.RemoveAll();
  762. HSCOPEITEM hChild = NULL, hCurrent;
  763. LONG_PTR cookie = 0;
  764. IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  765. err = pConsoleNameSpace->GetChildItem(QueryScopeItem(), &hChild, &cookie);
  766. while (err.Succeeded() && hChild != NULL)
  767. {
  768. CIISMBNode * pNode = (CIISMBNode *)cookie;
  769. if (pNode)
  770. {
  771. if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cApplicationNode))
  772. {
  773. CApplicationNode * pNode2 = (CApplicationNode *) pNode;
  774. if (pNode2)
  775. {
  776. // clean the displayname, it could have changed..
  777. // and this could be the real reason for the refresh...
  778. pNode2->QueryDisplayName(TRUE);
  779. MyMMCList.AddTail(pNode2);
  780. }
  781. }
  782. }
  783. hCurrent = hChild;
  784. err = pConsoleNameSpace->GetNextItem(hCurrent, &hChild, &cookie);
  785. }
  786. // Loop thru and see if we need to add anything
  787. CStringListEx strListOfApps;
  788. BuildMetaPath(bstrPath1);
  789. CIISAppPool pool(QueryAuthInfo(), (LPCTSTR)bstrPath1);
  790. err = pool.EnumerateApplications(strListOfApps);
  791. if (err.Succeeded() && strListOfApps.GetCount() > 0)
  792. {
  793. POSITION pos2 = NULL;
  794. DWORD iNumApp = 0;
  795. CString strAppInMetabase;
  796. CString strAppInMetabaseName;
  797. pos1 = strListOfApps.GetHeadPosition();
  798. while ( pos1 != NULL)
  799. {
  800. BOOL bExistsInUI = FALSE;
  801. strAppInMetabase = strListOfApps.GetNext(pos1);
  802. iNumApp = CMetabasePath::GetInstanceNumber(strAppInMetabase);
  803. if (iNumApp > 0)
  804. {
  805. CMetabasePath::CleanMetaPath(strAppInMetabase);
  806. CMetabasePath::GetLastNodeName(strAppInMetabase, strAppInMetabaseName);
  807. // Check if this item is in the list...
  808. // Loop through our list
  809. // and see if we need to add anything
  810. pos2 = MyMMCList.GetHeadPosition();
  811. while (pos2)
  812. {
  813. pItemFromMMC = MyMMCList.GetNext(pos2);
  814. if (pItemFromMMC)
  815. {
  816. CComBSTR bstrPath2;
  817. err = pItemFromMMC->BuildMetaPath(bstrPath2);
  818. CString csAppID = bstrPath2;
  819. CMetabasePath::CleanMetaPath(csAppID);
  820. if (0 == csAppID.CompareNoCase(strAppInMetabase))
  821. {
  822. bExistsInUI = TRUE;
  823. break;
  824. }
  825. }
  826. }
  827. if (!bExistsInUI)
  828. {
  829. TRACEEOL(strAppInMetabase << ", not exist but should, adding to UI...");
  830. CApplicationNode * app_node = new CApplicationNode(GetOwner(), strAppInMetabase, strAppInMetabaseName);
  831. if (app_node != NULL)
  832. {
  833. app_node->AddRef();
  834. app_node->AddToScopePane(m_hScopeItem, TRUE, TRUE, FALSE);
  835. }
  836. }
  837. }
  838. }
  839. }
  840. // Loop through our list and find stuff we want to delete
  841. BuildMetaPath(bstrPath1);
  842. pos1 = MyMMCList.GetHeadPosition();
  843. BOOL bMarkedForDelete = FALSE;
  844. while (pos1)
  845. {
  846. pItemFromMMC = MyMMCList.GetNext(pos1);
  847. bMarkedForDelete = FALSE;
  848. // see if it exists in the metabase,
  849. // if it doesn't then add it to the delete list...
  850. if (pItemFromMMC)
  851. {
  852. CComBSTR bstrPath3;
  853. pItemFromMMC->BuildMetaPath(bstrPath3);
  854. // check if path exists...
  855. CMetaKey mk(QueryInterface(), bstrPath3);
  856. if (!mk.Succeeded())
  857. {
  858. // delete it
  859. bMarkedForDelete = TRUE;
  860. }
  861. else
  862. {
  863. // doesn't need to be removed...
  864. // put perhase it does..
  865. // check if this Application is actually being used
  866. // by the site!
  867. if (bMyVerifyChildren)
  868. {
  869. // Lookup that website
  870. // and get it's App that it's using
  871. // see if it's the same as this AppID (BuildMetaPath(bstrPath1);)
  872. err = mk.QueryResult();
  873. if (err.Succeeded())
  874. {
  875. CString csAppID = bstrPath1;
  876. CString csAppIDName;
  877. CMetabasePath::CleanMetaPath(csAppID);
  878. CMetabasePath::GetLastNodeName(csAppID, csAppIDName);
  879. CString id;
  880. err = mk.QueryValue(MD_APP_APPPOOL_ID, id);
  881. err = mk.QueryResult();
  882. if (err.Succeeded())
  883. {
  884. if (0 != csAppIDName.CompareNoCase(id))
  885. {
  886. // the web site, isn't actually using it..
  887. // delete it
  888. bMarkedForDelete = TRUE;
  889. }
  890. }
  891. }
  892. }
  893. }
  894. if (bMarkedForDelete)
  895. {
  896. // delete it list...
  897. TRACEEOL(bstrPath3 << ", not exist, removing from UI...");
  898. // remove it from the UI
  899. pItemFromMMC->RemoveScopeItem();
  900. // delete the object
  901. pItemFromMMC->Release();
  902. }
  903. }
  904. }
  905. }
  906. return err;
  907. }
  908. /* virtual */
  909. int
  910. CAppPoolNode::CompareResultPaneItem(
  911. CIISObject * pObject,
  912. int nCol
  913. )
  914. /*++
  915. Routine Description:
  916. Compare two CIISObjects on sort item criteria
  917. Arguments:
  918. CIISObject * pObject : Object to compare against
  919. int nCol : Column number to sort on
  920. Return Value:
  921. 0 if the two objects are identical
  922. <0 if this object is less than pObject
  923. >0 if this object is greater than pObject
  924. --*/
  925. {
  926. ASSERT_READ_PTR(pObject);
  927. if (nCol == 0)
  928. {
  929. return CompareScopeItem(pObject);
  930. }
  931. //
  932. // First criteria is object type
  933. //
  934. int n1 = QuerySortWeight();
  935. int n2 = pObject->QuerySortWeight();
  936. if (n1 != n2)
  937. {
  938. return n1 - n2;
  939. }
  940. //
  941. // Both are CAppPoolNode objects
  942. //
  943. CAppPoolNode * pPool = (CAppPoolNode *)pObject;
  944. switch(nCol)
  945. {
  946. case COL_DESCRIPTION:
  947. case COL_STATE:
  948. default:
  949. //
  950. // Lexical sort
  951. //
  952. return ::lstrcmpi(
  953. GetResultPaneColInfo(nCol),
  954. pObject->GetResultPaneColInfo(nCol)
  955. );
  956. }
  957. }
  958. /* virtual */
  959. void
  960. CAppPoolNode::InitializeChildHeaders(LPHEADERCTRL lpHeader)
  961. /*++
  962. Routine Description:
  963. Build result view for immediate descendant type
  964. Arguments:
  965. LPHEADERCTRL lpHeader : Header control
  966. --*/
  967. {
  968. CApplicationNode::InitializeHeaders(lpHeader);
  969. }
  970. /* static */
  971. void
  972. CAppPoolNode::InitializeHeaders(LPHEADERCTRL lpHeader)
  973. /*++
  974. Routine Description:
  975. Initialize the result headers
  976. Arguments:
  977. LPHEADERCTRL lpHeader : Header control
  978. --*/
  979. {
  980. CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths);
  981. if (!_fStaticsLoaded)
  982. {
  983. _fStaticsLoaded =
  984. _bstrStarted.LoadString(IDS_STARTED) &&
  985. _bstrStopped.LoadString(IDS_STOPPED) &&
  986. _bstrUnknown.LoadString(IDS_UNKNOWN) &&
  987. _bstrPending.LoadString(IDS_PENDING);
  988. }
  989. }
  990. /* virtual */
  991. HRESULT
  992. CAppPoolNode::EnumerateScopePane(
  993. IN HSCOPEITEM hParent
  994. )
  995. /*++
  996. Routine Description:
  997. Enumerate scope child items.
  998. Arguments:
  999. HSCOPEITEM hParent : Parent console handle
  1000. Return Value:
  1001. HRESULT
  1002. --*/
  1003. {
  1004. CError err;
  1005. do
  1006. {
  1007. CComBSTR path;
  1008. BuildMetaPath(path);
  1009. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,path);
  1010. BREAK_ON_ERR_FAILURE(err)
  1011. CIISAppPool pool(QueryAuthInfo(), path);
  1012. if (pool.Succeeded())
  1013. {
  1014. CStringListEx strListOfApps;
  1015. err = pool.EnumerateApplications(strListOfApps);
  1016. if (err.Succeeded() && strListOfApps.GetCount() > 0)
  1017. {
  1018. POSITION pos = strListOfApps.GetHeadPosition();
  1019. while ( pos != NULL)
  1020. {
  1021. CString app = strListOfApps.GetNext(pos);
  1022. DWORD i = CMetabasePath::GetInstanceNumber(app);
  1023. if (i > 0)
  1024. {
  1025. CString name;
  1026. CMetabasePath::CleanMetaPath(app);
  1027. CMetabasePath::GetLastNodeName(app, name);
  1028. CApplicationNode * app_node = new CApplicationNode(
  1029. GetOwner(), app, name);
  1030. if (app_node != NULL)
  1031. {
  1032. app_node->AddRef();
  1033. app_node->AddToScopePane(m_hScopeItem, TRUE, TRUE, FALSE);
  1034. }
  1035. else
  1036. {
  1037. err = ERROR_NOT_ENOUGH_MEMORY;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. }
  1043. } while (FALSE);
  1044. return err;
  1045. }
  1046. /* virtual */
  1047. HRESULT
  1048. CAppPoolNode::CreatePropertyPages(
  1049. LPPROPERTYSHEETCALLBACK lpProvider,
  1050. LONG_PTR handle,
  1051. IUnknown * pUnk,
  1052. DATA_OBJECT_TYPES type
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. Create the property pages for the given object
  1057. Arguments:
  1058. LPPROPERTYSHEETCALLBACK lpProvider : Provider
  1059. LONG_PTR handle : Handle.
  1060. IUnknown * pUnk,
  1061. DATA_OBJECT_TYPES type
  1062. Return Value:
  1063. HRESULT
  1064. --*/
  1065. {
  1066. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1067. CError err;
  1068. if (S_FALSE == (HRESULT)(err = CIISMBNode::CreatePropertyPages(lpProvider, handle, pUnk, type)))
  1069. {
  1070. return S_OK;
  1071. }
  1072. if (ERROR_ALREADY_EXISTS == err.Win32Error())
  1073. {
  1074. return S_FALSE;
  1075. }
  1076. if (err.Succeeded())
  1077. {
  1078. CComBSTR path;
  1079. err = BuildMetaPath(path);
  1080. if (err.Succeeded())
  1081. {
  1082. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,path);
  1083. if (err.Succeeded())
  1084. {
  1085. CAppPoolSheet * pSheet = new CAppPoolSheet(
  1086. QueryAuthInfo(), path, GetMainWindow(GetConsole()), (LPARAM)this,
  1087. (LPARAM) m_pContainer
  1088. );
  1089. if (pSheet != NULL)
  1090. {
  1091. // cache handle for user in MMCPropertyChangeNotify
  1092. m_ppHandle = handle;
  1093. pSheet->SetModeless();
  1094. err = AddMMCPage(lpProvider, new CAppPoolRecycle(pSheet));
  1095. err = AddMMCPage(lpProvider, new CAppPoolPerf(pSheet));
  1096. err = AddMMCPage(lpProvider, new CAppPoolHealth(pSheet));
  1097. // err = AddMMCPage(lpProvider, new CAppPoolDebug(pSheet));
  1098. err = AddMMCPage(lpProvider, new CAppPoolIdent(pSheet));
  1099. // err = AddMMCPage(lpProvider, new CAppPoolCache(pSheet));
  1100. // err = AddMMCPage(lpProvider, new CPoolProcessOpt(pSheet));
  1101. }
  1102. }
  1103. }
  1104. }
  1105. err.MessageBoxOnFailure();
  1106. return err;
  1107. }
  1108. /* virtual */
  1109. HRESULT
  1110. CAppPoolNode::AddMenuItems(
  1111. IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
  1112. IN OUT long * pInsertionAllowed,
  1113. IN DATA_OBJECT_TYPES type
  1114. )
  1115. {
  1116. ASSERT_READ_PTR(lpContextMenuCallback);
  1117. //
  1118. // Add base menu items
  1119. //
  1120. HRESULT hr = CIISObject::AddMenuItems(
  1121. lpContextMenuCallback,
  1122. pInsertionAllowed,
  1123. type
  1124. );
  1125. ASSERT(pInsertionAllowed != NULL);
  1126. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) != 0)
  1127. {
  1128. AddMenuSeparator(lpContextMenuCallback);
  1129. AddMenuItemByCommand(lpContextMenuCallback, IDM_START, IsStartable() ? 0 : MF_GRAYED);
  1130. AddMenuItemByCommand(lpContextMenuCallback, IDM_STOP, IsStoppable() ? 0 : MF_GRAYED);
  1131. AddMenuItemByCommand(lpContextMenuCallback, IDM_RECYCLE, IsRunning() ? 0 : MF_GRAYED);
  1132. }
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. ASSERT(pInsertionAllowed != NULL);
  1136. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
  1137. {
  1138. AddMenuSeparator(lpContextMenuCallback);
  1139. AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL);
  1140. if (IsConfigImportExportable())
  1141. {
  1142. AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL_FROM_FILE);
  1143. }
  1144. }
  1145. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
  1146. {
  1147. if (IsConfigImportExportable())
  1148. {
  1149. AddMenuSeparator(lpContextMenuCallback);
  1150. AddMenuItemByCommand(lpContextMenuCallback, IDM_TASK_EXPORT_CONFIG_WIZARD);
  1151. }
  1152. }
  1153. }
  1154. return hr;
  1155. }
  1156. /* virtual */
  1157. HRESULT
  1158. CAppPoolNode::Command(
  1159. IN long lCommandID,
  1160. IN CSnapInObjectRootBase * pObj,
  1161. IN DATA_OBJECT_TYPES type
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Handle command from context menu.
  1166. Arguments:
  1167. long lCommandID : Command ID
  1168. CSnapInObjectRootBase * pObj : Base object
  1169. DATA_OBJECT_TYPES type : Data object type
  1170. Return Value:
  1171. HRESULT
  1172. --*/
  1173. {
  1174. HRESULT hr = S_OK;
  1175. CString name;
  1176. DWORD command = 0;
  1177. CError err;
  1178. CComBSTR bstrMetaPath;
  1179. BOOL bNeedMetabase = FALSE;
  1180. BOOL bHaveMetabase = FALSE;
  1181. switch (lCommandID)
  1182. {
  1183. case IDM_NEW_APP_POOL:
  1184. case IDM_START:
  1185. case IDM_STOP:
  1186. case IDM_RECYCLE:
  1187. bNeedMetabase = TRUE;
  1188. break;
  1189. default:
  1190. bNeedMetabase = FALSE;
  1191. }
  1192. if (bNeedMetabase)
  1193. {
  1194. // WARNING:bstrMetaPath will be used by switch statement below
  1195. VERIFY(SUCCEEDED(BuildMetaPath(bstrMetaPath)));
  1196. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
  1197. if (!IsLostInterface(err))
  1198. {
  1199. // reset error if an other error other than No interface
  1200. err.Reset();
  1201. }
  1202. if (err.Succeeded())
  1203. {
  1204. bHaveMetabase = TRUE;
  1205. }
  1206. }
  1207. switch (lCommandID)
  1208. {
  1209. case IDM_NEW_APP_POOL:
  1210. if (bHaveMetabase)
  1211. {
  1212. if (SUCCEEDED(hr = AddAppPool(pObj, type, m_pContainer, name)) && !name.IsEmpty())
  1213. {
  1214. hr = m_pContainer->InsertNewPool(name);
  1215. }
  1216. }
  1217. break;
  1218. case IDM_START:
  1219. if (bHaveMetabase)
  1220. {
  1221. command = MD_APPPOOL_COMMAND_START;
  1222. }
  1223. break;
  1224. case IDM_STOP:
  1225. if (bHaveMetabase)
  1226. {
  1227. command = MD_APPPOOL_COMMAND_STOP;
  1228. }
  1229. break;
  1230. case IDM_RECYCLE:
  1231. {
  1232. if (bHaveMetabase)
  1233. {
  1234. CIISAppPool pool(QueryAuthInfo(), (LPCTSTR)bstrMetaPath);
  1235. err = pool.Recycle(QueryNodeName());
  1236. hr = err;
  1237. }
  1238. break;
  1239. }
  1240. //
  1241. // Pass on to base class
  1242. //
  1243. default:
  1244. hr = CIISMBNode::Command(lCommandID, pObj, type);
  1245. }
  1246. if (command != 0)
  1247. {
  1248. hr = ChangeState(command);
  1249. }
  1250. return hr;
  1251. }
  1252. HRESULT
  1253. CAppPoolNode::ChangeState(DWORD dwCommand)
  1254. /*++
  1255. Routine Description:
  1256. Change the state of this instance (started/stopped/paused)
  1257. Arguments:
  1258. DWORD dwCommand : MD_SERVER_COMMAND_START, etc.
  1259. Return Value:
  1260. HRESULT
  1261. --*/
  1262. {
  1263. CError err;
  1264. CComBSTR bstrPath;
  1265. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1266. do
  1267. {
  1268. CWaitCursor wait;
  1269. err = BuildMetaPath(bstrPath);
  1270. CAppPoolProps prop(QueryAuthInfo(), bstrPath);
  1271. err = prop.LoadData();
  1272. BREAK_ON_ERR_FAILURE(err)
  1273. err = prop.ChangeState(dwCommand);
  1274. BREAK_ON_ERR_FAILURE(err)
  1275. err = RefreshData();
  1276. if (err.Succeeded())
  1277. {
  1278. err = RefreshDisplay();
  1279. }
  1280. }
  1281. while(FALSE);
  1282. err.MessageBoxOnFailure();
  1283. return err;
  1284. }
  1285. ////////////////////////////////////////////////////////////////////////
  1286. /* static */ int
  1287. CApplicationNode::_rgnLabels[COL_TOTAL] =
  1288. {
  1289. IDS_RESULT_SERVICE_DESCRIPTION,
  1290. IDS_RESULT_PATH,
  1291. };
  1292. /* static */ int
  1293. CApplicationNode::_rgnWidths[COL_TOTAL] =
  1294. {
  1295. 180,
  1296. 200,
  1297. };
  1298. /* static */
  1299. void
  1300. CApplicationNode::InitializeHeaders(LPHEADERCTRL lpHeader)
  1301. /*++
  1302. Routine Description:
  1303. Initialize the result headers
  1304. Arguments:
  1305. LPHEADERCTRL lpHeader : Header control
  1306. --*/
  1307. {
  1308. CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths);
  1309. }
  1310. LPOLESTR
  1311. CApplicationNode::QueryDisplayName()
  1312. /*++
  1313. Routine Description:
  1314. Return primary display name of this site.
  1315. Arguments:
  1316. None
  1317. Return Value:
  1318. The display name
  1319. --*/
  1320. {
  1321. return QueryDisplayName(FALSE);
  1322. }
  1323. LPOLESTR
  1324. CApplicationNode::QueryDisplayName(BOOL bForceQuery)
  1325. {
  1326. if (m_strDisplayName.IsEmpty() || bForceQuery)
  1327. {
  1328. CMetaKey mk(QueryInterface(), m_meta_path, METADATA_PERMISSION_READ);
  1329. if (mk.Succeeded())
  1330. {
  1331. mk.QueryValue(MD_APP_FRIENDLY_NAME, m_strDisplayName);
  1332. if (m_strDisplayName.IsEmpty())
  1333. {
  1334. m_strDisplayName = QueryNodeName();
  1335. }
  1336. }
  1337. }
  1338. return (LPTSTR)(LPCTSTR)m_strDisplayName;
  1339. }
  1340. HRESULT
  1341. CApplicationNode::BuildMetaPath(CComBSTR& path) const
  1342. {
  1343. path = m_meta_path;
  1344. return S_OK;
  1345. }
  1346. LPOLESTR
  1347. CApplicationNode::GetResultPaneColInfo(
  1348. IN int nCol
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. Return result pane string for the given column number
  1353. Arguments:
  1354. int nCol : Column number
  1355. Return Value:
  1356. String
  1357. --*/
  1358. {
  1359. switch(nCol)
  1360. {
  1361. case COL_ALIAS:
  1362. return QueryDisplayName();
  1363. case COL_PATH:
  1364. {
  1365. CString buf;
  1366. return (LPTSTR)(LPCTSTR)FriendlyAppRoot(m_meta_path, buf);
  1367. }
  1368. }
  1369. ASSERT_MSG("Bad column number");
  1370. return OLESTR("");
  1371. }
  1372. LPCTSTR
  1373. CApplicationNode::FriendlyAppRoot(
  1374. LPCTSTR lpAppRoot,
  1375. CString & strFriendly
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. Convert the metabase app root path to a friendly display name
  1380. format.
  1381. Arguments:
  1382. LPCTSTR lpAppRoot : App root
  1383. CString & strFriendly : Output friendly app root format
  1384. Return Value:
  1385. Reference to the output string
  1386. Notes:
  1387. App root must have been cleaned from WAM format prior
  1388. to calling this function (see first ASSERT below)
  1389. --*/
  1390. {
  1391. if (lpAppRoot != NULL && *lpAppRoot != 0)
  1392. {
  1393. //
  1394. // Make sure we cleaned up WAM format
  1395. //
  1396. ASSERT(*lpAppRoot != _T('/'));
  1397. strFriendly.Empty();
  1398. CInstanceProps prop(QueryAuthInfo(), lpAppRoot);
  1399. HRESULT hr = prop.LoadData();
  1400. if (SUCCEEDED(hr))
  1401. {
  1402. CString root, tail;
  1403. strFriendly.Format(_T("<%s>"), prop.GetDisplayText(root));
  1404. CMetabasePath::GetRootPath(lpAppRoot, root, &tail);
  1405. if (!tail.IsEmpty())
  1406. {
  1407. //
  1408. // Add rest of dir path
  1409. //
  1410. strFriendly += _T("/");
  1411. strFriendly += tail;
  1412. }
  1413. //
  1414. // Now change forward slashes in the path to backward slashes
  1415. //
  1416. // CvtPathToDosStyle(strFriendly);
  1417. return strFriendly;
  1418. }
  1419. }
  1420. //
  1421. // Bogus
  1422. //
  1423. VERIFY(strFriendly.LoadString(IDS_APPROOT_UNKNOWN));
  1424. return strFriendly;
  1425. }
  1426. //////////////////////////////////////////////////////////////////////////