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

1438 lines
31 KiB
C++

/*++
Copyright (c) 1994-2001 Microsoft Corporation
Module Name :
iismbnode.cpp
Abstract:
CIISMBNode 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 "supdlgs.h"
#include "iisobj.h"
#include "ftpsht.h"
#include "w3sht.h"
#include "fltdlg.h"
#include "pwiz.h"
#include <lm.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
//
// CIISMBNode implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* static */ LPOLESTR CIISMBNode::_cszSeparator = _T("/");
CIISMBNode::CIISMBNode(
IN CIISMachine * pOwner,
IN LPCTSTR szNode
)
/*++
Routine Description:
Constructor
Arguments:
CIISMachine * pOwner : Owner machine object
LPCTSTR szNode : Node name
Return Value:
N/A
--*/
: m_bstrNode(szNode),
m_bstrURL(NULL),
m_pOwner(pOwner)
{
ASSERT_READ_PTR(szNode);
ASSERT_READ_PTR(pOwner);
}
CIISMBNode::~CIISMBNode()
{
RemoveResultItems();
}
void
CIISMBNode::SetErrorOverrides(
IN OUT CError & err,
IN BOOL fShort
) const
/*++
Routine Description:
Set error message overrides
Arguments:
CError err : Error message object
BOOL fShort : TRUE to use only single-line errors
Return Value:
None
--*/
{
//
// Substitute friendly message for some ID codes.
//
// CODEWORK: Add global overrides as well.
//
err.AddOverride(EPT_S_NOT_REGISTERED,
fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA);
err.AddOverride(RPC_S_SERVER_UNAVAILABLE,
fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA);
err.AddOverride(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE);
err.AddOverride(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
err.AddOverride(REGDB_E_CLASSNOTREG, IDS_ERR_NO_INTERFACE);
if (!fShort)
{
err.AddOverride(ERROR_ACCESS_DENIED, IDS_ERR_ACCESS_DENIED);
}
}
BOOL
CIISMBNode::IsAdministrator() const
{
CIISMBNode * that = (CIISMBNode *)this;
return that->GetOwner()->HasAdministratorAccess();
}
void
CIISMBNode::DisplayError(
IN OUT CError & err
) const
/*++
Routine Description:
Display error message box. Substituting some friendly messages for
some specific error codes
Arguments:
CError & err : Error object contains code to be displayed
Return Value:
Noen
--*/
{
SetErrorOverrides(err);
err.MessageBox();
}
CIISMBNode *
CIISMBNode::GetParentNode() const
/*++
Routine Description:
Helper function to return the parent node in the scope tree
Arguments:
None
Return Value:
Parent CIISMBNode or NULL.
--*/
{
LONG_PTR cookie = NULL;
HSCOPEITEM hParent;
CIISMBNode * pNode = NULL;
HRESULT hr = S_OK;
ASSERT_PTR(_lpConsoleNameSpace);
if (m_hResultItem != 0)
{
SCOPEDATAITEM si;
::ZeroMemory(&si, sizeof(SCOPEDATAITEM));
si.mask = SDI_PARAM;
si.ID = m_hScopeItem;
hr = _lpConsoleNameSpace->GetItem(&si);
if (SUCCEEDED(hr))
{
cookie = si.lParam;
}
}
else
{
hr = _lpConsoleNameSpace->GetParentItem(
m_hScopeItem,
&hParent,
&cookie
);
}
if (SUCCEEDED(hr))
{
pNode = (CIISMBNode *)cookie;
ASSERT_PTR(pNode);
}
return pNode;
}
/* virtual */
HRESULT
CIISMBNode::BuildMetaPath(
OUT 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
--*/
{
HRESULT hr = S_OK;
CIISMBNode * pNode = GetParentNode();
if (pNode)
{
hr = pNode->BuildMetaPath(bstrPath);
if (SUCCEEDED(hr))
{
bstrPath.Append(_cszSeparator);
bstrPath.Append(QueryNodeName());
}
return hr;
}
//
// No parent node
//
ASSERT_MSG("No parent node");
return E_UNEXPECTED;
}
HRESULT
CIISMBNode::FillCustomData(CLIPFORMAT cf, LPSTREAM pStream)
{
HRESULT hr = DV_E_CLIPFORMAT;
ULONG uWritten;
if (cf == m_CCF_MachineName)
{
hr = pStream->Write(
QueryMachineName(),
(ocslen((OLECHAR*)QueryMachineName()) + 1) * sizeof(OLECHAR),
&uWritten
);
ASSERT(SUCCEEDED(hr));
return hr;
}
//
// Generate complete metabase path for this node
//
CString strField;
CString strMetaPath;
CComBSTR bstr;
if (FAILED(hr = BuildMetaPath(bstr)))
{
ASSERT(FALSE);
return hr;
}
strMetaPath = bstr;
if (cf == m_CCF_MetaPath)
{
//
// Whole metabase path requested
//
strField = strMetaPath;
}
else
{
//
// A portion of the metabase is requested. Return the requested
// portion
//
LPCTSTR lpMetaPath = (LPCTSTR)strMetaPath;
LPCTSTR lpEndPath = lpMetaPath + strMetaPath.GetLength() + 1;
LPCTSTR lpSvc = NULL;
LPCTSTR lpInstance = NULL;
LPCTSTR lpParent = NULL;
LPCTSTR lpNode = NULL;
//
// Break up the metabase path in portions
//
if (lpSvc = _tcschr(lpMetaPath, _T('/')))
{
++lpSvc;
if (lpInstance = _tcschr(lpSvc, _T('/')))
{
++lpInstance;
if (lpParent = _tcschr(lpInstance, _T('/')))
{
++lpParent;
lpNode = _tcsrchr(lpParent, _T('/'));
if (lpNode)
{
++lpNode;
}
}
}
}
int n1, n2;
if (cf == m_CCF_Service)
{
//
// Requested the service string
//
if (lpSvc)
{
n1 = DIFF(lpSvc - lpMetaPath);
n2 = lpInstance ? DIFF(lpInstance - lpSvc) : DIFF(lpEndPath - lpSvc);
strField = strMetaPath.Mid(n1, n2 - 1);
}
}
else if (cf == m_CCF_Instance)
{
//
// Requested the instance number
//
if (lpInstance)
{
n1 = DIFF(lpInstance - lpMetaPath);
n2 = lpParent ? DIFF(lpParent - lpInstance) : DIFF(lpEndPath - lpInstance);
strField = strMetaPath.Mid(n1, n2 - 1);
}
}
else if (cf == m_CCF_ParentPath)
{
//
// Requestd the parent path
//
if (lpParent)
{
n1 = DIFF(lpParent - lpMetaPath);
n2 = lpNode ? DIFF(lpNode - lpParent) : DIFF(lpEndPath - lpParent);
strField = strMetaPath.Mid(n1, n2 - 1);
}
}
else if (cf == m_CCF_Node)
{
//
// Requested the node name
//
if (lpNode)
{
n1 = DIFF(lpNode - lpMetaPath);
n2 = DIFF(lpEndPath - lpNode);
strField = strMetaPath.Mid(n1, n2 - 1);
}
}
else
{
ASSERT(FALSE);
DV_E_CLIPFORMAT;
}
}
TRACEEOLID("Requested metabase path data: " << strField);
int len = strField.GetLength() + 1;
hr = pStream->Write(strField,
(ocslen(strField) + 1) * sizeof(OLECHAR), &uWritten);
ASSERT(SUCCEEDED(hr));
return hr;
}
HRESULT
CIISMBNode::BuildURL(
OUT CComBSTR & bstrURL
) const
/*++
Routine Description:
Recursively build up the URL from the current node
and its parents.
Arguments:
CComBSTR & bstrURL : Returns URL
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
//
// Prepend parent portion
//
CIISMBNode * pNode = GetParentNode();
if (pNode)
{
hr = pNode->BuildURL(bstrURL);
//
// And our portion
//
if (SUCCEEDED(hr))
{
bstrURL.Append(_cszSeparator);
bstrURL.Append(QueryNodeName());
}
return hr;
}
//
// No parent node
//
ASSERT_MSG("No parent node");
return E_UNEXPECTED;
}
BOOL
CIISMBNode::OnLostInterface(
IN OUT CError & err
)
/*++
Routine Description:
Deal with lost interface. Ask the user to reconnect.
Arguments:
CError & err : Error object
Return Value:
TRUE if the interface was successfully recreated.
FALSE otherwise. If it tried and failed the error will
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CString str;
str.Format(IDS_RECONNECT_WARNING, QueryMachineName());
if (YesNoMessageBox(str))
{
//
// Attempt to recreate the interface
//
err = CreateInterface(TRUE);
return err.Succeeded();
}
return FALSE;
}
HRESULT
CIISMBNode::DeleteNode(IResultData * pResult)
{
CError err;
if (!NoYesMessageBox(IDS_CONFIRM_DELETE))
return err;
do
{
CComBSTR path;
CMetaInterface * pInterface = QueryInterface();
ASSERT(pInterface != NULL);
err = 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;
}
HRESULT
CIISMBNode::EnumerateVDirs(HSCOPEITEM hParent, CIISService * pService)
/*++
Routine Description:
Enumerate scope child items.
Arguments:
HSCOPEITEM hParent : Parent console handle
CIISService * pService : Service type
Return Value:
HRESULT
--*/
{
ASSERT_PTR(pService);
CError err;
CString strVRoot;
CMetaEnumerator * pme = NULL;
err = CreateEnumerator(pme);
while (err.Succeeded())
{
CIISDirectory * pDir;
err = pme->Next(strVRoot);
if (err.Succeeded())
{
TRACEEOLID("Enumerating node: " << strVRoot);
CChildNodeProps child(pme, strVRoot, WITH_INHERITANCE, FALSE);
err = child.LoadData();
DWORD dwWin32Error = err.Win32Error();
if (err.Failed())
{
//
// Filter out the non-fatal errors
//
switch(err.Win32Error())
{
case ERROR_ACCESS_DENIED:
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
err.Reset();
break;
default:
TRACEEOLID("Fatal error occurred " << err);
}
}
if (err.Succeeded())
{
//
// Skip non-virtual directories (that is, those with
// inherited vrpaths)
//
if (!child.IsPathInherited())
{
//
// Construct with full information.
//
pDir = new CIISDirectory(
m_pOwner,
pService,
strVRoot,
child.IsEnabledApplication(),
child.QueryWin32Error(),
child.GetRedirectedPath()
);
if (!pDir)
{
err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
err = pDir->AddToScopePane(hParent);
}
}
}
}
SAFE_DELETE(pme);
if (err.Win32Error() == ERROR_NO_MORE_ITEMS)
{
err.Reset();
}
if (err.Failed())
{
DisplayError(err);
}
// SetInterfaceError(err);
return err;
}
BOOL
CIISMBNode::GetPhysicalPath(
LPCTSTR metaPath,
CString & alias,
CString & physicalPath
)
/*++
Routine Description:
Build a physical path for the current node. Starting with the current
node, walk up the tree appending node names until a virtual directory
with a real physical path is found
Arguments:
CString & physicalPath : Returns file path
Return Value:
Pointer to path
--*/
{
if (CMetabasePath::IsMasterInstance(metaPath))
return FALSE;
BOOL fInherit = FALSE;
CMetaInterface * pInterface = QueryInterface();
ASSERT(pInterface != NULL);
CMetaKey mk(pInterface);
CError err(mk.QueryValue(
MD_VR_PATH,
physicalPath,
&fInherit,
metaPath
));
if (err.Failed())
{
CString lastNode;
CMetabasePath::GetLastNodeName(metaPath, lastNode);
PathAppend(lastNode.GetBuffer(MAX_PATH), alias);
lastNode.ReleaseBuffer();
CString buf(metaPath);
if (NULL == CMetabasePath::ConvertToParentPath(buf))
{
return FALSE;
}
else if (GetPhysicalPath(buf, lastNode, physicalPath))
{
return TRUE;
}
}
if (!alias.IsEmpty())
{
PathAppend(physicalPath.GetBuffer(MAX_PATH), alias);
physicalPath.ReleaseBuffer();
}
return TRUE;
}
HRESULT
CIISMBNode::CleanResult(IResultData * lpResultData)
{
CError err;
if (!m_ResultItems.IsEmpty())
{
POSITION pos = m_ResultItems.GetHeadPosition();
while (pos != NULL)
{
CIISFileName * pNode = m_ResultItems.GetNext(pos);
err = lpResultData->DeleteItem(pNode->m_hResultItem, 0);
if (err.Failed())
{
ASSERT(FALSE);
break;
}
delete pNode;
}
m_ResultItems.RemoveAll();
}
return err;
}
HRESULT
CIISMBNode::EnumerateResultPane_(
BOOL fExpand,
IHeaderCtrl * lpHeader,
IResultData * lpResultData,
CIISService * pService
)
{
CError err;
if (HasFileSystemFiles())
{
if (fExpand)
{
do
{
CString dir;
CComBSTR root;
BuildMetaPath(root);
CString physPath, alias;
GetPhysicalPath(CString(root), alias, physPath);
if (pService->IsLocal() || PathIsUNC(physPath))
{
dir = physPath;
}
else
{
::MakeUNCPath(dir, pService->QueryMachineName(), physPath);
}
dir.TrimLeft();
dir.TrimRight();
if (dir.IsEmpty())
{
break;
}
if (PathIsUNCServerShare(dir))
{
CString server, share;
int idx = dir.ReverseFind(_T('\\'));
ASSERT(idx != -1);
server = dir.Left(idx);
share = dir.Mid(++idx);
LPBYTE pbuf = NULL;
NET_API_STATUS rc = NetShareGetInfo((LPTSTR)(LPCTSTR)server, (LPTSTR)(LPCTSTR)share, 0, &pbuf);
if (NERR_Success == rc)
{
NetApiBufferFree(pbuf);
}
else
{
err = ERROR_BAD_NETPATH;
break;
}
}
dir += _T("\\*");
WIN32_FIND_DATA w32data;
HANDLE hFind = ::FindFirstFile(dir, &w32data);
if (hFind == INVALID_HANDLE_VALUE)
{
err.GetLastWinError();
ASSERT(FALSE);
break;
}
do
{
LPCTSTR name = w32data.cFileName;
if ((w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
CIISFileName * pNode = new CIISFileName(
GetOwner(),
pService,
w32data.dwFileAttributes,
name,
NULL);
if (!pNode)
{
err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
RESULTDATAITEM ri;
::ZeroMemory(&ri, sizeof(ri));
ri.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
ri.str = MMC_CALLBACK;
ri.nImage = pNode->QueryImage();
ri.lParam = (LPARAM)pNode;
err = lpResultData->InsertItem(&ri);
if (err.Succeeded())
{
pNode->SetScopeItem(m_hScopeItem);
pNode->SetResultItem(ri.itemID);
m_ResultItems.AddTail(pNode);
}
else
{
delete pNode;
}
}
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
FindClose(hFind);
} while (FALSE);
}
else
{
RemoveResultItems();
}
}
ASSERT(err.Succeeded());
return err;
}
void
CIISMBNode::RemoveResultItems()
{
if (!m_ResultItems.IsEmpty())
{
POSITION pos = m_ResultItems.GetHeadPosition();
while (pos != NULL)
{
CIISFileName * pNode = m_ResultItems.GetNext(pos);
delete pNode;
}
m_ResultItems.RemoveAll();
}
}
HRESULT
CIISMBNode::EnumerateWebDirs(HSCOPEITEM hParent, CIISService * pService)
/*++
Routine Description:
Enumerate scope file system child items.
Arguments:
HSCOPEITEM hParent : Parent console handle
CIISService * pService : Service type
Return Value:
HRESULT
--*/
{
ASSERT_PTR(pService);
CError err;
do
{
CString dir;
CComBSTR root;
BuildMetaPath(root);
CString physPath, alias;
GetPhysicalPath(CString(root), alias, physPath);
if (pService->IsLocal() || PathIsUNC(physPath))
{
dir = physPath;
}
else
{
::MakeUNCPath(dir, pService->QueryMachineName(), physPath);
}
dir.TrimLeft();
dir.TrimRight();
if (dir.IsEmpty())
{
break;
}
// Prepare for target machine metabase lookup
BOOL fCheckMetabase = TRUE;
CMetaKey mk(QueryInterface(), root, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE);
CError errMB(mk.QueryResult());
if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND)
{
//
// Metabase path not found, not a problem.
//
fCheckMetabase = FALSE;
errMB.Reset();
}
// We could have vroot pointed to target machine, or to another remote machine.
// Check if this resource is available and we have access to this resource
if (PathIsUNC(dir))
{
CString server, user, password;
server = PathFindNextComponent(dir);
int n = server.Find(_T('\\'));
if (n != -1)
{
server = server.Left(n);
}
user = QueryInterface()->QueryAuthInfo()->QueryUserName();
password = QueryInterface()->QueryAuthInfo()->QueryPassword();
if (server.CompareNoCase(pService->QueryMachineName()) != 0)
{
// non-local resource, get connection credentials
if (fCheckMetabase)
{
err = mk.QueryValue(MD_VR_USERNAME, user);
if (err.Succeeded())
{
err = mk.QueryValue(MD_VR_PASSWORD, password);
}
// these credentials could be empty. try defaults
err.Reset();
}
}
// Add use for this resource
NETRESOURCE nr;
nr.dwType = RESOURCETYPE_DISK;
nr.lpLocalName = NULL;
nr.lpRemoteName = (LPTSTR)(LPCTSTR)dir;
nr.lpProvider = NULL;
// Empty strings below mean no password, which is wrong. NULLs mean
// default user and default password -- this could work better for local case.
LPCTSTR p1 = password, p2 = user;
if (password.IsEmpty())
{
p1 = NULL;
}
if (user.IsEmpty())
{
p2 = NULL;
}
DWORD rc = WNetAddConnection2(&nr, p1, p2, 0);
if (NO_ERROR != rc)
{
err = rc;
break;
}
}
#if 0
// This is obsolete now
if (PathIsUNCServerShare(dir))
{
CString server, share;
int idx = dir.ReverseFind(_T('\\'));
ASSERT(idx != -1);
server = dir.Left(idx);
share = dir.Mid(++idx);
LPBYTE pbuf = NULL;
NET_API_STATUS rc = NetShareGetInfo((LPTSTR)(LPCTSTR)server, (LPTSTR)(LPCTSTR)share, 0, &pbuf);
if (NERR_Success == rc)
{
NetApiBufferFree(pbuf);
}
else
{
err = ERROR_BAD_NETPATH;
break;
}
}
#endif
dir += _T("\\*");
WIN32_FIND_DATA w32data;
HANDLE hFind = ::FindFirstFile(dir, &w32data);
if (hFind == INVALID_HANDLE_VALUE)
{
err.GetLastWinError();
break;
}
do
{
LPCTSTR name = w32data.cFileName;
if ( (w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
&& lstrcmp(name, _T(".")) != 0
&& lstrcmp(name, _T("..")) != 0
)
{
CIISFileName * pNode = new CIISFileName(m_pOwner,
pService, w32data.dwFileAttributes, name, NULL);
if (!pNode)
{
err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (fCheckMetabase)
{
errMB = mk.DoesPathExist(w32data.cFileName);
if (errMB.Succeeded())
{
//
// Match up with metabase properties. If the item
// is found in the metabase with a non-inherited vrpath,
// than a virtual root with this name exists, and this
// file/directory should not be shown.
//
CString vrpath;
BOOL f = FALSE;
DWORD attr = 0;
errMB = mk.QueryValue(MD_VR_PATH, vrpath, NULL, w32data.cFileName, &attr);
if (errMB.Succeeded() && (attr & METADATA_ISINHERITED) == 0)
{
TRACEEOLID("file/directory exists as vroot -- tossing" << w32data.cFileName);
delete pNode;
continue;
}
}
}
err = pNode->AddToScopePane(hParent);
}
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
FindClose(hFind);
} while (FALSE);
if (err.Failed())
{
DisplayError(err);
}
return err;
}
HRESULT
CIISMBNode::CreateEnumerator(CMetaEnumerator *& pEnum)
/*++
Routine Description:
Create enumerator object for the current path. Requires interface
to already be initialized
Arguments:
CMetaEnumerator *& pEnum : Returns enumerator
Return Value:
HRESULT
--*/
{
ASSERT(pEnum == NULL);
ASSERT(m_hScopeItem != NULL);
CComBSTR bstrPath;
CError err(BuildMetaPath(bstrPath));
if (err.Succeeded())
{
TRACEEOLID("Build metabase path: " << bstrPath);
BOOL fContinue = TRUE;
while(fContinue)
{
fContinue = FALSE;
pEnum = new CMetaEnumerator(QueryInterface(), bstrPath);
err = pEnum ? pEnum->QueryResult() : ERROR_NOT_ENOUGH_MEMORY;
if (IsLostInterface(err))
{
SAFE_DELETE(pEnum);
fContinue = OnLostInterface(err);
}
}
}
return err;
}
/* virtual */
HRESULT
CIISMBNode::Refresh(BOOL fReEnumerate)
/*++
Routine Description:
Refresh current node, and optionally re-enumerate child objects
Arguments:
BOOL fReEnumerate : If true, kill child objects, and re-enumerate
--*/
{
CError err;
//
// Set MFC state for wait cursor
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CWaitCursor wait;
if (fReEnumerate)
{
//
// Kill child objects
//
TRACEEOLID("Killing child objects");
ASSERT(m_hScopeItem != NULL);
err = RemoveChildren(m_hScopeItem);
if (err.Succeeded())
{
err = EnumerateScopePane(m_hScopeItem);
}
}
if (err.Succeeded())
{
//
// Refresh current node
//
err = RefreshData();
if (err.Succeeded())
{
err = RefreshDisplay();
}
}
return err;
}
/* virtual */
HRESULT
CIISMBNode::GetResultViewType(
OUT LPOLESTR * lplpViewType,
OUT long * lpViewOptions
)
/*++
Routine Description:
If we have an URL built up, display our result view as that URL,
and destroy it. This is done when 'browsing' a metabase node.
The derived class will build the URL, and reselect the node.
Arguments:
BSTR * lplpViewType : Return view type here
long * lpViewOptions : View options
Return Value:
S_FALSE to use default view type, S_OK indicates the
view type is returned in *ppViewType
--*/
{
if (m_bstrURL.Length())
{
*lpViewOptions = MMC_VIEW_OPTIONS_NONE;
*lplpViewType = (LPOLESTR)::CoTaskMemAlloc(
(m_bstrURL.Length() + 1) * sizeof(WCHAR)
);
if (*lplpViewType)
{
lstrcpy(*lplpViewType, m_bstrURL);
//
// Destroy URL so we get a normal result view next time
//
m_bstrURL.Empty();
m_fSkipEnumResult = TRUE;
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
//
// No URL waiting -- use standard result view
//
return CIISObject::GetResultViewType(lplpViewType, lpViewOptions);
}
HRESULT
ShellExecuteDirectory(
IN LPCTSTR lpszCommand,
IN LPCTSTR lpszOwner,
IN LPCTSTR lpszDirectory
)
/*++
Routine Description:
Shell Open or explore on a given directory path
Arguments:
LPCTSTR lpszCommand : "open" or "explore"
LPCTSTR lpszOwner : Owner server
LPCTSTR lpszDirectory : Directory path
Return Value:
Error return code.
--*/
{
CString strDir;
if (::IsServerLocal(lpszOwner) || ::IsUNCName(lpszDirectory))
{
//
// Local directory, or already a unc path
//
strDir = lpszDirectory;
}
else
{
::MakeUNCPath(strDir, lpszOwner, lpszDirectory);
}
TRACEEOLID("Attempting to " << lpszCommand << " Path: " << strDir);
CError err;
{
//
// AFX_MANAGE_STATE required for wait cursor
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState() );
CWaitCursor wait;
if (::ShellExecute(
NULL,
lpszCommand,
strDir,
NULL,
_T(""),
SW_SHOW
) <= (HINSTANCE)32)
{
err.GetLastWinError();
}
}
return err;
}
HRESULT
CIISMBNode::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
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
HRESULT hr = S_OK;
CError err = ERROR_NOT_ENOUGH_MEMORY;
switch (lCommandID)
{
case IDM_BROWSE:
//
// Build URL for this node, and force a re-select so as to change
// the result view
//
BuildURL(m_bstrURL);
if (m_bstrURL.Length())
{
//
// After selection, the browsed URL will come up in the result view
//
SelectScopeItem();
}
break;
//
// CODEWORK: Build path, and, using the explorer URL, put this stuff
// in the result view.
//
case IDM_OPEN:
{
CComBSTR meta_path;
CString phys_path, alias;
BuildMetaPath(meta_path);
if (GetPhysicalPath(meta_path, alias, phys_path))
{
hr = ShellExecuteDirectory(_T("open"), QueryMachineName(), phys_path);
}
}
break;
case IDM_EXPLORE:
{
CComBSTR meta_path;
CString phys_path, alias;
BuildMetaPath(meta_path);
if (GetPhysicalPath(meta_path, alias, phys_path))
{
TCHAR url[MAX_PATH];
DWORD len = MAX_PATH;
hr = UrlCreateFromPath(phys_path, url, &len, NULL);
m_bstrURL = url;
SelectScopeItem();
}
}
break;
case IDM_TASK_SECURITY_WIZARD:
{
CComBSTR path;
VERIFY(SUCCEEDED(BuildMetaPath(path)));
hr = RunSecurityWizard(QueryAuthInfo(),
QueryInterface(), CString(path),
IDB_WIZ_FTP_LEFT_SEC, IDB_WIZ_FTP_HEAD_SEC);
}
break;
//
// Pass on to base class
//
default:
hr = CIISObject::Command(lCommandID, pObj, type);
}
return hr;
}
HRESULT
CIISMBNode::OnPropertyChange(BOOL fScope, IResultData * pResult)
{
CError err;
err = Refresh(fScope);
if (err.Succeeded())
{
if ( fScope
&& HasFileSystemFiles()
&& !m_ResultItems.IsEmpty()
)
{
err = CleanResult(pResult);
if (err.Succeeded())
{
err = EnumerateResultPane(fScope, NULL, pResult);
}
}
else if (!fScope)
{
pResult->UpdateItem(m_hResultItem);
}
}
return err;
}
HRESULT
CIISMBNode::RemoveResultNode(CIISMBNode * pNode, IResultData * pResult)
{
CError err;
ASSERT(HasFileSystemFiles());
err = pResult->DeleteItem(pNode->m_hResultItem, 0);
if (err.Succeeded())
{
BOOL found = FALSE;
POSITION pos = m_ResultItems.GetHeadPosition();
while (pos != NULL)
{
if (m_ResultItems.GetNext(pos) == pNode)
{
found = TRUE;
break;
}
}
if (found)
{
m_ResultItems.RemoveAt(pos);
delete pNode;
}
}
return err;
}
// See FtpAddNew.cpp for the method CIISMBNode::AddFTPSite
// See WebAddNew.cpp for the method CIISMBNode::AddWebSite
// See add_app_pool.cpp for the method CIISMBNode::AddAppPool