windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/snapin/app_pools.cpp
2020-09-26 16:20:57 +08:00

1125 lines
22 KiB
C++

/*++
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;
}
//////////////////////////////////////////////////////////////////////////