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

1215 lines
24 KiB
C++

/*++
Copyright (c) 1994-2001 Microsoft Corporation
Module Name :
iissite.cpp
Abstract:
IIS Site Object
Author:
Ronald Meijer (ronaldm)
Sergei Antonov (sergeia)
Project:
Internet Services Manager
Revision History:
10/28/2000 sergeia Split from iisobj.cpp
--*/
#include "stdafx.h"
#include "common.h"
#include "inetprop.h"
#include "InetMgrApp.h"
#include "iisobj.h"
#include "machsht.h"
#include "errors.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
//
// CIISSite implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//
// Site Result View definition
//
/* static */ int
CIISSite::_rgnLabels[COL_TOTAL] =
{
IDS_RESULT_SERVICE_DESCRIPTION,
IDS_RESULT_SERVICE_STATE,
IDS_RESULT_SERVICE_DOMAIN_NAME,
IDS_RESULT_SERVICE_IP_ADDRESS,
IDS_RESULT_SERVICE_TCP_PORT,
IDS_RESULT_STATUS,
};
/* static */ int
CIISSite::_rgnWidths[COL_TOTAL] =
{
180,
70,
120,
105,
40,
200,
};
/* static */ CComBSTR CIISSite::_bstrStarted;
/* static */ CComBSTR CIISSite::_bstrStopped;
/* static */ CComBSTR CIISSite::_bstrPaused;
/* static */ CComBSTR CIISSite::_bstrUnknown;
/* static */ CComBSTR CIISSite::_bstrPending;
/* static */ CComBSTR CIISSite::_bstrAllUnassigned;
/* static */ BOOL CIISSite::_fStaticsLoaded = FALSE;
/* static */
void
CIISSite::InitializeHeaders(LPHEADERCTRL lpHeader)
/*++
Routine Description:
Initialize the result headers
Arguments:
LPHEADERCTRL lpHeader : Header control
Return Value:
None
--*/
{
CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths);
// CIISDirectory::InitializeHeaders(lpHeader);
if (!_fStaticsLoaded)
{
_fStaticsLoaded =
_bstrStarted.LoadString(IDS_STARTED) &&
_bstrStopped.LoadString(IDS_STOPPED) &&
_bstrPaused.LoadString(IDS_PAUSED) &&
_bstrUnknown.LoadString(IDS_UNKNOWN) &&
_bstrPending.LoadString(IDS_PENDING) &&
_bstrAllUnassigned.LoadString(IDS_IP_ALL_UNASSIGNED);
}
}
/* virtual */
void
CIISSite::InitializeChildHeaders(
IN LPHEADERCTRL lpHeader
)
/*++
Routine Description:
Build result view for immediate descendant type
Arguments:
LPHEADERCTRL lpHeader : Header control
Return Value:
None
--*/
{
CIISDirectory::InitializeHeaders(lpHeader);
}
CIISSite::CIISSite(
IN CIISMachine * pOwner,
IN CIISService * pService,
IN LPCTSTR szNodeName
)
/*++
Routine Description:
Constructor. Determine if the given service is administrable,
and resolve the details
Arguments:
CIISMachine * pOwner : Owner machine object
CIISService * pService : Service type
LPCTSTR szNodeName : Node name (numeric)
Return Value:
N/A
Notes:
This constructor does not immediately resolve the display name of the
site. It will only resolve its display information when asked
--*/
: CIISMBNode(pOwner, szNodeName),
m_pService(pService),
m_fResolved(FALSE),
m_strDisplayName(),
//
// Data members -- plonk in some defaults
//
m_dwState(MD_SERVER_STATE_INVALID),
m_fDeletable(FALSE),
m_fWolfPackEnabled(FALSE),
m_fFrontPageWeb(FALSE),
m_sPort(80),
m_dwID(::_ttol(szNodeName)),
m_dwIPAddress(0L),
m_dwWin32Error(ERROR_SUCCESS),
m_bstrHostHeaderName(),
m_bstrComment()
{
ASSERT_PTR(m_pService);
}
CIISSite::CIISSite(
IN CIISMachine * pOwner,
IN CIISService * pService,
IN LPCTSTR szNodeName,
IN DWORD dwState,
IN BOOL fDeletable,
IN BOOL fClusterEnabled,
IN USHORT sPort,
IN DWORD dwID,
IN DWORD dwIPAddress,
IN DWORD dwWin32Error,
IN LPOLESTR szHostHeaderName,
IN LPOLESTR szComment
)
/*++
Routine Description:
Construct with full information
Arguments:
CIISMachine * pOwner : Owner machine object
CIISService * pService : Service type
LPCTSTR szNodeName : Node name (numeric)
plus datamembers
Return Value:
N/A
--*/
: CIISMBNode(pOwner, szNodeName),
m_pService(pService),
m_fResolved(TRUE),
m_strDisplayName(),
//
// Data Members
//
m_dwState(dwState),
m_fDeletable(fDeletable),
m_fWolfPackEnabled(fClusterEnabled),
m_sPort(sPort),
m_dwID(dwID),
m_dwIPAddress(dwIPAddress),
m_dwWin32Error(dwWin32Error),
m_bstrHostHeaderName(szHostHeaderName),
m_bstrComment(szComment)
{
ASSERT_PTR(m_pService);
}
CIISSite::~CIISSite()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
}
/* virtual */
HRESULT
CIISSite::RefreshData()
/*++
Routine Description:
Refresh relevant configuration data required for display.
Arguments:
None
Return Value:
HRESULT
--*/
{
CError err;
CWaitCursor wait;
CComBSTR bstrPath;
CMetaKey * pKey = NULL;
do
{
ASSERT_PTR(_lpConsoleNameSpace);
err = BuildMetaPath(bstrPath);
BREAK_ON_ERR_FAILURE(err);
// We need instance key here
CString path_inst;
CMetabasePath::GetInstancePath(bstrPath, path_inst);
BOOL fContinue = TRUE;
while (fContinue)
{
fContinue = FALSE;
if (NULL == (pKey = new CMetaKey(QueryInterface(), path_inst)))
{
TRACEEOLID("RefreshData: OOM");
err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
err = pKey->QueryResult();
if (IsLostInterface(err))
{
SAFE_DELETE(pKey);
fContinue = OnLostInterface(err);
}
}
BREAK_ON_ERR_FAILURE(err);
CInstanceProps inst(pKey, _T(""), m_dwID);
err = inst.LoadData();
BREAK_ON_ERR_FAILURE(err);
m_dwState = inst.m_dwState;
m_fDeletable = !inst.m_fNotDeletable;
//
// Don't be confused -- cluster enabled refers
// to wolfpack and has nothing to do with app server
//
m_fWolfPackEnabled = inst.IsClusterEnabled();
m_sPort = (SHORT)inst.m_nTCPPort;
m_dwID = inst.QueryInstance();
m_dwIPAddress = inst.m_iaIpAddress;
m_dwWin32Error = inst.m_dwWin32Error;
m_bstrHostHeaderName = inst.m_strDomainName;
m_bstrComment = inst.m_strComment;
m_strDisplayName.Empty();
// Check if it is Frontpage controlled site
pKey->QueryValue(MD_FRONTPAGE_WEB, m_fFrontPageWeb);
CChildNodeProps child(pKey, SZ_MBN_ROOT);
err = child.LoadData();
BREAK_ON_ERR_FAILURE(err);
m_strRedirectPath = child.GetRedirectedPath();
}
while(FALSE);
SAFE_DELETE(pKey);
if (m_dwWin32Error == ERROR_SUCCESS)
{
m_dwWin32Error = err.Win32Error();
}
return err;
}
/* virtual */
int
CIISSite::QueryImage() const
/*++
Routine Description:
Return bitmap index for the site
Arguments:
None
Return Value:
Bitmap index
--*/
{
ASSERT_PTR(m_pService);
if (!m_fResolved)
{
TRACEEOLID("Resolving name for site #" << QueryNodeName());
if (m_hScopeItem == NULL)
{
//
// BUGBUG:
//
// This is probably related to MMC bug #324519
// where we're asked for the display info immediately
// after adding the item to the console view. This
// appears to fail only on refresh because the scope
// item handle is missing, and we can't build a metabase
// path yet.
//
TRACEEOLID("BUGBUG: Prematurely asked for display information");
//ASSERT(FALSE);
return iError;
}
CIISSite * that = (CIISSite *)this;
CError err = that->RefreshData();
that->m_fResolved = err.Succeeded();
}
return !m_dwWin32Error && m_pService ? m_pService->QuerySiteImage() : iError;
}
/* virtual */
LPOLESTR
CIISSite::QueryDisplayName()
/*++
Routine Description:
Return primary display name of this site.
Arguments:
None
Return Value:
The display name
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
if (!m_fResolved)
{
TRACEEOLID("Resolving name for site #" << QueryNodeName());
if (m_hScopeItem == NULL)
{
//
// BUGBUG:
//
// This is probably related to MMC bug #324519
// where we're asked for the display info immediately
// after adding the item to the console view. This
// appears to fail only on refresh because the scope
// item handle is missing, and we can't build a metabase
// path yet.
//
TRACEEOLID("BUGBUG: Prematurely asked for display information");
//ASSERT(FALSE);
return OLESTR("");
}
CError err = RefreshData();
m_fResolved = err.Succeeded();
}
if (m_strDisplayName.IsEmpty())
{
CIPAddress ia(m_dwIPAddress);
CInstanceProps::GetDisplayText(
m_strDisplayName,
m_bstrComment,
m_bstrHostHeaderName,
ia,
m_sPort,
m_dwID
);
}
CString buf = m_strDisplayName;
if (m_dwState == MD_SERVER_STATE_STOPPED)
{
buf.Format(IDS_STOPPED_SITE_FMT, m_strDisplayName);
}
else if (m_dwState == MD_SERVER_STATE_PAUSED)
{
buf.Format(IDS_PAUSED_SITE_FMT, m_strDisplayName);
}
m_bstrDisplayNameStatus = buf;
// return (LPTSTR)(LPCTSTR)m_strDisplayName;
return m_bstrDisplayNameStatus;
}
/* virtual */
LPOLESTR
CIISSite::GetResultPaneColInfo(int nCol)
/*++
Routine Description:
Return result pane string for the given column number
Arguments:
int nCol : Column number
Return Value:
String
--*/
{
ASSERT(_fStaticsLoaded);
TCHAR sz[255];
switch(nCol)
{
case COL_DESCRIPTION:
return QueryDisplayName();
case COL_STATE:
switch(m_dwState)
{
case MD_SERVER_STATE_STARTED:
return _bstrStarted;
case MD_SERVER_STATE_PAUSED:
return _bstrPaused;
case MD_SERVER_STATE_STOPPED:
return _bstrStopped;
case MD_SERVER_STATE_STARTING:
case MD_SERVER_STATE_PAUSING:
case MD_SERVER_STATE_CONTINUING:
case MD_SERVER_STATE_STOPPING:
return _bstrPending;
}
return OLESTR("");
case COL_DOMAIN_NAME:
return m_bstrHostHeaderName;
case COL_IP_ADDRESS:
{
CIPAddress ia(m_dwIPAddress);
if (ia.IsZeroValue())
{
_bstrResult = _bstrAllUnassigned;
}
else
{
_bstrResult = ia;
}
}
return _bstrResult;
case COL_TCP_PORT:
_bstrResult = ::_itot(m_sPort, sz, 10);
return _bstrResult;
case COL_STATUS:
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CError err(m_dwWin32Error);
if (err.Succeeded())
{
return OLESTR("");
}
_bstrResult = err;
}
return _bstrResult;
}
ASSERT_MSG("Bad column number");
return OLESTR("");
}
/* virtual */
int
CIISSite::CompareResultPaneItem(CIISObject * pObject, 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 CIISSite objects
//
CIISSite * pSite = (CIISSite *)pObject;
switch(nCol)
{
//
// Special case columns
//
case COL_IP_ADDRESS:
{
CIPAddress ia1(m_dwIPAddress);
CIPAddress ia2(pSite->QueryIPAddress());
return ia1.CompareItem(ia2);
}
case COL_TCP_PORT:
n1 = QueryPort();
n2 = pSite->QueryPort();
return n1 - n2;
case COL_STATUS:
{
DWORD dw1 = QueryWin32Error();
DWORD dw2 = pSite->QueryWin32Error();
return dw1 - dw2;
}
case COL_DESCRIPTION:
case COL_STATE:
case COL_DOMAIN_NAME:
default:
//
// Lexical sort
//
return ::lstrcmpi(
GetResultPaneColInfo(nCol),
pObject->GetResultPaneColInfo(nCol)
);
}
}
/* virtual */
HRESULT
CIISSite::BuildURL(CComBSTR & bstrURL) const
/*++
Routine Description:
Recursively build up the URL from the current node
and its parents. For a site node, add the machine name.
Arguments:
CComBSTR & bstrURL : Returns URL
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
//
// Prepend parent portion (protocol in this case)
//
CIISMBNode * pNode = GetParentNode();
if (pNode)
{
hr = pNode->BuildURL(bstrURL);
}
if (SUCCEEDED(hr))
{
CString strOwner;
///////////////////////////////////////////////////////////////////////////
//
// Try to build an URL. Use in order of priority:
//
// Domain name:port/root
// ip address:port/root
// computer name:port/root
//
if (m_bstrHostHeaderName.Length())
{
strOwner = m_bstrHostHeaderName;
}
else if (m_dwIPAddress != 0L)
{
CIPAddress ia(m_dwIPAddress);
ia.QueryIPAddress(strOwner);
}
else
{
if (IsLocal())
{
//
// Security reasons restrict this to "localhost" oftentimes
//
strOwner = _bstrLocalHost;
}
else
{
LPOLESTR lpOwner = QueryMachineName();
strOwner = PURE_COMPUTER_NAME(lpOwner);
}
}
TCHAR szPort[6]; // 65536 max.
_itot(m_sPort, szPort, 10);
strOwner += _T(":");
strOwner += szPort;
bstrURL.Append(strOwner);
}
return hr;
}
/*virtual*/
HRESULT
CIISSite::AddMenuItems(
LPCONTEXTMENUCALLBACK piCallback,
long * pInsertionAllowed,
DATA_OBJECT_TYPES type
)
{
ASSERT_READ_PTR(piCallback);
//
// Add base menu items
//
HRESULT hr = CIISObject::AddMenuItems(
piCallback,
pInsertionAllowed,
type
);
if (SUCCEEDED(hr))
{
ASSERT(pInsertionAllowed != NULL);
if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
{
AddMenuSeparator(piCallback);
if (IsFtpSite())
{
if (GetOwner()->CanAddInstance() && !GetOwner()->Has10ConnectionsLimit())
{
AddMenuItemByCommand(piCallback, IDM_NEW_FTP_SITE);
}
AddMenuItemByCommand(piCallback, IDM_NEW_FTP_VDIR);
}
else if (IsWebSite())
{
if (GetOwner()->CanAddInstance() && !GetOwner()->Has10ConnectionsLimit())
{
AddMenuItemByCommand(piCallback, IDM_NEW_WEB_SITE);
}
AddMenuItemByCommand(piCallback, IDM_NEW_WEB_VDIR);
}
}
if (!m_fFrontPageWeb && (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
{
AddMenuSeparator(piCallback);
AddMenuItemByCommand(piCallback, IDM_TASK_SECURITY_WIZARD);
}
}
return hr;
}
HRESULT
CIISSite::InsertNewInstance(DWORD inst)
{
return m_pService->InsertNewInstance(inst);
}
HRESULT
CIISSite::InsertNewAlias(CString alias)
{
CError err;
// Now we should insert and select this new site
CIISDirectory * pAlias = new CIISDirectory(m_pOwner, m_pService, alias);
if (pAlias != NULL)
{
// If item is not expanded we will get error and no effect
if (!IsExpanded())
{
SelectScopeItem();
IConsoleNameSpace2 * pConsole
= (IConsoleNameSpace2 *)GetConsoleNameSpace();
pConsole->Expand(QueryScopeItem());
}
err = pAlias->AddToScopePaneSorted(QueryScopeItem(), FALSE);
if (err.Succeeded())
{
VERIFY(SUCCEEDED(pAlias->SelectScopeItem()));
}
}
else
{
err = ERROR_NOT_ENOUGH_MEMORY;
}
return err;
}
/* virtual */
HRESULT
CIISSite::Command(
long lCommandID,
CSnapInObjectRootBase * pObj,
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
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
HRESULT hr = S_OK;
DWORD dwCommand = 0;
DWORD inst;
CString alias;
switch (lCommandID)
{
case IDM_STOP:
dwCommand = MD_SERVER_COMMAND_STOP;
break;
case IDM_START:
dwCommand = m_dwState == MD_SERVER_STATE_PAUSED ?
MD_SERVER_COMMAND_CONTINUE : MD_SERVER_COMMAND_START;
break;
case IDM_PAUSE:
dwCommand = m_dwState == MD_SERVER_STATE_PAUSED ?
MD_SERVER_COMMAND_CONTINUE : MD_SERVER_COMMAND_PAUSE;
break;
case IDM_NEW_FTP_SITE:
if (SUCCEEDED(hr = AddFTPSite(pObj, type, &inst)))
{
hr = InsertNewInstance(inst);
}
break;
case IDM_NEW_FTP_VDIR:
if (SUCCEEDED(hr = CIISMBNode::AddFTPVDir(pObj, type, alias)))
{
hr = InsertNewAlias(alias);
}
break;
case IDM_NEW_WEB_SITE:
if (SUCCEEDED(hr = CIISMBNode::AddWebSite(pObj, type, &inst)))
{
hr = InsertNewInstance(inst);
}
break;
case IDM_NEW_WEB_VDIR:
if (SUCCEEDED(hr = CIISMBNode::AddWebVDir(pObj, type, alias)))
{
hr = InsertNewAlias(alias);
}
break;
//
// Pass on to base class
//
default:
hr = CIISMBNode::Command(lCommandID, pObj, type);
}
if (dwCommand)
{
hr = ChangeState(dwCommand);
}
return hr;
}
/* virtual */
HRESULT
CIISSite::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 bstrPath;
//
// CODEWORK: What to do with m_err? This might be
// a bad machine object in the first place. Aborting
// when the machine object has an error code isn't
// such a bad solution here.
//
/*
if (m_err.Failed())
{
m_err.MessageBox();
return m_err;
}
*/
CError err(BuildMetaPath(bstrPath));
if (err.Succeeded())
{
err = ShowPropertiesDlg(
lpProvider,
QueryAuthInfo(),
bstrPath,
GetMainWindow(),
(LPARAM)this,
handle
);
}
err.MessageBoxOnFailure();
return err;
}
HRESULT
CIISSite::ChangeState(DWORD dwCommand)
/*++
Routine Description:
Change the state of this instance (started/stopped/paused)
Arguments:
DWORD dwCommand : MD_SERVER_COMMAND_START, etc.
Return Value:
HRESULT
--*/
{
CError err;
CComBSTR bstrPath;
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
do
{
CWaitCursor wait;
err = BuildMetaPath(bstrPath);
// We need instance key here
CString path_inst;
CMetabasePath::GetInstancePath(bstrPath, path_inst);
BREAK_ON_ERR_FAILURE(err)
CInstanceProps ip(QueryAuthInfo(), path_inst);
err = ip.LoadData();
BREAK_ON_ERR_FAILURE(err)
err = ip.ChangeState(dwCommand);
BREAK_ON_ERR_FAILURE(err)
err = RefreshData();
if (err.Succeeded())
{
err = RefreshDisplay();
}
}
while(FALSE);
err.MessageBoxOnFailure();
return err;
}
/* virtual */
HRESULT
CIISSite::EnumerateScopePane(HSCOPEITEM hParent)
/*++
Routine Description:
Enumerate scope child items.
Arguments:
HSCOPEITEM hParent : Parent console handle
Return Value:
HRESULT
--*/
{
CError err = EnumerateVDirs(hParent, m_pService);
if (err.Succeeded() && !IsFtpSite() && m_strRedirectPath.IsEmpty())
{
if (m_dwWin32Error == ERROR_SUCCESS)
{
err = EnumerateWebDirs(hParent, m_pService);
}
}
if (err.Failed())
{
m_dwWin32Error = err.Win32Error();
RefreshDisplay();
}
return err;
}
/*virtual*/
HRESULT
CIISSite::EnumerateResultPane(BOOL fExp, IHeaderCtrl * pHdr, IResultData * pResData)
{
CError err = CIISObject::EnumerateResultPane(fExp, pHdr, pResData);
if ( err.Succeeded()
&& QueryWin32Error() == ERROR_SUCCESS
&& !IsFtpSite()
&& m_strRedirectPath.IsEmpty()
)
{
err = CIISMBNode::EnumerateResultPane_(fExp, pHdr, pResData, m_pService);
if (err.Failed())
{
m_dwWin32Error = err.Win32Error();
}
}
return err;
}
/* virtual */
HRESULT
CIISSite::BuildMetaPath(CComBSTR & bstrPath) const
/*++
Routine Description:
Recursively build up the metabase path from the current node
and its parents
Arguments:
CComBSTR & bstrPath : Returns metabase path
Return Value:
HRESULT
Notes:
This will return the home directory path, e.g. "lm/w3svc/2/root",
not the path of the instance.
--*/
{
//
// Build instance path
//
HRESULT hr = CIISMBNode::BuildMetaPath(bstrPath);
if (SUCCEEDED(hr))
{
//
// Add root directory path
//
bstrPath.Append(_cszSeparator);
bstrPath.Append(g_cszRoot);
}
return hr;
}
// CODEWORK: make it work from CIISMBNode::DeleteNode
HRESULT
CIISSite::DeleteNode(IResultData * pResult)
{
CError err;
if (!NoYesMessageBox(IDS_CONFIRM_DELETE))
return err;
do
{
CComBSTR path;
CMetaInterface * pInterface = QueryInterface();
ASSERT(pInterface != NULL);
err = CIISMBNode::BuildMetaPath(path);
if (err.Failed())
break;
CMetaKey mk(pInterface, METADATA_MASTER_ROOT_HANDLE, METADATA_PERMISSION_WRITE);
if (!mk.Succeeded())
break;
err = mk.DeleteKey(path);
if (err.Failed())
break;
err = RemoveScopeItem();
} while (FALSE);
if (err.Failed())
{
DisplayError(err);
}
return err;
}
//
// We are not supporting empty comments on sites. Even if it is OK for
// metabase, it will bring more problems in UI. Empty name will be displayed
// as [Site #N] in UI, and when user will try to rename it again, it could be
// stored in metabase in this format.
//
HRESULT
CIISSite::RenameItem(LPOLESTR new_name)
{
CComBSTR path;
CError err;
if (new_name != NULL && lstrlen(new_name) > 0)
{
err = BuildMetaPath(path);
if (err.Succeeded())
{
// We need instance key here
CString path_inst;
CMetabasePath::GetInstancePath(path, path_inst);
CMetaKey mk(QueryInterface(), path_inst, METADATA_PERMISSION_WRITE);
err = mk.QueryResult();
if (err.Succeeded())
{
err = mk.SetValue(MD_SERVER_COMMENT, CString(new_name));
if (err.Succeeded())
{
m_strDisplayName = new_name;
}
}
}
}
return err;
}