|
|
/*++
Copyright (c) 1994-2000 Microsoft Corporation
Module Name : app_pools.cpp
Abstract: IIS Application Pools nodes
Author: Sergei Antonov (sergeia)
Project: Internet Services Manager
Revision History: 11/03/2000 sergeia Initial creation
--*/ #include "stdafx.h"
#include "common.h"
#include "inetprop.h"
#include "InetMgrApp.h"
#include "iisobj.h"
#include "shts.h"
#include "app_pool_sheet.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__; #endif
#define new DEBUG_NEW
CAppPoolsContainer::CAppPoolsContainer( CIISMachine * pOwner, CIISService * pService ) : CIISMBNode(pOwner, SZ_MBN_APP_POOLS), m_pWebService(pService) { VERIFY(m_bstrDisplayName.LoadString(IDS_APP_POOLS)); }
CAppPoolsContainer::~CAppPoolsContainer() { }
/* static */ int CAppPoolsContainer::_rgnLabels[COL_TOTAL] = { IDS_RESULT_SERVICE_DESCRIPTION, IDS_RESULT_SERVICE_STATE, };
/* static */ int CAppPoolsContainer::_rgnWidths[COL_TOTAL] = { 180, 70, };
/* virtual */ HRESULT CAppPoolsContainer::EnumerateScopePane(HSCOPEITEM hParent) { CError err; CMetaEnumerator * pme = NULL; CString strPool;
err = CreateEnumerator(pme); while (err.Succeeded()) { CAppPoolNode * pPool;
err = pme->Next(strPool);
if (err.Succeeded()) { TRACEEOLID("Enumerating node: " << strPool); CString key_type; CMetabasePath path(FALSE, pme->QueryMetaPath(), strPool); CMetaKey mk(pme, path); mk.QueryValue(MD_KEY_TYPE, key_type); if (mk.Succeeded() && 0 == key_type.CompareNoCase(_T("IIsApplicationPool"))) { if (NULL == (pPool = new CAppPoolNode(m_pOwner, this, strPool))) { err = ERROR_NOT_ENOUGH_MEMORY; break; } err = pPool->AddToScopePane(hParent); } } }
SAFE_DELETE(pme);
if (err.Win32Error() == ERROR_NO_MORE_ITEMS) { err.Reset(); }
if (err.Failed()) { DisplayError(err); }
SetInterfaceError(err);
return err; }
HRESULT CAppPoolsContainer::EnumerateAppPools(CPoolList * pList) { CError err; CMetaEnumerator * pme = NULL; CString strPool;
err = CreateEnumerator(pme); while (err.Succeeded()) { err = pme->Next(strPool); if (err.Succeeded()) { CString key_type; CMetabasePath path(FALSE, pme->QueryMetaPath(), strPool); CMetaKey mk(pme, path); mk.QueryValue(MD_KEY_TYPE, key_type); if (mk.Succeeded() && 0 == key_type.CompareNoCase(_T("IIsApplicationPool"))) { CAppPoolNode * pPool; if (NULL == (pPool = new CAppPoolNode(m_pOwner, this, strPool))) { err = ERROR_NOT_ENOUGH_MEMORY; break; } pList->AddTail(pPool); } } } SAFE_DELETE(pme);
if (err.Win32Error() == ERROR_NO_MORE_ITEMS) { err.Reset(); }
return err; }
/* virtual */ void CAppPoolsContainer::InitializeChildHeaders( IN LPHEADERCTRL lpHeader ) /*++
Routine Description:
Build result view for immediate descendant type
Arguments:
LPHEADERCTRL lpHeader : Header control
Return Value:
None
--*/ { CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths); }
/* virtual */ HRESULT CAppPoolsContainer::CreatePropertyPages( IN LPPROPERTYSHEETCALLBACK lpProvider, IN LONG_PTR handle, IN IUnknown * pUnk, IN DATA_OBJECT_TYPES type ) /*++
Routine Description:
Create the property pages for the given object
Arguments:
LPPROPERTYSHEETCALLBACK lpProvider : Provider LONG_PTR handle : Handle. IUnknown * pUnk, DATA_OBJECT_TYPES type
Return Value:
HRESULT --*/ { AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CError err; CComBSTR path;
err = BuildMetaPath(path); if (err.Failed()) return err;
CAppPoolSheet * pSheet = new CAppPoolSheet( QueryAuthInfo(), path, GetMainWindow(), (LPARAM)this, handle ); if (pSheet != NULL) { pSheet->SetModeless(); // err = AddMMCPage(lpProvider, new CAppPoolGeneral(pSheet));
err = AddMMCPage(lpProvider, new CAppPoolRecycle(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolPerf(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolHealth(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolDebug(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolIdent(pSheet)); }
return err; }
/* virtual */ HRESULT CAppPoolsContainer::BuildMetaPath( OUT CComBSTR & bstrPath ) const /*++
Routine Description:
Recursively build up the metabase path from the current node and its parents. We cannot use CIISMBNode method because AppPools is located under w3svc, but rendered after machine.
Arguments:
CComBSTR & bstrPath : Returns metabase path
Return Value:
HRESULT
--*/ { HRESULT hr = S_OK; ASSERT(m_pWebService != NULL); hr = m_pWebService->BuildMetaPath(bstrPath);
if (SUCCEEDED(hr)) { bstrPath.Append(_cszSeparator); bstrPath.Append(QueryNodeName()); return hr; }
//
// No service node
//
ASSERT_MSG("No WebService pointer"); return E_UNEXPECTED; }
HRESULT CAppPoolsContainer::QueryDefaultPoolId(CString& id) //
// Returns pool id which is set on master node for web service
//
{ CError err; CComBSTR path; CString service;
BuildMetaPath(path); CMetabasePath::GetServicePath(path, service); CMetaKey mk(QueryAuthInfo(), service, METADATA_PERMISSION_READ); err = mk.QueryResult(); if (err.Succeeded()) { err = mk.QueryValue(MD_APP_APPPOOL_ID, id); }
return err; }
/* virtual */ HRESULT CAppPoolsContainer::AddMenuItems( IN LPCONTEXTMENUCALLBACK lpContextMenuCallback, IN OUT long * pInsertionAllowed, IN DATA_OBJECT_TYPES type ) { ASSERT_READ_PTR(lpContextMenuCallback);
//
// Add base menu items
//
HRESULT hr = CIISObject::AddMenuItems( lpContextMenuCallback, pInsertionAllowed, type );
if (SUCCEEDED(hr)) { ASSERT(pInsertionAllowed != NULL); if (IsAdministrator() && (*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0) { AddMenuSeparator(lpContextMenuCallback); AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL); } }
return hr; }
HRESULT CAppPoolsContainer::Command( long lCommandID, CSnapInObjectRootBase * pObj, DATA_OBJECT_TYPES type ) { HRESULT hr = S_OK; CString name;
switch (lCommandID) { case IDM_NEW_APP_POOL: if ( SUCCEEDED(hr = AddAppPool(pObj, type, this, name)) && !name.IsEmpty() ) { hr = InsertNewPool(name); } break;
//
// Pass on to base class
//
default: hr = CIISMBNode::Command(lCommandID, pObj, type); }
return hr; }
HRESULT CAppPoolsContainer::InsertNewPool(CString& id) { CError err; // Now we should insert and select this new site
CAppPoolNode * pPool = new CAppPoolNode(m_pOwner, this, id); if (pPool != NULL) { err = pPool->RefreshData(); if (err.Succeeded()) { // If item is not expanded we will get error and no effect
if (!IsExpanded()) { SelectScopeItem(); IConsoleNameSpace2 * pConsole = (IConsoleNameSpace2 *)GetConsoleNameSpace(); pConsole->Expand(QueryScopeItem()); } err = pPool->AddToScopePaneSorted(QueryScopeItem(), FALSE); if (err.Succeeded()) { VERIFY(SUCCEEDED(pPool->SelectScopeItem())); } } } else { err = ERROR_NOT_ENOUGH_MEMORY; } return err; }
////////////////////////////////////////////////////////////////////////////////
// CAppPoolNode implementation
//
// App Pool Result View definition
//
/* static */ int CAppPoolNode::_rgnLabels[COL_TOTAL] = { IDS_RESULT_SERVICE_DESCRIPTION, IDS_RESULT_PATH, };
/* static */ int CAppPoolNode::_rgnWidths[COL_TOTAL] = { 180, 200, };
CAppPoolNode::CAppPoolNode( CIISMachine * pOwner, CAppPoolsContainer * pContainer, LPCTSTR name ) : CIISMBNode(pOwner, name), m_pContainer(pContainer) { }
CAppPoolNode::~CAppPoolNode() { }
#if 0
// This is too expensive
BOOL CAppPoolNode::IsDeletable() const { // We could delete node if it is empty and it is not default app pool
BOOL bRes = TRUE;
CComBSTR path; CStringListEx apps; BuildMetaPath(path); CIISMBNode * that = (CIISMBNode *)this; CIISAppPool pool(that->QueryAuthInfo(), (LPCTSTR)path); HRESULT hr = pool.EnumerateApplications(apps); bRes = (SUCCEEDED(hr) && apps.GetCount() == 0); if (bRes) { CString buf; hr = m_pContainer->QueryDefaultPoolId(buf); bRes = buf.CompareNoCase(QueryNodeName()) != 0; } return bRes; } #endif
HRESULT CAppPoolNode::DeleteNode(IResultData * pResult) { CError err; CComBSTR path; BuildMetaPath(path); CIISAppPool pool(QueryAuthInfo(), (LPCTSTR)path);
err = pool.Delete(GetNodeName());
if (err.Succeeded()) { err = RemoveScopeItem(); } if (err.Win32Error() == ERROR_NOT_EMPTY) { CString msg; msg.LoadString(IDS_ERR_NONEMPTY_APPPOOL); AfxMessageBox(msg); } else { err.MessageBoxOnFailure(); }
return err; }
/* virtual */ HRESULT CAppPoolNode::BuildMetaPath(CComBSTR & bstrPath) const { HRESULT hr = S_OK; ASSERT(m_pContainer != NULL); hr = m_pContainer->BuildMetaPath(bstrPath);
if (SUCCEEDED(hr)) { bstrPath.Append(_cszSeparator); bstrPath.Append(QueryNodeName()); return hr; }
//
// No service node
//
ASSERT_MSG("No pointer to container"); return E_UNEXPECTED; }
/* virtual */ LPOLESTR CAppPoolNode::GetResultPaneColInfo( IN int nCol ) /*++
Routine Description:
Return result pane string for the given column number
Arguments:
int nCol : Column number
Return Value:
String
--*/ { switch(nCol) { case COL_DESCRIPTION: return QueryDisplayName();
case COL_STATE: return OLESTR(""); }
ASSERT_MSG("Bad column number");
return OLESTR(""); }
/* virtual */ int CAppPoolNode::QueryImage() const /*++
Routine Description:
Return bitmap index for the site
Arguments:
None
Return Value:
Bitmap index
--*/ { return iFolder; }
/* virtual */ LPOLESTR CAppPoolNode::QueryDisplayName() /*++
Routine Description:
Return primary display name of this site. Arguments:
None
Return Value:
The display name
--*/ { if (m_strDisplayName.IsEmpty()) { CComBSTR path; BuildMetaPath(path); CMetaKey mk(QueryInterface(), path); if (mk.Succeeded()) { mk.QueryValue(MD_APPPOOL_FRIENDLY_NAME, m_strDisplayName); } } return (LPTSTR)(LPCTSTR)m_strDisplayName; }
/*virtual*/ HRESULT CAppPoolNode::RenameItem(LPOLESTR new_name) { CComBSTR path; CError err; if (new_name != NULL && lstrlen(new_name) > 0) { BuildMetaPath(path);
CMetaKey mk(QueryInterface(), path, METADATA_PERMISSION_WRITE);
CError err(mk.QueryResult()); if (err.Succeeded()) { err = mk.SetValue(MD_APPPOOL_FRIENDLY_NAME, CString(new_name)); if (err.Succeeded()) { m_strDisplayName = new_name; } } } return err; }
/* virtual */ HRESULT CAppPoolNode::RefreshData() /*++
Routine Description:
Refresh relevant configuration data required for display.
Arguments:
None
Return Value:
HRESULT
--*/ { CError err; // CWaitCursor wait;
CComBSTR path; CMetaKey * pKey = NULL;
do { ASSERT_PTR(_lpConsoleNameSpace); err = BuildMetaPath(path); if (err.Failed()) { break; }
BOOL fContinue = TRUE;
while (fContinue) { fContinue = FALSE; if (NULL == (pKey = new CMetaKey(QueryInterface(), path))) { TRACEEOLID("RefreshData: Out Of Memory"); err = ERROR_NOT_ENOUGH_MEMORY; break; }
err = pKey->QueryResult();
if (IsLostInterface(err)) { SAFE_DELETE(pKey); fContinue = OnLostInterface(err); } }
if (err.Failed()) { break; }
CAppPoolProps pool(pKey, _T(""));
err = pool.LoadData(); if (err.Failed()) { break; } // Assign the data
} while(FALSE);
SAFE_DELETE(pKey);
return err; }
/* virtual */ int CAppPoolNode::CompareResultPaneItem( IN CIISObject * pObject, IN int nCol ) /*++
Routine Description:
Compare two CIISObjects on sort item criteria
Arguments:
CIISObject * pObject : Object to compare against int nCol : Column number to sort on
Return Value:
0 if the two objects are identical <0 if this object is less than pObject >0 if this object is greater than pObject
--*/ { ASSERT_READ_PTR(pObject);
if (nCol == 0) { return CompareScopeItem(pObject); }
//
// First criteria is object type
//
int n1 = QuerySortWeight(); int n2 = pObject->QuerySortWeight();
if (n1 != n2) { return n1 - n2; }
//
// Both are CAppPoolNode objects
//
CAppPoolNode * pPool = (CAppPoolNode *)pObject;
switch(nCol) { case COL_DESCRIPTION: case COL_STATE: default: //
// Lexical sort
//
return ::lstrcmpi( GetResultPaneColInfo(nCol), pObject->GetResultPaneColInfo(nCol) ); } }
/* virtual */ void CAppPoolNode::InitializeChildHeaders( IN LPHEADERCTRL lpHeader ) /*++
Routine Description:
Build result view for immediate descendant type
Arguments:
LPHEADERCTRL lpHeader : Header control
Return Value:
None
--*/ { CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths); }
/* virtual */ HRESULT CAppPoolNode::EnumerateScopePane( IN HSCOPEITEM hParent ) /*++
Routine Description:
Enumerate scope child items.
Arguments:
HSCOPEITEM hParent : Parent console handle
Return Value:
HRESULT
--*/ { HRESULT hr = S_OK; CComBSTR path; BuildMetaPath(path); CIISAppPool pool(QueryAuthInfo(), path);
if (pool.Succeeded()) { CStringListEx apps;
hr = pool.EnumerateApplications(apps); if (SUCCEEDED(hr) && apps.GetCount() > 0) { POSITION pos = apps.GetHeadPosition(); while ( pos != NULL) { CString app = apps.GetNext(pos); DWORD i = CMetabasePath::GetInstanceNumber(app); if (i > 0) { CString name; CMetabasePath::CleanMetaPath(app); CMetabasePath::GetLastNodeName(app, name); CApplicationNode * app_node = new CApplicationNode( GetOwner(), app, name); if (app_node != NULL) { app_node->AddToScopePane(m_hScopeItem, TRUE, TRUE, FALSE); } else hr = ERROR_NOT_ENOUGH_MEMORY; } } } }
return hr; }
/* virtual */ HRESULT CAppPoolNode::CreatePropertyPages( IN LPPROPERTYSHEETCALLBACK lpProvider, IN LONG_PTR handle, IN IUnknown * pUnk, IN DATA_OBJECT_TYPES type ) /*++
Routine Description:
Create the property pages for the given object
Arguments:
LPPROPERTYSHEETCALLBACK lpProvider : Provider LONG_PTR handle : Handle. IUnknown * pUnk, DATA_OBJECT_TYPES type
Return Value:
HRESULT --*/ { AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CComBSTR path;
CError err(BuildMetaPath(path));
if (err.Succeeded()) { CAppPoolSheet * pSheet = new CAppPoolSheet( QueryAuthInfo(), path, GetMainWindow(), (LPARAM)this, handle ); if (pSheet != NULL) { pSheet->SetModeless(); // err = AddMMCPage(lpProvider, new CAppPoolGeneral(pSheet));
err = AddMMCPage(lpProvider, new CAppPoolRecycle(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolPerf(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolHealth(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolDebug(pSheet)); err = AddMMCPage(lpProvider, new CAppPoolIdent(pSheet)); } }
err.MessageBoxOnFailure();
return err; }
/* virtual */ HRESULT CAppPoolNode::AddMenuItems( IN LPCONTEXTMENUCALLBACK lpContextMenuCallback, IN OUT long * pInsertionAllowed, IN DATA_OBJECT_TYPES type ) { ASSERT_READ_PTR(lpContextMenuCallback);
//
// Add base menu items
//
HRESULT hr = CIISObject::AddMenuItems( lpContextMenuCallback, pInsertionAllowed, type );
if (SUCCEEDED(hr)) { ASSERT(pInsertionAllowed != NULL); if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0) { AddMenuSeparator(lpContextMenuCallback); AddMenuItemByCommand(lpContextMenuCallback, IDM_NEW_APP_POOL); } }
return hr; }
/* virtual */ HRESULT CAppPoolNode::Command( IN long lCommandID, IN CSnapInObjectRootBase * pObj, IN DATA_OBJECT_TYPES type ) /*++
Routine Description:
Handle command from context menu.
Arguments:
long lCommandID : Command ID CSnapInObjectRootBase * pObj : Base object DATA_OBJECT_TYPES type : Data object type
Return Value:
HRESULT
--*/ { HRESULT hr = S_OK; CString name;
switch (lCommandID) { case IDM_NEW_APP_POOL: if ( SUCCEEDED(hr = AddAppPool(pObj, type, m_pContainer, name)) && !name.IsEmpty() ) { hr = m_pContainer->InsertNewPool(name); } break;
//
// Pass on to base class
//
default: hr = CIISMBNode::Command(lCommandID, pObj, type); }
return hr; }
////////////////////////////////////////////////////////////////////////
LPOLESTR CApplicationNode::QueryDisplayName() /*++
Routine Description:
Return primary display name of this site. Arguments:
None
Return Value:
The display name
--*/ { if (m_strDisplayName.IsEmpty()) { CMetaKey mk(QueryInterface(), m_meta_path); if (mk.Succeeded()) { mk.QueryValue(MD_APP_FRIENDLY_NAME, m_strDisplayName); if (m_strDisplayName.IsEmpty()) { m_strDisplayName = QueryNodeName(); } } } return (LPTSTR)(LPCTSTR)m_strDisplayName; }
HRESULT CApplicationNode::BuildMetaPath(CComBSTR& path) const { path = m_meta_path; return S_OK; }
LPOLESTR CApplicationNode::GetResultPaneColInfo( IN int nCol ) /*++
Routine Description:
Return result pane string for the given column number
Arguments:
int nCol : Column number
Return Value:
String
--*/ { switch(nCol) { case COL_ALIAS: return QueryDisplayName();
case COL_PATH: { CString buf; return (LPTSTR)(LPCTSTR)FriendlyAppRoot(m_meta_path, buf); } }
ASSERT_MSG("Bad column number");
return OLESTR(""); }
LPCTSTR CApplicationNode::FriendlyAppRoot( LPCTSTR lpAppRoot, CString & strFriendly ) /*++
Routine Description:
Convert the metabase app root path to a friendly display name format.
Arguments:
LPCTSTR lpAppRoot : App root CString & strFriendly : Output friendly app root format
Return Value:
Reference to the output string
Notes:
App root must have been cleaned from WAM format prior to calling this function (see first ASSERT below)
--*/ { if (lpAppRoot != NULL && *lpAppRoot != 0) { //
// Make sure we cleaned up WAM format
//
ASSERT(*lpAppRoot != _T('/')); strFriendly.Empty();
CInstanceProps prop(QueryAuthInfo(), lpAppRoot); HRESULT hr = prop.LoadData();
if (SUCCEEDED(hr)) { CString root, tail; strFriendly.Format(_T("<%s>"), prop.GetDisplayText(root)); CMetabasePath::GetRootPath(lpAppRoot, root, &tail); if (!tail.IsEmpty()) { //
// Add rest of dir path
//
strFriendly += _T("/"); strFriendly += tail; }
//
// Now change forward slashes in the path to backward slashes
//
// CvtPathToDosStyle(strFriendly);
return strFriendly; } } //
// Bogus
//
VERIFY(strFriendly.LoadString(IDS_APPROOT_UNKNOWN));
return strFriendly; } //////////////////////////////////////////////////////////////////////////
|