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.
3052 lines
82 KiB
3052 lines
82 KiB
/*++
|
|
|
|
Copyright (c) 1994-2001 Microsoft Corporation
|
|
|
|
Module Name :
|
|
iisobj.cpp
|
|
|
|
Abstract:
|
|
IIS Object
|
|
|
|
Author:
|
|
Ronald Meijer (ronaldm)
|
|
Sergei Antonov (sergeia)
|
|
|
|
Project:
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "inetprop.h"
|
|
#include "InetMgrApp.h"
|
|
#include "supdlgs.h"
|
|
#include "connects.h"
|
|
#include "iisobj.h"
|
|
#include "ftpsht.h"
|
|
#include "w3sht.h"
|
|
#include "fltdlg.h"
|
|
#include "util.h"
|
|
#include "tracker.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
extern CInetmgrApp theApp;
|
|
extern INT g_iDebugOutputLevel;
|
|
extern DWORD g_dwInetmgrParamFlags;
|
|
|
|
// global list keep to track of open property sheets, project wide.
|
|
CPropertySheetTracker g_OpenPropertySheetTracker;
|
|
CWNetConnectionTrackerGlobal g_GlobalConnections;
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
CDebug_IISObject g_Debug_IISObject;
|
|
#endif
|
|
|
|
#define GLOBAL_DEFAULT_HELP_PATH _T("::/htm/iiswelcome.htm")
|
|
|
|
BOOL IsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// simple version using Win-32 APIs for pointer validation.
|
|
if (lp == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
if (lp == (const void *) 0xfeeefeee){return FALSE;}
|
|
if (lp == (const void *) 0xfefefefe){return FALSE;}
|
|
if (lp == (const void *) 0xdddddddd){return FALSE;}
|
|
if (lp == (const void *) 0x0badf00d){return FALSE;}
|
|
if (lp == (const void *) 0xbaadf00d){return FALSE;}
|
|
if (lp == (const void *) 0xbadf00d2){return FALSE;}
|
|
if (lp == (const void *) 0xbaadf000){return FALSE;}
|
|
if (lp == (const void *) 0xdeadbeef){return FALSE;}
|
|
#else
|
|
if (lp == (const void *) 0xfeeefeeefeeefeee){return FALSE;}
|
|
if (lp == (const void *) 0xfefefefefefefefe){return FALSE;}
|
|
if (lp == (const void *) 0xdddddddddddddddd){return FALSE;}
|
|
if (lp == (const void *) 0x0badf00d0badf00d){return FALSE;}
|
|
if (lp == (const void *) 0xbaadf00dbaadf00d){return FALSE;}
|
|
if (lp == (const void *) 0xbadf00d2badf00d2){return FALSE;}
|
|
if (lp == (const void *) 0xbaadf000baadf000){return FALSE;}
|
|
if (lp == (const void *) 0xdeadbeefdeadbeef){return FALSE;}
|
|
#endif
|
|
// Check for valid read ptr
|
|
// this will break into debugger on Chk build
|
|
if (0 == IsBadReadPtr(lp, nBytes))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
|
|
// Check for bad write ptr
|
|
// this will break into debugger on Chk build
|
|
if (TRUE == bRet && bReadWrite)
|
|
{
|
|
bRet = FALSE;
|
|
if (0 == IsBadWritePtr((LPVOID)lp, nBytes))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (FALSE == bRet)
|
|
{
|
|
DebugTrace(_T("Bad Pointer:%p"),lp);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// CInetMgrComponentData
|
|
//
|
|
static const GUID CInetMgrGUID_NODETYPE
|
|
= {0xa841b6c2, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
|
|
//BOOL CIISObject::m_fIsExtension = FALSE;
|
|
|
|
#define TB_COLORMASK RGB(192,192,192) // Lt. Gray
|
|
|
|
|
|
LPOLESTR
|
|
CoTaskDupString(
|
|
IN LPCOLESTR szString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to duplicate a OLESTR
|
|
|
|
Arguments:
|
|
|
|
LPOLESTR szString : Source string
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new string or NULL
|
|
|
|
--*/
|
|
{
|
|
OLECHAR * lpString = (OLECHAR *)CoTaskMemAlloc(
|
|
sizeof(OLECHAR)*(lstrlen(szString) + 1)
|
|
);
|
|
|
|
if (lpString != NULL)
|
|
{
|
|
lstrcpy(lpString, szString);
|
|
}
|
|
|
|
return lpString;
|
|
}
|
|
|
|
const GUID * CIISObject::m_NODETYPE = &CLSID_InetMgr; //&CInetMgrGUID_NODETYPE;
|
|
const OLECHAR * CIISObject::m_SZNODETYPE = OLESTR("A841B6C2-7577-11d0-BB1F-00A0C922E79C");
|
|
const CLSID * CIISObject::m_SNAPIN_CLASSID = &CLSID_InetMgr;
|
|
|
|
|
|
//
|
|
// Backup/restore taskpad gif resource
|
|
//
|
|
#define RES_TASKPAD_BACKUP _T("/img\\backup.gif")
|
|
|
|
|
|
|
|
//
|
|
// CIISObject implementation
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
//
|
|
// Important! The array indices below must ALWAYS be one
|
|
// less than the menu ID -- keep in sync with enumeration
|
|
// in iisobj.h!!!!
|
|
//
|
|
/* static */ CIISObject::CONTEXTMENUITEM_RC CIISObject::_menuItemDefs[] =
|
|
{
|
|
//
|
|
// Menu Commands in toolbar order
|
|
//
|
|
//nNameID nStatusID nDescriptionID lCmdID lInsertionPointID fSpecialFlags
|
|
// lpszMouseOverBitmap lpszMouseOffBitmap lpszLanguageIndenpendentID
|
|
{ IDS_MENU_CONNECT, IDS_MENU_TT_CONNECT, -1, IDM_CONNECT, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_CONNECT"), },
|
|
{ IDS_MENU_DISCOVER, IDS_MENU_TT_DISCOVER, -1, IDM_DISCOVER, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_DISCOVER"), },
|
|
{ IDS_MENU_START, IDS_MENU_TT_START, -1, IDM_START, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_START"), },
|
|
{ IDS_MENU_STOP, IDS_MENU_TT_STOP, -1, IDM_STOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_STOP"), },
|
|
{ IDS_MENU_PAUSE, IDS_MENU_TT_PAUSE, -1, IDM_PAUSE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_PAUSE"), },
|
|
//
|
|
// These are menu commands that do not show up in the toolbar
|
|
//
|
|
{ IDS_MENU_EXPLORE, IDS_MENU_TT_EXPLORE, -1, IDM_EXPLORE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_EXPLORE"), },
|
|
{ IDS_MENU_OPEN, IDS_MENU_TT_OPEN, -1, IDM_OPEN, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_OPEN"), },
|
|
{ IDS_MENU_BROWSE, IDS_MENU_TT_BROWSE, -1, IDM_BROWSE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_BROWSE"), },
|
|
{ IDS_MENU_RECYCLE, IDS_MENU_TT_RECYCLE, -1, IDM_RECYCLE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_RECYCLE"), },
|
|
{ IDS_MENU_PERMISSION, IDS_MENU_TT_PERMISSION, -1, IDM_PERMISSION, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_PERMISSION"), },
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
{ IDS_MENU_IMPERSONATE, IDS_MENU_TT_IMPERSONATE, -1, IDM_IMPERSONATE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_IMPERSONATE"), },
|
|
{ IDS_MENU_REM_IMPERS, IDS_MENU_TT_REM_IMPERS, -1, IDM_REMOVE_IMPERSONATION, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_REM_IMPERS"), },
|
|
#endif // _DEBUG
|
|
|
|
{ IDS_MENU_PROPERTIES, IDS_MENU_TT_PROPERTIES, -1, IDM_CONFIGURE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_PROPERTIES"), },
|
|
{ IDS_MENU_DISCONNECT, IDS_MENU_TT_DISCONNECT, -1, IDM_DISCONNECT, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_DISCONNECT"), },
|
|
{ IDS_MENU_BACKUP, IDS_MENU_TT_BACKUP, IDS_MENU_TT_BACKUP, IDM_METABACKREST, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, NULL, NULL, _T("IDS_MENU_BACKUP"), },
|
|
{ IDS_MENU_SHUTDOWN_IIS, IDS_MENU_TT_SHUTDOWN_IIS, -1, IDM_SHUTDOWN, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, NULL, NULL, _T("IDS_MENU_SHUTDOWN_IIS"), },
|
|
{ IDS_MENU_SAVE_DATA, IDS_MENU_TT_SAVE_DATA, -1, IDM_SAVE_DATA, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, NULL, NULL, _T("IDS_MENU_SAVE_DATA"), },
|
|
{ IDS_MENU_NEWVROOT, IDS_MENU_TT_NEWVROOT, IDS_MENU_DS_NEWVROOT, IDM_NEW_VROOT, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWVROOT, RES_TASKPAD_NEWVROOT, _T("IDS_MENU_NEWVROOT"), },
|
|
{ IDS_MENU_NEWINSTANCE, IDS_MENU_TT_NEWINSTANCE, IDS_MENU_DS_NEWINSTANCE, IDM_NEW_INSTANCE, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWINSTANCE"), },
|
|
{ IDS_MENU_NEWFTPSITE, IDS_MENU_TT_NEWFTPSITE, IDS_MENU_DS_NEWFTPSITE, IDM_NEW_FTP_SITE, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWFTPSITE"), },
|
|
{ IDS_MENU_NEWFTPSITE_FROMFILE, IDS_MENU_TT_NEWFTPSITE_FROMFILE, -1, IDM_NEW_FTP_SITE_FROM_FILE,CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, NULL, NULL, _T("IDS_MENU_NEWFTPSITE_FROMFILE"), },
|
|
{ IDS_MENU_NEWFTPVDIR, IDS_MENU_TT_NEWFTPVDIR, IDS_MENU_DS_NEWFTPVDIR, IDM_NEW_FTP_VDIR, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWFTPVDIR"), },
|
|
{ IDS_MENU_NEWFTPVDIR_FROMFILE, IDS_MENU_TT_NEWFTPVDIR_FROMFILE, -1, IDM_NEW_FTP_VDIR_FROM_FILE,CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, NULL, NULL, _T("IDS_MENU_NEWFTPVDIR_FROMFILE"), },
|
|
{ IDS_MENU_NEWWEBSITE, IDS_MENU_TT_NEWWEBSITE, IDS_MENU_DS_NEWWEBSITE, IDM_NEW_WEB_SITE, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWWEBSITE"), },
|
|
{ IDS_MENU_NEWWEBSITE_FROMFILE, IDS_MENU_TT_NEWWEBSITE_FROMFILE, -1, IDM_NEW_WEB_SITE_FROM_FILE,CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, NULL, NULL, _T("IDS_MENU_NEWWEBSITE_FROMFILE"), },
|
|
{ IDS_MENU_NEWWEBVDIR, IDS_MENU_TT_NEWWEBVDIR, IDS_MENU_DS_NEWWEBVDIR, IDM_NEW_WEB_VDIR, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWWEBVDIR"), },
|
|
{ IDS_MENU_NEWWEBVDIR_FROMFILE, IDS_MENU_TT_NEWWEBVDIR_FROMFILE, -1, IDM_NEW_WEB_VDIR_FROM_FILE,CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, NULL, NULL, _T("IDS_MENU_NEWWEBVDIR_FROMFILE"), },
|
|
{ IDS_MENU_NEWAPPPOOL, IDS_MENU_TT_NEWAPPPOOL, IDS_MENU_DS_NEWAPPPOOL, IDM_NEW_APP_POOL, CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, RES_TASKPAD_NEWSITE, RES_TASKPAD_NEWSITE, _T("IDS_MENU_NEWAPPPOOL"), },
|
|
{ IDS_MENU_NEWAPPPOOL_FROMFILE, IDS_MENU_TT_NEWAPPPOOL_FROMFILE, -1, IDM_NEW_APP_POOL_FROM_FILE,CCM_INSERTIONPOINTID_PRIMARY_NEW, 0, NULL, NULL, _T("IDS_MENU_NEWAPPPOOL_FROMFILE"), },
|
|
{ IDS_MENU_TASKPAD, IDS_MENU_TT_TASKPAD, -1, IDM_VIEW_TASKPAD, CCM_INSERTIONPOINTID_PRIMARY_VIEW,0, NULL, NULL, _T("IDS_MENU_TASKPAD"), },
|
|
{ IDS_MENU_EXPORT_CONFIG_WIZARD, IDS_MENU_TT_EXPORT_CONFIG_WIZARD, -1, IDM_TASK_EXPORT_CONFIG_WIZARD, CCM_INSERTIONPOINTID_PRIMARY_TASK, 0, NULL, NULL, _T("IDS_MENU_EXPORT_CONFIG_WIZARD"), },
|
|
{ IDS_MENU_WEBEXT_CONTAINER_ADD1, IDS_MENU_TT_WEBEXT_CONTAINER_ADD1, -1, IDM_WEBEXT_CONTAINER_ADD1, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_WEBEXT_CONTAINER_ADD1"), },
|
|
{ IDS_MENU_WEBEXT_CONTAINER_ADD2, IDS_MENU_TT_WEBEXT_CONTAINER_ADD2, -1, IDM_WEBEXT_CONTAINER_ADD2, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_WEBEXT_CONTAINER_ADD2"), },
|
|
{ IDS_MENU_WEBEXT_CONTAINER_PROHIBIT_ALL, IDS_MENU_TT_WEBEXT_CONTAINER_PROHIBIT_ALL, -1, IDM_WEBEXT_CONTAINER_PROHIBIT_ALL, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_WEBEXT_CONTAINER_PROHIBIT_ALL"), },
|
|
{ IDS_MENU_WEBEXT_ALLOW, IDS_MENU_TT_WEBEXT_ALLOW, -1, IDM_WEBEXT_ALLOW, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_WEBEXT_ALLOW"), },
|
|
{ IDS_MENU_WEBEXT_PROHIBIT, IDS_MENU_TT_WEBEXT_PROHIBIT, -1, IDM_WEBEXT_PROHIBIT, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_WEBEXT_PROHIBIT"), },
|
|
// { IDS_MENU_SERVICE_START, IDS_MENU_TT_SERVICE_START, -1, IDM_SERVICE_START, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_SERVICE_START"), },
|
|
// { IDS_MENU_SERVICE_STOP, IDS_MENU_TT_SERVICE_STOP, -1, IDM_SERVICE_STOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_SERVICE_STOP"), },
|
|
// { IDS_MENU_SERVICE_ENABLE, IDS_MENU_TT_SERVICE_ENABLE, -1, IDM_SERVICE_ENABLE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, NULL, NULL, _T("IDS_MENU_SERVICE_ENABLE"), },
|
|
};
|
|
|
|
/* static */ CComBSTR CIISObject::_bstrResult;
|
|
/* static */ CComBSTR CIISObject::_bstrLocalHost = _T("localhost");
|
|
/* static */ CComPtr<IComponent> CIISObject::_lpComponent = NULL;
|
|
/* static */ CComPtr<IComponentData> CIISObject::_lpComponentData = NULL;
|
|
/* static */ IToolbar * CIISObject::_lpToolBar = NULL;
|
|
|
|
|
|
/* static */
|
|
HRESULT
|
|
CIISObject::SetImageList(
|
|
IN LPIMAGELIST lpImageList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the image list
|
|
|
|
Arguments:
|
|
|
|
LPIMAGELIST lpImageList
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HBITMAP hImage16 = ::LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_INETMGR16));
|
|
HBITMAP hImage32 = ::LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_INETMGR32));
|
|
ASSERT(hImage16 != NULL);
|
|
ASSERT(hImage32 != NULL);
|
|
HRESULT hr = S_OK;
|
|
|
|
if (hImage16 != NULL && hImage32 != NULL)
|
|
{
|
|
if (S_OK != lpImageList->ImageListSetStrip(
|
|
(LONG_PTR *)hImage16,
|
|
(LONG_PTR *)hImage32,
|
|
0,
|
|
RGB_BK_IMAGES
|
|
))
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
::DeleteObject(hImage16);
|
|
::DeleteObject(hImage32);
|
|
}
|
|
else
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
IConsoleNameSpace * CIISObject::GetConsoleNameSpace()
|
|
{
|
|
if (!_lpConsoleNameSpace)
|
|
{
|
|
// Our Machine node should this info for us.
|
|
CIISObject * pMyMachine = GetMachineObject();
|
|
if (pMyMachine)
|
|
{
|
|
if (pMyMachine != this)
|
|
{
|
|
_lpConsoleNameSpace = pMyMachine->GetConsoleNameSpace();
|
|
}
|
|
}
|
|
}
|
|
ASSERT(_lpConsoleNameSpace);
|
|
return _lpConsoleNameSpace;
|
|
}
|
|
|
|
IConsole * CIISObject::GetConsole()
|
|
{
|
|
if (!_lpConsole)
|
|
{
|
|
// Our Machine node should this info for us.
|
|
CIISObject * pMyMachine = GetMachineObject();
|
|
if (pMyMachine)
|
|
{
|
|
if (pMyMachine != this)
|
|
{
|
|
_lpConsole = pMyMachine->GetConsole();
|
|
}
|
|
}
|
|
}
|
|
ASSERT(_lpConsole);
|
|
return _lpConsole;
|
|
}
|
|
|
|
|
|
/* static */
|
|
void
|
|
CIISObject::BuildResultView(
|
|
IN LPHEADERCTRL lpHeader,
|
|
IN int cColumns,
|
|
IN int * pnIDS,
|
|
IN int * pnWidths
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the result view columns.
|
|
|
|
Routine Description:
|
|
|
|
LPHEADERCTRL lpHeader : Header control
|
|
int cColumns : Number of columns
|
|
int * pnIDS : Array of column header strings
|
|
int * pnWidths : Array of column widths
|
|
|
|
Routine Description:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(lpHeader);
|
|
|
|
CComBSTR bstr;
|
|
|
|
for (int n = 0; n < cColumns; ++n)
|
|
{
|
|
if (pnIDS[n] != 0)
|
|
{
|
|
VERIFY(bstr.LoadString(pnIDS[n]));
|
|
lpHeader->InsertColumn(n, bstr, LVCFMT_LEFT, pnWidths[n]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* static */
|
|
CWnd *
|
|
CIISObject::GetMainWindow(IConsole * pConsole)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a pointer to main window object.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to main window object. This object is temporary and should not be
|
|
cached.
|
|
|
|
--*/
|
|
{
|
|
HWND hWnd;
|
|
CWnd * pWnd = NULL;
|
|
if (pConsole)
|
|
{
|
|
HRESULT hr = pConsole->GetMainWindow(&hWnd);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pWnd = CWnd::FromHandle(hWnd);
|
|
}
|
|
}
|
|
return pWnd;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
HRESULT
|
|
CIISObject::AddMMCPage(
|
|
IN LPPROPERTYSHEETCALLBACK lpProvider,
|
|
IN CPropertyPage * pPage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add MMC page to providers sheet.
|
|
|
|
Arguments:
|
|
|
|
LPPROPERTYSHEETCALLBACK lpProvider : Property sheet provider
|
|
CPropertyPage * pPage : Property page to add
|
|
|
|
Return:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(pPage);
|
|
|
|
if (pPage == NULL)
|
|
{
|
|
TRACEEOLID("NULL page pointer passed to AddMMCPage");
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
PROPSHEETPAGE_LATEST pspLatest;
|
|
ZeroMemory(&pspLatest, sizeof(PROPSHEETPAGE_LATEST));
|
|
CopyMemory (&pspLatest, &pPage->m_psp, pPage->m_psp.dwSize);
|
|
pspLatest.dwSize = sizeof(pspLatest);
|
|
//
|
|
// MFC Bug work-around.
|
|
//
|
|
MMCPropPageCallback(&pspLatest);
|
|
|
|
HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pspLatest);
|
|
if (hPage == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
return lpProvider->AddPage(hPage);
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::GetProperty(
|
|
LPDATAOBJECT pDataObject,
|
|
BSTR szPropertyName,
|
|
BSTR* pbstrProperty)
|
|
{
|
|
CString strProperty;
|
|
|
|
if (!_wcsicmp(L"CCF_HTML_DETAILS",szPropertyName))
|
|
{
|
|
// return back html/javascript into strProperty
|
|
//*pbstrProperty = ::SysAllocString(strProperty);
|
|
}
|
|
else if (!_wcsicmp(L"CCF_DESCRIPTION",szPropertyName))
|
|
{
|
|
// Display data in Description field...
|
|
}
|
|
else
|
|
{
|
|
return S_FALSE; // unknown strPropertyName
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
CIISObject::CIISObject()
|
|
: m_hScopeItem(NULL),
|
|
m_use_count(0),
|
|
m_hResultItem(0),
|
|
m_fSkipEnumResult(FALSE),
|
|
m_fFlaggedForDeletion(FALSE),
|
|
m_hwnd(NULL),
|
|
m_ppHandle(NULL)
|
|
{
|
|
m_fIsExtension = FALSE;
|
|
#if defined(_DEBUG) || DBG
|
|
// Add to the global list of CIISObjects
|
|
// and keep track of it.
|
|
g_Debug_IISObject.Add(this);
|
|
#endif
|
|
}
|
|
|
|
CIISObject::~CIISObject()
|
|
{
|
|
#if defined(_DEBUG) || DBG
|
|
// Add to the global list of CIISObjects
|
|
// and keep track of it.
|
|
g_Debug_IISObject.Del(this);
|
|
#endif
|
|
}
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::ControlbarNotify(
|
|
IN MMC_NOTIFY_TYPE event,
|
|
IN LPARAM arg,
|
|
IN LPARAM param
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle control bar notification messages, such as select or click.
|
|
|
|
Arguments:
|
|
|
|
MMC_NOTIFY_TYPE event : Notification message
|
|
long arg : Message specific argument
|
|
long param : Message specific parameter
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL fSelect = (BOOL)HIWORD(arg);
|
|
BOOL fScope = (BOOL)LOWORD(arg);
|
|
HRESULT hr = S_OK;
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_SELECT:
|
|
{
|
|
//
|
|
// Handle selection of this node by attaching the toolbar
|
|
// and enabling/disabling specific buttons
|
|
//
|
|
_lpToolBar = (IToolbar *) (* (LPUNKNOWN *) param);
|
|
if (_lpToolBar)
|
|
{
|
|
SetToolBarStates(_lpToolBar);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MMCN_BTN_CLICK:
|
|
//
|
|
// Handle button-click by passing the command ID of the
|
|
// button to the command handler
|
|
//
|
|
hr = Command((long)param, NULL, fScope ? CCT_SCOPE : CCT_RESULT);
|
|
break;
|
|
|
|
case MMCN_HELP:
|
|
break;
|
|
|
|
default:
|
|
ASSERT_MSG("Invalid control bar notification received");
|
|
};
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::SetToolBarStates(CComPtr<IToolbar> lpToolBar)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the toolbar states depending on the state of this object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
if (lpToolBar)
|
|
{
|
|
lpToolBar->SetButtonState(IDM_CONNECT, ENABLED, IsConnectable());
|
|
lpToolBar->SetButtonState(IDM_PAUSE, ENABLED, IsPausable());
|
|
lpToolBar->SetButtonState(IDM_START, ENABLED, IsStartable());
|
|
lpToolBar->SetButtonState(IDM_STOP, ENABLED, IsStoppable());
|
|
lpToolBar->SetButtonState(IDM_PAUSE, BUTTONPRESSED, IsPaused());
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::GetScopePaneInfo(
|
|
IN OUT LPSCOPEDATAITEM lpScopeDataItem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return information about scope pane.
|
|
|
|
Arguments:
|
|
|
|
LPSCOPEDATAITEM lpScopeDataItem : Scope data item
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_WRITE_PTR(lpScopeDataItem);
|
|
|
|
if (lpScopeDataItem->mask & SDI_STR)
|
|
{
|
|
lpScopeDataItem->displayname = QueryDisplayName();
|
|
}
|
|
|
|
if (lpScopeDataItem->mask & SDI_IMAGE)
|
|
{
|
|
lpScopeDataItem->nImage = QueryImage();
|
|
}
|
|
|
|
if (lpScopeDataItem->mask & SDI_OPENIMAGE)
|
|
{
|
|
lpScopeDataItem->nOpenImage = QueryImage();
|
|
}
|
|
|
|
if (lpScopeDataItem->mask & SDI_PARAM)
|
|
{
|
|
lpScopeDataItem->lParam = (LPARAM)this;
|
|
}
|
|
|
|
if (lpScopeDataItem->mask & SDI_STATE)
|
|
{
|
|
//
|
|
// BUGBUG: Wotz all this then?
|
|
//
|
|
ASSERT_MSG("State requested");
|
|
lpScopeDataItem->nState = 0;
|
|
}
|
|
|
|
//
|
|
// TODO : Add code for SDI_CHILDREN
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
int
|
|
CIISObject::CompareScopeItem(
|
|
IN CIISObject * pObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Standard comparison method to compare lexically on display name.
|
|
Derived classes should override if anything other than lexical
|
|
sort on the display name is required.
|
|
|
|
Arguments:
|
|
|
|
CIISObject * pObject : Object to compare against
|
|
|
|
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);
|
|
|
|
//
|
|
// First criteria is object type
|
|
//
|
|
int n1 = QuerySortWeight();
|
|
int n2 = pObject->QuerySortWeight();
|
|
|
|
if (n1 != n2)
|
|
{
|
|
return n1 - n2;
|
|
}
|
|
|
|
//
|
|
// Else sort lexically on the display name.
|
|
//
|
|
return ::lstrcmpi(QueryDisplayName(), pObject->QueryDisplayName());
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
int
|
|
CIISObject::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;
|
|
}
|
|
|
|
//
|
|
// Sort lexically on column text
|
|
//
|
|
return ::lstrcmpi(
|
|
GetResultPaneColInfo(nCol),
|
|
pObject->GetResultPaneColInfo(nCol)
|
|
);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::GetResultPaneInfo(LPRESULTDATAITEM lpResultDataItem)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get information about result pane item
|
|
|
|
Arguments:
|
|
|
|
LPRESULTDATAITEM lpResultDataItem : Result data item
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_WRITE_PTR(lpResultDataItem);
|
|
|
|
if (lpResultDataItem->mask & RDI_STR)
|
|
{
|
|
lpResultDataItem->str = GetResultPaneColInfo(lpResultDataItem->nCol);
|
|
}
|
|
|
|
if (lpResultDataItem->mask & RDI_IMAGE)
|
|
{
|
|
lpResultDataItem->nImage = QueryImage();
|
|
}
|
|
|
|
if (lpResultDataItem->mask & RDI_PARAM)
|
|
{
|
|
lpResultDataItem->lParam = (LPARAM)this;
|
|
}
|
|
|
|
if (lpResultDataItem->mask & RDI_INDEX)
|
|
{
|
|
//
|
|
// BUGBUG: Wotz all this then?
|
|
//
|
|
ASSERT_MSG("INDEX???");
|
|
lpResultDataItem->nIndex = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
LPOLESTR
|
|
CIISObject::GetResultPaneColInfo(int nCol)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return result pane string for the given column number
|
|
|
|
Arguments:
|
|
|
|
int nCol : Column number
|
|
|
|
Return Value:
|
|
|
|
String
|
|
|
|
--*/
|
|
{
|
|
if (nCol == 0)
|
|
{
|
|
return QueryDisplayName();
|
|
}
|
|
|
|
ASSERT_MSG("Override GetResultPaneColInfo");
|
|
|
|
return OLESTR("Override GetResultPaneColInfo");
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::GetResultViewType(
|
|
OUT LPOLESTR * lplpViewType,
|
|
OUT long * lpViewOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tell MMC what our result view looks like
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
*lplpViewType = NULL;
|
|
*lpViewOptions = MMC_VIEW_OPTIONS_USEFONTLINKING;
|
|
//
|
|
// Default View
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::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
|
|
|
|
--*/
|
|
{
|
|
CComQIPtr<IPropertySheetProvider, &IID_IPropertySheetProvider> sp(GetConsole());
|
|
CError err = sp->FindPropertySheet(
|
|
reinterpret_cast<MMC_COOKIE>(this),
|
|
0,
|
|
(LPDATAOBJECT)this);
|
|
if (err == S_OK)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::QueryPagesFor(
|
|
IN DATA_OBJECT_TYPES type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if a property sheet should be brought up for this data
|
|
object
|
|
|
|
Arguments:
|
|
|
|
DATA_OBJECT_TYPES type : Data object type
|
|
|
|
Return Value:
|
|
|
|
S_OK, if properties may be brought up for this item, S_FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
return IsConfigurable() ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
CIISRoot *
|
|
CIISObject::GetRoot()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the CIISRoot object of this tree.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
CIISRoot * or NULL
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!m_fIsExtension);
|
|
LONG_PTR cookie;
|
|
HSCOPEITEM hParent;
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
|
|
HRESULT hr = pConsoleNameSpace->GetParentItem(m_hScopeItem, &hParent, &cookie);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CIISMBNode * pNode = (CIISMBNode *)cookie;
|
|
ASSERT_PTR(pNode);
|
|
ASSERT_PTR(hParent);
|
|
|
|
if (pNode)
|
|
{
|
|
return pNode->GetRoot();
|
|
}
|
|
}
|
|
|
|
ASSERT_MSG("Unable to find CIISRoot object!");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::AskForAndAddMachine()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask user to add a computer name, verify the computer is alive, and add it to
|
|
the list.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
CError err;
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
|
|
// ensure the dialog gets themed
|
|
CThemeContextActivator activator(theApp.GetFusionInitHandle());
|
|
|
|
ConnectServerDlg dlg(GetConsoleNameSpace(),GetConsole(),GetMainWindow(GetConsole()));
|
|
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
CIISMachine * pMachine = dlg.GetMachine();
|
|
|
|
//
|
|
// The machine object we get from the dialog
|
|
// is guaranteed to be good and valid.
|
|
//
|
|
ASSERT_PTR(pMachine);
|
|
ASSERT(pMachine->HasInterface());
|
|
|
|
CIISRoot * pRoot = GetRoot();
|
|
|
|
if (pRoot)
|
|
{
|
|
pMachine->SetConsoleData(pRoot->GetConsoleNameSpace(),pRoot->GetConsole());
|
|
//
|
|
// Add new machine object as child of the IIS root
|
|
// object.
|
|
//
|
|
if (pRoot->m_scServers.Add(pMachine))
|
|
{
|
|
pMachine->AddRef();
|
|
err = pMachine->AddToScopePaneSorted(pRoot->QueryScopeItem());
|
|
if (err.Succeeded())
|
|
{
|
|
//
|
|
// Select the item in the scope view
|
|
//
|
|
err = pMachine->SelectScopeItem();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Duplicate machine already in cache. Find it and select
|
|
// it.
|
|
//
|
|
TRACEEOLID("Machine already in scope view.");
|
|
CIISObject * pIdentical = pRoot->FindIdenticalScopePaneItem(pMachine);
|
|
//
|
|
// Duplicate must exist!
|
|
//
|
|
ASSERT_READ_PTR(pIdentical);
|
|
|
|
if (pIdentical)
|
|
{
|
|
err = pIdentical->SelectScopeItem();
|
|
}
|
|
|
|
pMachine->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
HRESULT
|
|
CIISObject::AddMenuItemByCommand(
|
|
IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
|
|
IN LONG lCmdID,
|
|
IN LONG fFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add menu item by command
|
|
|
|
Arguments:
|
|
|
|
LPCONTEXTMENUCALLBACK lpContextMenuCallback : Callback pointer
|
|
LONG lCmdID : Command ID
|
|
LONG fFlags : Flags
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL bAdded = FALSE;
|
|
ASSERT_READ_PTR(lpContextMenuCallback);
|
|
|
|
//
|
|
// Offset 1 menu commands
|
|
//
|
|
LONG l = lCmdID -1;
|
|
|
|
CComBSTR strName;
|
|
CComBSTR strStatus;
|
|
|
|
VERIFY(strName.LoadString(_menuItemDefs[l].nNameID));
|
|
VERIFY(strStatus.LoadString(_menuItemDefs[l].nStatusID));
|
|
|
|
// Try to use IContextMenuCallback2 because of language independent string
|
|
CONTEXTMENUITEM2 contextmenuitem;
|
|
IContextMenuCallback2* pIContextMenuCallback2 = NULL;
|
|
HRESULT hr = lpContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (void**)&pIContextMenuCallback2);
|
|
if(hr == S_OK && pIContextMenuCallback2 != NULL)
|
|
{
|
|
::ZeroMemory( &contextmenuitem, sizeof(contextmenuitem) );
|
|
contextmenuitem.strName = strName;
|
|
contextmenuitem.strStatusBarText = strStatus;
|
|
contextmenuitem.lCommandID = _menuItemDefs[l].lCmdID;
|
|
contextmenuitem.lInsertionPointID = _menuItemDefs[l].lInsertionPointID;
|
|
contextmenuitem.fFlags = fFlags;
|
|
contextmenuitem.fSpecialFlags = _menuItemDefs[l].fSpecialFlags;
|
|
// Here is the language independent ID
|
|
// We must use this to refer to the Menu item otherwise we will have problems in every language (mainly far east (FE) languages.
|
|
contextmenuitem.strLanguageIndependentName = (LPWSTR) _menuItemDefs[l].lpszLanguageIndenpendentID;
|
|
hr = pIContextMenuCallback2->AddItem( &contextmenuitem );
|
|
if( hr == S_OK)
|
|
{
|
|
bAdded = TRUE;
|
|
}
|
|
pIContextMenuCallback2->Release();
|
|
pIContextMenuCallback2 = NULL;
|
|
}
|
|
|
|
if (!bAdded)
|
|
{
|
|
CONTEXTMENUITEM cmi;
|
|
cmi.strName = strName;
|
|
cmi.strStatusBarText = strStatus;
|
|
cmi.lCommandID = _menuItemDefs[l].lCmdID;
|
|
cmi.lInsertionPointID = _menuItemDefs[l].lInsertionPointID;
|
|
cmi.fFlags = fFlags;
|
|
cmi.fSpecialFlags = _menuItemDefs[l].fSpecialFlags;
|
|
hr = lpContextMenuCallback->AddItem(&cmi);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
HRESULT
|
|
CIISObject::AddMenuSeparator(
|
|
IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
|
|
IN LONG lInsertionPointID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a separator to the given insertion point menu.
|
|
|
|
Arguments:
|
|
|
|
LPCONTEXTMENUCALLBACK lpContextMenuCallback : Callback pointer
|
|
LONG lInsertionPointID : Insertion point menu id.
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(lpContextMenuCallback);
|
|
|
|
CONTEXTMENUITEM menuSep =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
-1,
|
|
lInsertionPointID,
|
|
0,
|
|
CCM_SPECIAL_SEPARATOR
|
|
};
|
|
|
|
return lpContextMenuCallback->AddItem(&menuSep);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CIISObject::IsExpanded() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if this object has been expanded.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if the node has been expanded,
|
|
FALSE if it has not.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(m_hScopeItem != NULL);
|
|
SCOPEDATAITEM scopeDataItem;
|
|
CIISObject * ThisConst = (CIISObject *)this;
|
|
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *) ThisConst->GetConsoleNameSpace();
|
|
|
|
::ZeroMemory(&scopeDataItem, sizeof(SCOPEDATAITEM));
|
|
scopeDataItem.mask = SDI_STATE;
|
|
|
|
scopeDataItem.ID = m_hScopeItem;
|
|
|
|
HRESULT hr = pConsoleNameSpace->GetItem(&scopeDataItem);
|
|
|
|
return SUCCEEDED(hr) &&
|
|
scopeDataItem.nState == MMC_SCOPE_ITEM_STATE_EXPANDEDONCE;
|
|
}
|
|
|
|
|
|
CIISObject *
|
|
CIISObject::FindIdenticalScopePaneItem(
|
|
IN CIISObject * pObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find CIISObject in the scope view. The scope view is assumed
|
|
to be sorted.
|
|
|
|
Arguments:
|
|
|
|
CIISObject * pObject : Item to search for
|
|
|
|
Return Value:
|
|
|
|
Pointer to iis object, or NULL if the item was not found
|
|
|
|
Notes:
|
|
|
|
Note that any item with a 0 comparison value is returned, not
|
|
necessarily the identical CIISObject.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(m_hScopeItem != NULL);
|
|
|
|
//
|
|
// Find proper insertion point
|
|
//
|
|
HSCOPEITEM hChildItem = NULL;
|
|
CIISObject * pReturn = NULL;
|
|
CIISObject * pItem;
|
|
LONG_PTR cookie;
|
|
int nSwitch;
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
|
|
HRESULT hr = pConsoleNameSpace->GetChildItem(
|
|
m_hScopeItem, &hChildItem, &cookie);
|
|
|
|
while(SUCCEEDED(hr) && hChildItem)
|
|
{
|
|
//
|
|
// The cookie is really the IISObject, which is what we stuff
|
|
// in the lparam.
|
|
//
|
|
pItem = (CIISObject *)cookie;
|
|
ASSERT_PTR(pItem);
|
|
|
|
nSwitch = pItem->CompareScopeItem(pObject);
|
|
|
|
if (nSwitch == 0)
|
|
{
|
|
//
|
|
// Found it.
|
|
//
|
|
pReturn = pItem;
|
|
}
|
|
|
|
if (nSwitch > 0)
|
|
{
|
|
//
|
|
// Should have found it by now.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Advance to next child of same parent
|
|
//
|
|
hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
|
|
}
|
|
|
|
return pReturn;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::AddMenuItems(
|
|
IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
|
|
IN OUT long * pInsertionAllowed,
|
|
IN DATA_OBJECT_TYPES type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add menu items to the context menu
|
|
|
|
Arguments:
|
|
|
|
LPCONTEXTMENUCALLBACK lpContextMenuCallback : Context menu callback
|
|
long * pInsertionAllowed : Insertion allowed
|
|
DATA_OBJECT_TYPES type : Object type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(lpContextMenuCallback);
|
|
|
|
ASSERT(pInsertionAllowed != NULL);
|
|
if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) != 0)
|
|
{
|
|
if (IsConnectable() && !m_fIsExtension)
|
|
{
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_CONNECT);
|
|
}
|
|
|
|
if (IsDisconnectable() && !m_fIsExtension)
|
|
{
|
|
ASSERT(IsConnectable());
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_DISCONNECT);
|
|
}
|
|
|
|
// Check if it should be disabled...
|
|
BOOL bHasFiles = HasFileSystemFiles();
|
|
if (IsExplorable())
|
|
{
|
|
AddMenuSeparator(lpContextMenuCallback);
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_EXPLORE, bHasFiles ? 0 : MF_GRAYED);
|
|
}
|
|
|
|
if (IsOpenable())
|
|
{
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_OPEN, bHasFiles ? 0 : MF_GRAYED);
|
|
}
|
|
|
|
if (IsPermissionable())
|
|
{
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_PERMISSION, bHasFiles ? 0 : MF_GRAYED);
|
|
}
|
|
|
|
if (IsBrowsable())
|
|
{
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_BROWSE);
|
|
}
|
|
|
|
if (IsControllable())
|
|
{
|
|
AddMenuSeparator(lpContextMenuCallback);
|
|
|
|
UINT nPauseFlags = IsPausable() ? 0 : MF_GRAYED;
|
|
|
|
if (IsPaused())
|
|
{
|
|
nPauseFlags |= MF_CHECKED;
|
|
}
|
|
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_START, IsStartable() ? 0 : MF_GRAYED);
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_STOP, IsStoppable() ? 0 : MF_GRAYED);
|
|
AddMenuItemByCommand(lpContextMenuCallback, IDM_PAUSE, nPauseFlags);
|
|
}
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
g_Debug_IISObject.Dump(2);
|
|
#endif
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
CIISObject * pOpenItem = NULL;
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
g_OpenPropertySheetTracker.IsPropertySheetOpenBelowMe(pConsoleNameSpace,this,&pOpenItem);
|
|
#endif
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::Command(
|
|
IN long lCommandID,
|
|
IN CSnapInObjectRootBase * lpObj,
|
|
IN DATA_OBJECT_TYPES type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle command from context menu.
|
|
|
|
Arguments:
|
|
|
|
long lCommandID : Command ID
|
|
CSnapInObjectRootBase * lpObj : Base object
|
|
DATA_OBJECT_TYPES type : Data object type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (lCommandID)
|
|
{
|
|
case IDM_CONNECT:
|
|
hr = AskForAndAddMachine();
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
|
|
LPCTSTR
|
|
ParseEvent(MMC_NOTIFY_TYPE event)
|
|
{
|
|
LPCTSTR p = NULL;
|
|
switch (event)
|
|
{
|
|
case MMCN_ACTIVATE: p = _T("MMCN_ACTIVATE"); break;
|
|
case MMCN_ADD_IMAGES: p = _T("MMCN_ADD_IMAGES"); break;
|
|
case MMCN_BTN_CLICK: p = _T("MMCN_BTN_CLICK"); break;
|
|
case MMCN_CLICK: p = _T("MMCN_CLICK"); break;
|
|
case MMCN_COLUMN_CLICK: p = _T("MMCN_COLUMN_CLICK"); break;
|
|
case MMCN_CONTEXTMENU: p = _T("MMCN_CONTEXTMENU"); break;
|
|
case MMCN_CUTORMOVE: p = _T("MMCN_CUTORMOVE"); break;
|
|
case MMCN_DBLCLICK: p = _T("MMCN_DBLCLICK"); break;
|
|
case MMCN_DELETE: p = _T("MMCN_DELETE"); break;
|
|
case MMCN_DESELECT_ALL: p = _T("MMCN_DESELECT_ALL"); break;
|
|
case MMCN_EXPAND: p = _T("MMCN_EXPAND"); break;
|
|
case MMCN_HELP: p = _T("MMCN_HELP"); break;
|
|
case MMCN_MENU_BTNCLICK: p = _T("MMCN_MENU_BTNCLICK"); break;
|
|
case MMCN_MINIMIZED: p = _T("MMCN_MINIMIZED"); break;
|
|
case MMCN_PASTE: p = _T("MMCN_PASTE"); break;
|
|
case MMCN_PROPERTY_CHANGE: p = _T("MMCN_PROPERTY_CHANGE"); break;
|
|
case MMCN_QUERY_PASTE: p = _T("MMCN_QUERY_PASTE"); break;
|
|
case MMCN_REFRESH: p = _T("MMCN_REFRESH"); break;
|
|
case MMCN_REMOVE_CHILDREN: p = _T("MMCN_REMOVE_CHILDREN"); break;
|
|
case MMCN_RENAME: p = _T("MMCN_RENAME"); break;
|
|
case MMCN_SELECT: p = _T("MMCN_SELECT"); break;
|
|
case MMCN_SHOW: p = _T("MMCN_SHOW"); break;
|
|
case MMCN_VIEW_CHANGE: p = _T("MMCN_VIEW_CHANGE"); break;
|
|
case MMCN_SNAPINHELP: p = _T("MMCN_SNAPINHELP"); break;
|
|
case MMCN_CONTEXTHELP: p = _T("MMCN_CONTEXTHELP"); break;
|
|
case MMCN_INITOCX: p = _T("MMCN_INITOCX"); break;
|
|
case MMCN_FILTER_CHANGE: p = _T("MMCN_FILTER_CHANGE"); break;
|
|
case MMCN_FILTERBTN_CLICK: p = _T("MMCN_FILTERBTN_CLICK"); break;
|
|
case MMCN_RESTORE_VIEW: p = _T("MMCN_RESTORE_VIEW"); break;
|
|
case MMCN_PRINT: p = _T("MMCN_PRINT"); break;
|
|
case MMCN_PRELOAD: p = _T("MMCN_PRELOAD"); break;
|
|
case MMCN_LISTPAD: p = _T("MMCN_LISTPAD"); break;
|
|
case MMCN_EXPANDSYNC: p = _T("MMCN_EXPANDSYNC"); break;
|
|
case MMCN_COLUMNS_CHANGED: p = _T("MMCN_COLUMNS_CHANGED"); break;
|
|
case MMCN_CANPASTE_OUTOFPROC: p = _T("MMCN_CANPASTE_OUTOFPROC"); break;
|
|
default: p = _T("Unknown"); break;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern HRESULT
|
|
GetHelpTopic(LPOLESTR *lpCompiledHelpFile);
|
|
|
|
void CIISObject::DoRunOnce(
|
|
IN MMC_NOTIFY_TYPE event,
|
|
IN LPARAM arg,
|
|
IN LPARAM param
|
|
)
|
|
{
|
|
static bActivateCalled = FALSE;
|
|
static iSelectionCount = 0;
|
|
|
|
switch (event)
|
|
{
|
|
case MMCN_ACTIVATE:
|
|
{
|
|
bActivateCalled = TRUE;
|
|
}
|
|
case MMCN_SHOW:
|
|
{
|
|
if (!(g_dwInetmgrParamFlags & INETMGR_PARAM_RUNONCE_HAPPENED))
|
|
{
|
|
// only on the Root node
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cInternetRootNode))
|
|
{
|
|
// This RunOnce thing will only work
|
|
// if we select the container twice...
|
|
//
|
|
// after the second selection (which is really the 2nd MMCN_SHOW for the root item)
|
|
// it will stick....
|
|
//
|
|
// and this will only also work when the additonal runonce code in
|
|
// CIISRoot::EnumerateScopePane is executed...
|
|
if (bActivateCalled && iSelectionCount <= 1)
|
|
{
|
|
CIISRoot * pRoot = (CIISRoot *) this;
|
|
if (pRoot)
|
|
{
|
|
CIISMachine * pMach = pRoot->m_scServers.GetFirst();
|
|
if (pMach)
|
|
{
|
|
if (pMach->IsLocal())
|
|
{
|
|
CWebServiceExtensionContainer * pContainer = pMach->QueryWebSvcExtContainer();
|
|
if (pContainer)
|
|
{
|
|
if ((BOOL)arg)
|
|
{
|
|
pContainer->SelectScopeItem();
|
|
iSelectionCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iSelectionCount > 1)
|
|
{
|
|
// Set the flag to say we did runonce already!
|
|
SetInetmgrParamFlag(INETMGR_PARAM_RUNONCE_HAPPENED,TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::Notify(
|
|
IN MMC_NOTIFY_TYPE event,
|
|
IN LPARAM arg,
|
|
IN LPARAM param,
|
|
IN IComponentData * lpComponentData,
|
|
IN IComponent * lpComponent,
|
|
IN DATA_OBJECT_TYPES type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notification handler
|
|
|
|
Arguments:
|
|
|
|
MMC_NOTIFY_TYPE event : Notification type
|
|
long arg : Event-specific argument
|
|
long param : Event-specific parameter
|
|
IComponentData * pComponentData : IComponentData
|
|
IComponent * pComponent : IComponent
|
|
DATA_OBJECT_TYPES type : Data object type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
if (g_iDebugOutputLevel & DEBUG_FLAG_MMC_NOTIFY)
|
|
{
|
|
TRACEEOL("CIISObject::Notify -> " << ParseEvent(event));
|
|
}
|
|
|
|
static BOOL s_bLastEventSel = FALSE;
|
|
|
|
CError err(E_NOTIMPL);
|
|
ASSERT(lpComponentData != NULL || lpComponent != NULL);
|
|
|
|
// CComPtr<IConsole> lpConsole;
|
|
IConsole * lpConsole;
|
|
CComQIPtr<IHeaderCtrl, &IID_IHeaderCtrl> lpHeader;
|
|
CComQIPtr<IResultData, &IID_IResultData> lpResultData;
|
|
|
|
// Cache the passed in pointers
|
|
_lpComponent = lpComponent;
|
|
_lpComponentData = lpComponentData;
|
|
|
|
if (lpComponentData != NULL)
|
|
{
|
|
lpConsole = ((CInetMgr *)lpComponentData)->m_spConsole;
|
|
}
|
|
else
|
|
{
|
|
lpConsole = ((CInetMgrComponent *)lpComponent)->m_spConsole;
|
|
}
|
|
|
|
lpHeader = lpConsole;
|
|
lpResultData = lpConsole;
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
if (g_iDebugOutputLevel & DEBUG_FLAG_MMC_NOTIFY)
|
|
{
|
|
SCOPEDATAITEM si;
|
|
::ZeroMemory(&si, sizeof(SCOPEDATAITEM));
|
|
si.mask = SDI_PARAM;
|
|
si.ID = m_hScopeItem;
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
if (SUCCEEDED(pConsoleNameSpace->GetItem(&si)))
|
|
{
|
|
CIISObject * pNode = (CIISObject *)si.lParam;
|
|
DumpFriendlyName(pNode);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch (event)
|
|
{
|
|
|
|
case MMCN_ACTIVATE:
|
|
if (!(g_dwInetmgrParamFlags & INETMGR_PARAM_RUNONCE_HAPPENED))
|
|
{
|
|
DoRunOnce(event,arg,param);
|
|
}
|
|
err = S_OK;
|
|
break;
|
|
|
|
case MMCN_PROPERTY_CHANGE:
|
|
// err = OnPropertyChange((BOOL)arg, lpResultData);
|
|
TRACEEOLID("MMCN_PROPERTY_CHANGE");
|
|
break;
|
|
case MMCN_SHOW:
|
|
// The notification is sent to the snap-in's IComponent implementation
|
|
// when a scope item is selected or deselected.
|
|
//
|
|
// arg: TRUE if selecting. Indicates that the snap-in should set up the
|
|
// result pane and add the enumerated items. FALSE if deselecting.
|
|
// Indicates that the snap-in is going out of focus and that it
|
|
// should clean up all result item cookies, because the current
|
|
// result pane will be replaced by a new one.
|
|
// param: The HSCOPEITEM of the selected or deselected item.
|
|
if (m_fSkipEnumResult)
|
|
{
|
|
m_fSkipEnumResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!m_fFlaggedForDeletion)
|
|
{
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cWebServiceExtensionContainer))
|
|
{
|
|
CWebServiceExtensionContainer * pTemp = (CWebServiceExtensionContainer *) this;
|
|
if (pTemp)
|
|
{
|
|
err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,pTemp,FALSE,METABASE_PATH_FOR_RESTRICT_LIST);
|
|
}
|
|
if (err.Win32Error() == RPC_S_SERVER_UNAVAILABLE)
|
|
{
|
|
// if the Metabase is reconnected in EnumerateResultPane() during MMCN_SHOW
|
|
// then it will be hosed. don't enumerate this node
|
|
// and just let user hit refresh.
|
|
// create the column headers at least
|
|
err = CIISObject::EnumerateResultPane((BOOL)arg, lpHeader, lpResultData);
|
|
}
|
|
else
|
|
{
|
|
EnumerateResultPane((BOOL)arg, lpHeader, lpResultData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EnumerateResultPane((BOOL)arg, lpHeader, lpResultData);
|
|
}
|
|
|
|
}
|
|
}
|
|
if (!(g_dwInetmgrParamFlags & INETMGR_PARAM_RUNONCE_HAPPENED))
|
|
{
|
|
// Call runonce during the MMCN_SHOW
|
|
DoRunOnce(event,arg,param);
|
|
}
|
|
// Fail code will prevent MMC from enabling verbs
|
|
err.Reset();
|
|
break;
|
|
case MMCN_EXPAND:
|
|
{
|
|
#if defined(_DEBUG) || DBG
|
|
g_Debug_IISObject.Dump(0);
|
|
#endif
|
|
CWaitCursor wait;
|
|
if (!m_fFlaggedForDeletion)
|
|
{
|
|
err = EnumerateScopePane((HSCOPEITEM)param);
|
|
}
|
|
}
|
|
break;
|
|
case MMCN_ADD_IMAGES:
|
|
// The MMCN_ADD_IMAGES notification is sent to the snap-in's IComponent
|
|
// implementation to add images for the result pane.
|
|
//
|
|
// lpDataObject: [in] Pointer to the data object of the currently selected scope item.
|
|
// arg: Pointer to the result pane's image list (IImageList).
|
|
// This pointer is valid only while the specific MMCN_ADD_IMAGES notification is
|
|
// being processed and should not be stored for later use. Additionally, the
|
|
// snap-in must not call the Release method of IImageList because MMC is responsible
|
|
// for releasing it.
|
|
// param: Specifies the HSCOPEITEM of the currently selected scope item. The snap-in
|
|
// can use this parameter to add images that apply specifically to the result
|
|
// items of this scope item, or the snap-in can ignore this parameter and add
|
|
// all possible images.
|
|
err = AddImages((LPIMAGELIST)arg);
|
|
break;
|
|
case MMCN_DELETE:
|
|
err = DeleteNode(lpResultData);
|
|
break;
|
|
|
|
case MMCN_REMOVE_CHILDREN:
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
g_Debug_IISObject.Dump(0);
|
|
#endif
|
|
err = DeleteChildObjects((HSCOPEITEM)arg);
|
|
break;
|
|
|
|
case MMCN_VIEW_CHANGE:
|
|
// The MMCN_VIEW_CHANGE notification message is sent to the snap-in's
|
|
// IComponent implementation so it can update the view when a change occurs.
|
|
// This notification is generated when the snap-in (IComponent or IComponentData)
|
|
// calls IConsole2::UpdateAllViews.
|
|
//
|
|
// lpDataObject: [in] Pointer to the data object passed to IConsole::UpdateAllViews.
|
|
// arg: [in] The data parameter passed to IConsole::UpdateAllViews.
|
|
// param: [in] The hint parameter passed to IConsole::UpdateAllViews.
|
|
err = OnViewChange(type == CCT_SCOPE, lpResultData, lpHeader, (DWORD) param);
|
|
break;
|
|
|
|
case MMCN_REFRESH:
|
|
{
|
|
// The MMCN_REFRESH notification message is sent to a snap-in's IComponent
|
|
// implementation when the refresh verb is selected. Refresh can be invoked
|
|
// through the context menu, through the toolbar, or by pressing F5.
|
|
//
|
|
// lpDataObject: [in] Pointer to the data object of the currently selected scope item.
|
|
// arg: Not used.
|
|
// param: Not used.
|
|
|
|
// Refresh current node, and re-enumerate
|
|
// child nodes of the child nodes had previously
|
|
// been expanded.
|
|
|
|
// check if we're doing the IISMachine Node...
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cMachineNode))
|
|
{
|
|
CIISObject * pOpenItem = NULL;
|
|
if (g_OpenPropertySheetTracker.IsPropertySheetOpenComputer(this,FALSE,&pOpenItem))
|
|
{
|
|
g_OpenPropertySheetTracker.Dump();
|
|
if (pOpenItem)
|
|
{
|
|
HWND hHwnd = pOpenItem->IsMyPropertySheetOpen();
|
|
// a property sheet is open somewhere..
|
|
// make sure they close it before proceeding with refresh...
|
|
// Highlight the property sheet.
|
|
if (hHwnd && (hHwnd != (HWND) 1))
|
|
{
|
|
DoHelpMessageBox(NULL,IDS_CLOSE_ALL_PROPERTY_SHEET_REFRESH, MB_OK | MB_ICONINFORMATION, 0);
|
|
|
|
if (!SetForegroundWindow(hHwnd))
|
|
{
|
|
// wasn't able to bring this property sheet to
|
|
// the foreground, the propertysheet must not
|
|
// exist anymore. let's just clean the hwnd
|
|
// so that the user will be able to open propertysheet
|
|
pOpenItem->SetMyPropertySheetOpen(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL fReEnumerate = (!IsLeafNode() && IsExpanded());
|
|
if (fReEnumerate)
|
|
{
|
|
// Look for all of the open property sheets that are a child of
|
|
// this node, and orphan it (erase it's scope/result item info)
|
|
// so that it doesn't send a MMCNotify if the user hits ok
|
|
// (since there is nothing to update anyways and this MMCNotify cause AV).
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
INT iOrphans = g_OpenPropertySheetTracker.OrphanPropertySheetsBelowMe(pConsoleNameSpace,this,TRUE);
|
|
}
|
|
err = Refresh(fReEnumerate);
|
|
if (err.Succeeded() && HasResultItems(lpResultData))
|
|
{
|
|
err = CleanResult(lpResultData);
|
|
if (err.Succeeded())
|
|
{
|
|
// We should use fForRefresh = TRUE here, because MMC will add extra
|
|
// columns on refresh when result pane doesn't contain scope items.
|
|
if (!m_fFlaggedForDeletion)
|
|
{
|
|
err = EnumerateResultPane(TRUE, lpHeader, lpResultData, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// refresh the verbs
|
|
ASSERT_PTR(lpConsole);
|
|
CComPtr<IConsoleVerb> lpConsoleVerb;
|
|
lpConsole->QueryConsoleVerb(&lpConsoleVerb);
|
|
ASSERT_PTR(lpConsoleVerb);
|
|
if (lpConsoleVerb)
|
|
{
|
|
err = SetStandardVerbs(lpConsoleVerb);
|
|
}
|
|
|
|
// Refresh() will clean out the scope item
|
|
// Reselect the refreshed item.
|
|
if (!s_bLastEventSel)
|
|
{
|
|
// if the last selection event
|
|
// was not ended upon a "selection" but rather a "deselection"
|
|
// make force a selection...
|
|
SelectScopeItem();
|
|
}
|
|
}
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
// check if we leaked anything.
|
|
g_Debug_IISObject.Dump(2);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
{
|
|
// The MMCN_SELECT notification is sent to the snap-in's IComponent::Notify
|
|
// or IExtendControlbar::ControlbarNotify method when an item is selected in
|
|
// either the scope pane or result pane.
|
|
//
|
|
// lpDataObject: [in] Pointer to the data object of the currently
|
|
// selected/deselected scope pane or result item.
|
|
// arg: BOOL bScope = (BOOL) LOWORD(arg); BOOL bSelect = (BOOL) HIWORD(arg);
|
|
// bScope is TRUE if the selected item is a scope item, or FALSE if
|
|
// the selected item is a result item. For bScope = TRUE, MMC does
|
|
// not provide information about whether the scope item is selected
|
|
// in the scope pane or in the result pane. bSelect is TRUE if the
|
|
// item is selected, or FALSE if the item is deselected.
|
|
// param: ignored.
|
|
|
|
#if defined(_DEBUG) || DBG
|
|
g_Debug_IISObject.Dump(0);
|
|
#endif
|
|
BOOL bScope = (BOOL) LOWORD(arg);
|
|
BOOL bSelect = (BOOL) HIWORD(arg);
|
|
s_bLastEventSel = bSelect;
|
|
err.Reset();
|
|
|
|
//
|
|
// Item has been selected -- set verb states
|
|
//
|
|
if (bSelect)
|
|
{
|
|
SetToolBarStates(_lpToolBar);
|
|
|
|
ASSERT_PTR(lpConsole);
|
|
CComPtr<IConsoleVerb> lpConsoleVerb;
|
|
lpConsole->QueryConsoleVerb(&lpConsoleVerb);
|
|
ASSERT_PTR(lpConsoleVerb);
|
|
if (lpConsoleVerb)
|
|
{
|
|
err = SetStandardVerbs(lpConsoleVerb);
|
|
}
|
|
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cWebServiceExtensionContainer))
|
|
{
|
|
ForceReportMode(lpResultData);
|
|
}
|
|
|
|
// if it's the service node,
|
|
// check if we need to update it's icon (started/stopped)
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cServiceCollectorNode))
|
|
{
|
|
CIISService * pTemp = (CIISService *) this;
|
|
// Don't do this on every selection.
|
|
// The SMTP/NNTP nodes require user to select refresh
|
|
// to get the latest status of the server
|
|
// we don't want to stray too far from they're behavior
|
|
// otherwise, the user might think it should be that
|
|
// way for SMTP/NNTP as well...
|
|
pTemp->GetServiceState(); // ahh well...
|
|
if (pTemp->m_dwServiceStateDisplayed != pTemp->m_dwServiceState)
|
|
{
|
|
pTemp->RefreshDisplay(FALSE);
|
|
RefreshDisplay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MMCN_RENAME:
|
|
err = RenameItem((LPOLESTR)param);
|
|
break;
|
|
case MMCN_DBLCLICK:
|
|
// The MMCN_DBLCLICK notification is sent to the snap-in's IComponent
|
|
// implementation when a user double-clicks a mouse button on a list
|
|
// view item or on a scope item in the result pane. Pressing enter
|
|
// while the list item or scope item has focus in the list view also
|
|
// generates an MMCN_DBLCLICK notification message.
|
|
//
|
|
// lpDataObject: [in] Pointer to the data object of the currently selected item.
|
|
// arg: Not used.
|
|
// param: Not used.
|
|
err = OnDblClick(lpComponentData, lpComponent);
|
|
break;
|
|
case MMCN_COLUMNS_CHANGED:
|
|
err = ChangeVisibleColumns((MMC_VISIBLE_COLUMNS *)param);
|
|
break;
|
|
case MMCN_CONTEXTHELP:
|
|
{
|
|
LPOLESTR pCompiledHelpFile = NULL;
|
|
CError err(E_NOTIMPL);
|
|
err = GetHelpTopic(&pCompiledHelpFile);
|
|
if (err.Succeeded())
|
|
{
|
|
IDisplayHelp * pdh;
|
|
err = lpConsole->QueryInterface(IID_IDisplayHelp, (void **)&pdh);
|
|
if (err.Succeeded())
|
|
{
|
|
CString strDefault;
|
|
CString strHtmlPage;
|
|
CString topic = ::PathFindFileName(pCompiledHelpFile);
|
|
|
|
strDefault = GLOBAL_DEFAULT_HELP_PATH ;
|
|
if (SUCCEEDED(GetContextHelp(strHtmlPage)))
|
|
{
|
|
if (!strHtmlPage.IsEmpty())
|
|
{
|
|
strDefault = strHtmlPage;
|
|
}
|
|
}
|
|
topic += strDefault;
|
|
|
|
LPTSTR p = topic.GetBuffer(topic.GetLength());
|
|
err = pdh->ShowTopic(p);
|
|
topic.ReleaseBuffer();
|
|
pdh->Release();
|
|
}
|
|
}
|
|
err.MessageBoxOnFailure();
|
|
CoTaskMemFree(pCompiledHelpFile);
|
|
}
|
|
break;
|
|
default:
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (!err.Succeeded())
|
|
{
|
|
if (g_iDebugOutputLevel & DEBUG_FLAG_MMC_NOTIFY)
|
|
{
|
|
TRACEEOL("CIISObject::Notify -> " << ParseEvent(event) << " error " << err);
|
|
}
|
|
}
|
|
err.Reset();
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::GetContextHelp(CString& strHtmlPage)
|
|
{
|
|
strHtmlPage = GLOBAL_DEFAULT_HELP_PATH ;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::AddToScopePane(
|
|
IN HSCOPEITEM hRelativeID,
|
|
IN BOOL fChild,
|
|
IN BOOL fNext,
|
|
IN BOOL fIsParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add current object to console namespace. Either as the last child
|
|
of a parent item, or right before/after sibling item
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hRelativeID : Relative scope ID (either parent or sibling)
|
|
BOOL fChild : If TRUE, object will be added as child of
|
|
hRelativeID
|
|
BOOL fNext : If fChild is TRUE, this parameter is ignored
|
|
If fChild is FALSE, and fNext is TRUE,
|
|
object will be added before hRelativeID
|
|
If fChild is FALSE, and fNext is FALSE,
|
|
object will be added after hRelativeID
|
|
BOOL fIsParent : If TRUE, it will add the [+] to indicate
|
|
that this node may have childnodes.
|
|
|
|
Return Value
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwMask = fChild ? SDI_PARENT : fNext ? SDI_NEXT : SDI_PREVIOUS;
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
SCOPEDATAITEM scopeDataItem;
|
|
|
|
::ZeroMemory(&scopeDataItem, sizeof(SCOPEDATAITEM));
|
|
scopeDataItem.mask =
|
|
SDI_STR | SDI_IMAGE | SDI_CHILDREN | SDI_OPENIMAGE | SDI_PARAM | dwMask;
|
|
scopeDataItem.displayname = MMC_CALLBACK;
|
|
scopeDataItem.nImage = scopeDataItem.nOpenImage = MMC_IMAGECALLBACK;//QueryImage();
|
|
scopeDataItem.lParam = (LPARAM)this;
|
|
scopeDataItem.relativeID = hRelativeID;
|
|
scopeDataItem.cChildren = fIsParent ? 1 : 0;
|
|
HRESULT hr = pConsoleNameSpace->InsertItem(&scopeDataItem);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Cache the scope item handle
|
|
//
|
|
ASSERT(m_hScopeItem == NULL);
|
|
m_hScopeItem = scopeDataItem.ID;
|
|
// BUGBUG: looks like MMC_IMAGECALLBACK doesn't work in InsertItem. Update it here.
|
|
scopeDataItem.mask =
|
|
SDI_IMAGE | SDI_OPENIMAGE;
|
|
pConsoleNameSpace->SetItem(&scopeDataItem);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::AddToScopePaneSorted(
|
|
IN HSCOPEITEM hParent,
|
|
IN BOOL fIsParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add current object to console namespace, sorted in its proper location.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent object
|
|
BOOL fIsParent : If TRUE, it will add the [+] to indicate
|
|
that this node may have childnodes.
|
|
|
|
|
|
Return Value
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
|
|
//
|
|
// Find proper insertion point
|
|
//
|
|
BOOL fChild = TRUE;
|
|
HSCOPEITEM hChildItem = NULL;
|
|
CIISObject * pItem;
|
|
LONG_PTR cookie;
|
|
int nSwitch;
|
|
|
|
HRESULT hr = pConsoleNameSpace->GetChildItem(hParent, &hChildItem, &cookie);
|
|
|
|
while(SUCCEEDED(hr) && hChildItem)
|
|
{
|
|
//
|
|
// The cookie is really the IISObject, which is what we stuff
|
|
// in the lparam.
|
|
//
|
|
pItem = (CIISObject *)cookie;
|
|
ASSERT_PTR(pItem);
|
|
|
|
nSwitch = CompareScopeItem(pItem);
|
|
|
|
//
|
|
// Dups should be weeded out by now.
|
|
//
|
|
// ASSERT(nSwitch != 0);
|
|
|
|
if (nSwitch < 0)
|
|
{
|
|
//
|
|
// Insert before this item
|
|
//
|
|
fChild = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Advance to next child of same parent
|
|
//
|
|
hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
|
|
}
|
|
|
|
return AddToScopePane(hChildItem ? hChildItem : hParent, fChild, fIsParent);
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::RemoveScopeItem()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the current item from the scope view. This method is virtual
|
|
to allow derived classes to do cleanup.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT(m_hScopeItem != NULL);
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
m_fFlaggedForDeletion = TRUE;
|
|
|
|
//RemoveChildren(m_hScopeItem);
|
|
//DeleteChildObjects(m_hScopeItem);
|
|
HRESULT hr = pConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE);
|
|
// set our scope item to point to nothing in the MMC
|
|
ResetScopeItem();
|
|
ResetResultItem();
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::ChangeVisibleColumns(MMC_VISIBLE_COLUMNS * pCol)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::OnDblClick(IComponentData * pcd, IComponent * pc)
|
|
{
|
|
// Default action is to select this item on scope
|
|
return SelectScopeItem();
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::SelectScopeItem()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select this item in the scope view.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
// Fix for bug #519763. I found no way of getting hScope from MMC for the
|
|
// root item.
|
|
if (NULL != QueryScopeItem())
|
|
{
|
|
ASSERT(m_hScopeItem != NULL);
|
|
IConsole * pConsole = (IConsole *)GetConsole();
|
|
return pConsole->SelectScopeItem(m_hScopeItem);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::SetCookie()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store the cookie (a pointer to the current CIISObject) in the
|
|
scope view object associated with it.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT(m_hScopeItem != NULL);
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
SCOPEDATAITEM scopeDataItem;
|
|
|
|
::ZeroMemory(&scopeDataItem, sizeof(SCOPEDATAITEM));
|
|
scopeDataItem.mask = SDI_PARAM;
|
|
|
|
scopeDataItem.ID = m_hScopeItem;
|
|
scopeDataItem.lParam = (LPARAM)this;
|
|
|
|
return pConsoleNameSpace->SetItem(&scopeDataItem);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISObject::RefreshDisplay(BOOL bRefreshToolBar)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Refresh the display parameters of the current node.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value
|
|
|
|
HRESULT
|
|
|
|
Note: This does not fetch any configuration information from the metabase,
|
|
that's done in RefreshData();
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_hResultItem == 0)
|
|
{
|
|
if (bRefreshToolBar)
|
|
{
|
|
SetToolBarStates(_lpToolBar);
|
|
}
|
|
|
|
ASSERT(m_hScopeItem != NULL);
|
|
if (m_hScopeItem != NULL)
|
|
{
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
SCOPEDATAITEM scopeDataItem;
|
|
|
|
::ZeroMemory(&scopeDataItem, sizeof(SCOPEDATAITEM));
|
|
scopeDataItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE;
|
|
scopeDataItem.displayname = MMC_CALLBACK;
|
|
scopeDataItem.nImage = scopeDataItem.nOpenImage = QueryImage();
|
|
scopeDataItem.ID = m_hScopeItem;
|
|
|
|
hr = pConsoleNameSpace->SetItem(&scopeDataItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RESULTDATAITEM ri;
|
|
::ZeroMemory(&ri, sizeof(ri));
|
|
ri.itemID = m_hResultItem;
|
|
ri.mask = RDI_STR | RDI_IMAGE;
|
|
ri.str = MMC_CALLBACK;
|
|
ri.nImage = QueryImage();
|
|
IConsole * pConsole = (IConsole *)GetConsole();
|
|
CComQIPtr<IResultData, &IID_IResultData> pResultData(pConsole);
|
|
if (pResultData != NULL)
|
|
{
|
|
pResultData->SetItem(&ri);
|
|
}
|
|
}
|
|
ASSERT(SUCCEEDED(hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::DeleteChildObjects(
|
|
IN HSCOPEITEM hParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the iisobject pointers belonging to the descendants of the current
|
|
nodes. This is in response to a MMCN_REMOVE_CHILDREN objects typically,
|
|
and does not remove the scope nodes from the scope view (for that see
|
|
RemoveChildren())
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent scope item handle
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HSCOPEITEM hChildItem = NULL;
|
|
CIISObject * pItem = NULL;
|
|
LONG_PTR cookie = NULL;
|
|
void ** ppVoid = NULL;
|
|
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
HRESULT hr = pConsoleNameSpace->GetChildItem(hParent, &hChildItem, &cookie);
|
|
while(SUCCEEDED(hr) && hChildItem)
|
|
{
|
|
//
|
|
// The cookie is really the IISObject, which is what we stuff
|
|
// in the lparam.
|
|
//
|
|
pItem = (CIISObject *)cookie;
|
|
ppVoid = (void **) cookie;
|
|
ASSERT_PTR(pItem);
|
|
|
|
if (pItem)
|
|
{
|
|
// do this extra check since
|
|
// this cookie object for some reason could be gone already!
|
|
if (ppVoid && (*ppVoid))
|
|
{
|
|
if (pItem != this)
|
|
{
|
|
//
|
|
// Recursively commit infanticide
|
|
// call this objects DeleteChildObjects
|
|
//
|
|
pItem->m_fFlaggedForDeletion = TRUE;
|
|
|
|
//
|
|
// Mark the item as orphaned!!
|
|
pItem->ResetScopeItem();
|
|
pItem->ResetResultItem();
|
|
|
|
// recursively call on this items children...
|
|
pItem->DeleteChildObjects(hChildItem);
|
|
|
|
// this release will delete the object
|
|
pItem->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Advance to next child of same parent
|
|
//
|
|
hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
|
|
}
|
|
|
|
//
|
|
// BUGBUG: For some reason GetNextItem() returns 1
|
|
// when no more child items exist, not a true HRESULT
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*virtual*/
|
|
HRESULT
|
|
CIISObject::DeleteNode(IResultData * pResult)
|
|
{
|
|
ASSERT(IsDeletable());
|
|
return S_OK;
|
|
}
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::RemoveChildren(
|
|
IN HSCOPEITEM hParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Similar to DeleteChildObjects() this method will actually remove
|
|
the child nodes from the scope view.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent scope item handle
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HSCOPEITEM hChildItem, hItem;
|
|
CIISObject * pItem;
|
|
LONG_PTR cookie;
|
|
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
HRESULT hr = pConsoleNameSpace->GetChildItem(hParent, &hChildItem, &cookie);
|
|
while(SUCCEEDED(hr) && hChildItem)
|
|
{
|
|
//
|
|
// The cookie is really the IISObject, which is what we stuff
|
|
// in the lparam.
|
|
//
|
|
pItem = (CIISObject *)cookie;
|
|
ASSERT_PTR(pItem);
|
|
|
|
hItem = pItem ? hChildItem : NULL;
|
|
|
|
//
|
|
// Determine next sibling before killing current sibling
|
|
//
|
|
hr = pConsoleNameSpace->GetNextItem(hChildItem, &hChildItem, &cookie);
|
|
|
|
//
|
|
// Now delete the current item from the tree
|
|
//
|
|
if (hItem)
|
|
{
|
|
pItem->m_fFlaggedForDeletion = TRUE;
|
|
|
|
// get rid of it's scopeitem or result item...
|
|
// this true param should also try to free the item if it's not used.
|
|
hr = pConsoleNameSpace->DeleteItem(hItem, TRUE);
|
|
// set our scope item to point to nothing in the MMC
|
|
pItem->ResetScopeItem();
|
|
pItem->ResetResultItem();
|
|
|
|
//
|
|
// ISSUE: Why doesn't DeleteItem above call some sort of
|
|
// notification so that I don't have to do this?
|
|
//
|
|
|
|
// this release will delete the object
|
|
pItem->Release();
|
|
}
|
|
}
|
|
|
|
//
|
|
// BUGBUG: For some reason GetNextItem() returns 1
|
|
// when no more child items exist, not a true HRESULT
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::EnumerateResultPane(
|
|
BOOL fExpand,
|
|
IHeaderCtrl * lpHeader,
|
|
IResultData * lpResultData,
|
|
BOOL fForRefresh
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Enumerate or destroy the result pane.
|
|
|
|
Arguments:
|
|
BOOL fExpand : TRUE to create the result view,
|
|
FALSE to destroy it
|
|
IHeaderCtrl * lpHeader : Header control
|
|
IResultData * pResultData : Result view
|
|
BOOL fForRefresh : if true then we don't need to rebuild result view
|
|
|
|
Return Value:
|
|
HRESULT
|
|
--*/
|
|
{
|
|
if (fExpand)
|
|
{
|
|
if (lpHeader != NULL)
|
|
{
|
|
ASSERT_READ_PTR(lpHeader);
|
|
if (!fForRefresh)
|
|
{
|
|
InitializeChildHeaders(lpHeader);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Destroy child result items
|
|
//
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISObject::SetStandardVerbs(LPCONSOLEVERB lpConsoleVerb)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the standard MMC verbs based on the this object type
|
|
and state.
|
|
|
|
Arguments:
|
|
|
|
LPCONSOLEVERB lpConsoleVerb : Console verb interface
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
CError err;
|
|
ASSERT_READ_PTR(lpConsoleVerb);
|
|
|
|
//
|
|
// Set enabled/disabled verb states
|
|
//
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE);
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE);
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE);
|
|
|
|
// cWebServiceExtension needs special handling since it's different from a regular schope item.
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cWebServiceExtension))
|
|
{
|
|
if (UseCount() <= 1)
|
|
{
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, IsRenamable());
|
|
}
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, IsDeletable());
|
|
}
|
|
else
|
|
{
|
|
if (UseCount() <= 1)
|
|
{
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, IsRenamable());
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, IsDeletable());
|
|
}
|
|
}
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, IsRefreshable());
|
|
lpConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, IsConfigurable());
|
|
|
|
//
|
|
// Set default verb
|
|
//
|
|
if (IsConfigurable())
|
|
{
|
|
lpConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
|
|
}
|
|
|
|
if (IsOpenable())
|
|
{
|
|
lpConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CIISObject::FillCustomData(CLIPFORMAT cf, LPSTREAM pStream)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT
|
|
CIISObject::FillData(CLIPFORMAT cf, LPSTREAM pStream)
|
|
{
|
|
HRESULT hr = CSnapInItemImpl<CIISObject>::FillData(cf, pStream);
|
|
if (hr == DV_E_CLIPFORMAT)
|
|
{
|
|
hr = FillCustomData(cf, pStream);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// CIISRoot implementation
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CIISRoot::CIISRoot() :
|
|
m_fRootAdded(FALSE),
|
|
m_pMachine(NULL)
|
|
{
|
|
VERIFY(m_bstrDisplayName.LoadString(IDS_ROOT_NODE));
|
|
TRACEEOL("CIISRoot::CIISRoot");
|
|
}
|
|
|
|
CIISRoot::~CIISRoot()
|
|
{
|
|
TRACEEOL("CIISRoot::~CIISRoot");
|
|
}
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISRoot::EnumerateScopePane(
|
|
IN HSCOPEITEM hParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerate scope child items of the root object -- i.e. machine nodes.
|
|
The machine nodes are expected to have been filled by via the IPersist
|
|
methods.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent console handle
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
if (m_fIsExtension)
|
|
{
|
|
return EnumerateScopePaneExt(hParent);
|
|
}
|
|
//
|
|
// The CIISRoot item was not added in the conventional way.
|
|
// Cache the scope item handle, and set the cookie, so that
|
|
// GetRoot() will work for child objects.
|
|
//
|
|
ASSERT(m_hScopeItem == NULL);
|
|
m_hScopeItem = hParent;
|
|
|
|
CError err(SetCookie());
|
|
|
|
if (err.Failed())
|
|
{
|
|
//
|
|
// We're in deep trouble. For some reason, we couldn't
|
|
// store the CIISRoot cookie in the scope view. That
|
|
// means anything depending on fetching the root object
|
|
// isn't going to work. Cough up a hairball, and bail
|
|
// out now.
|
|
//
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
ASSERT_MSG("Unable to cache root object");
|
|
err.MessageBox();
|
|
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Expand the computer cache
|
|
//
|
|
if (m_scServers.IsEmpty())
|
|
{
|
|
//
|
|
// Try to create the local machine
|
|
//
|
|
CIISMachine * pLocal = new CIISMachine(GetConsoleNameSpace(),GetConsole());
|
|
|
|
if (pLocal)
|
|
{
|
|
//
|
|
// Verify the machine object is created.
|
|
//
|
|
err = CIISMachine::VerifyMachine(pLocal);
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
TRACEEOLID("Added local computer to cache: ");
|
|
m_scServers.Add(pLocal);
|
|
}
|
|
|
|
err.Reset();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add each cached server to the view...
|
|
//
|
|
CIISMachine * pMachine = m_scServers.GetFirst();
|
|
|
|
while (pMachine)
|
|
{
|
|
TRACEEOLID("Adding " << pMachine->QueryServerName() << " to scope pane");
|
|
pMachine->AddRef();
|
|
err = pMachine->AddToScopePane(hParent);
|
|
|
|
// Do for runonce
|
|
if (!(g_dwInetmgrParamFlags & INETMGR_PARAM_RUNONCE_HAPPENED))
|
|
{
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
|
|
if (pConsoleNameSpace)
|
|
{
|
|
// expand under the covers...
|
|
pConsoleNameSpace->Expand(pMachine->QueryScopeItem());
|
|
}
|
|
}
|
|
|
|
if (err.Failed())
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMachine = m_scServers.GetNext();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISRoot::EnumerateScopePaneExt(HSCOPEITEM hParent)
|
|
{
|
|
CError err;
|
|
ASSERT(m_scServers.IsEmpty());
|
|
if (!m_fRootAdded)
|
|
{
|
|
CComAuthInfo auth(m_ExtMachineName);
|
|
m_pMachine = new CIISMachine(GetConsoleNameSpace(),GetConsole(),&auth, this);
|
|
if (m_pMachine != NULL)
|
|
{
|
|
m_pMachine->AddRef();
|
|
err = m_pMachine->AddToScopePane(hParent);
|
|
m_fRootAdded = err.Succeeded();
|
|
ASSERT(m_hScopeItem == NULL);
|
|
m_hScopeItem = m_pMachine->QueryScopeItem();
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
ExtractComputerNameExt(
|
|
IDataObject * pDataObject,
|
|
CString& strComputer)
|
|
{
|
|
//
|
|
// Find the computer name from the ComputerManagement snapin
|
|
//
|
|
CLIPFORMAT CCF_MyComputMachineName = (CLIPFORMAT)RegisterClipboardFormat(MYCOMPUT_MACHINE_NAME);
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC formatetc = {
|
|
CCF_MyComputMachineName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL
|
|
};
|
|
|
|
//
|
|
// Allocate memory for the stream
|
|
//
|
|
int len = MAX_PATH;
|
|
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);
|
|
if(stgmedium.hGlobal == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
HRESULT hr = pDataObject->GetDataHere(&formatetc, &stgmedium);
|
|
ASSERT(SUCCEEDED(hr));
|
|
//
|
|
// Get the computer name
|
|
//
|
|
strComputer = (LPTSTR)stgmedium.hGlobal;
|
|
|
|
GlobalFree(stgmedium.hGlobal);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISRoot::InitAsExtension(IDataObject * pDataObject)
|
|
{
|
|
ASSERT(!m_fIsExtension);
|
|
m_fIsExtension = TRUE;
|
|
CString buf;
|
|
return ExtractComputerNameExt(pDataObject, m_ExtMachineName);
|
|
}
|
|
|
|
HRESULT
|
|
CIISRoot::ResetAsExtension()
|
|
{
|
|
ASSERT(m_fIsExtension);
|
|
CIISObject::m_fIsExtension = FALSE;
|
|
// Remove machine node from the scope
|
|
CError err = RemoveScopeItem();
|
|
m_hScopeItem = NULL;
|
|
// Delete machine object
|
|
m_pMachine->Release();
|
|
m_pMachine = NULL;
|
|
m_fRootAdded = FALSE;
|
|
// Empty machine name
|
|
m_ExtMachineName.Empty();
|
|
// clean out
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISRoot::DeleteChildObjects(
|
|
IN HSCOPEITEM hParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need this method for extension case. CompMgmt send this event when
|
|
snapin is connected to another machine. We should clean all computer relevant
|
|
stuff from here and the root, because after that we will get MMCN_EXPAND, as
|
|
at the very beginning of extension cycle.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent scope item handle
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (m_pMachine != NULL)
|
|
{
|
|
m_pMachine->AddRef();
|
|
m_pMachine->DeleteChildObjects(m_hScopeItem);
|
|
m_pMachine->ResetScopeItem();
|
|
m_pMachine->ResetResultItem();
|
|
m_pMachine->m_MachineWNetConnections.Clear();
|
|
m_pMachine->Release();
|
|
}
|
|
else
|
|
{
|
|
CIISMachine * pMachine = m_scServers.GetFirst();
|
|
while (pMachine)
|
|
{
|
|
hr = pMachine->DeleteChildObjects(pMachine->QueryScopeItem());
|
|
pMachine->ResetScopeItem();
|
|
pMachine->ResetResultItem();
|
|
pMachine->m_MachineWNetConnections.Clear();
|
|
m_scServers.Remove(pMachine);
|
|
pMachine->Release();
|
|
pMachine = m_scServers.GetNext();
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr) && m_fIsExtension)
|
|
{
|
|
hr = ResetAsExtension();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* virtual */
|
|
void
|
|
CIISRoot::InitializeChildHeaders(
|
|
IN LPHEADERCTRL lpHeader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build result view for immediate descendant type
|
|
|
|
Arguments:
|
|
|
|
LPHEADERCTRL lpHeader : Header control
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!m_fIsExtension);
|
|
CIISMachine::InitializeHeaders(lpHeader);
|
|
}
|
|
|
|
HRESULT
|
|
CIISRoot::FillCustomData(CLIPFORMAT cf, LPSTREAM pStream)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/* virtual */
|
|
LPOLESTR
|
|
CIISRoot::GetResultPaneColInfo(int nCol)
|
|
{
|
|
if (nCol == 0)
|
|
{
|
|
return QueryDisplayName();
|
|
}
|
|
else if (nCol == 1)
|
|
{
|
|
}
|
|
else if (nCol == 2)
|
|
{
|
|
}
|
|
return OLESTR("");
|
|
}
|
|
|
|
HRESULT CheckForMetabaseAccess(DWORD dwPermissions,
|
|
CIISMBNode * pIISMBNode,
|
|
BOOL bReConnect,
|
|
LPCTSTR path)
|
|
{
|
|
CMetaKey * pKey = NULL;
|
|
CMetaInterface * pMyInterface = NULL;
|
|
CError err;
|
|
BOOL fContinue = TRUE;
|
|
|
|
if (!pIISMBNode)
|
|
{
|
|
err = E_POINTER;
|
|
goto CheckForMetabaseAccess_Exit;
|
|
}
|
|
|
|
// Check if we have a metabase access first...
|
|
while (fContinue)
|
|
{
|
|
fContinue = FALSE;
|
|
pMyInterface = pIISMBNode->QueryInterface();
|
|
if (pMyInterface)
|
|
{
|
|
if (dwPermissions != 0)
|
|
{
|
|
// METADATA_PERMISSION_READ
|
|
pKey = new CMetaKey(pMyInterface, path, dwPermissions);
|
|
}
|
|
else
|
|
{
|
|
pKey = new CMetaKey(pMyInterface, path);
|
|
}
|
|
|
|
if (NULL == pKey)
|
|
{
|
|
TRACEEOLID("RefreshData: Out Of Memory");
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
err = pKey->QueryResult();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = RPC_S_SERVER_UNAVAILABLE;
|
|
}
|
|
if (pIISMBNode->IsLostInterface(err))
|
|
{
|
|
if (bReConnect)
|
|
{
|
|
SAFE_DELETE(pKey);
|
|
fContinue = pIISMBNode->OnLostInterface(err);
|
|
}
|
|
else
|
|
{
|
|
fContinue = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SAFE_DELETE(pKey);
|
|
|
|
CheckForMetabaseAccess_Exit:
|
|
return err;
|
|
}
|
|
|
|
HRESULT CheckForMetabaseAccess(DWORD dwPermissions,
|
|
CMetaInterface * pMyInterface,
|
|
LPCTSTR path)
|
|
{
|
|
CMetaKey * pKey = NULL;
|
|
CError err;
|
|
|
|
if (!pMyInterface)
|
|
{
|
|
err = RPC_S_SERVER_UNAVAILABLE;
|
|
goto CheckForMetabaseAccess_Exit;
|
|
}
|
|
|
|
// Check if we have a metabase access...
|
|
if (dwPermissions != 0)
|
|
{
|
|
// METADATA_PERMISSION_READ
|
|
pKey = new CMetaKey(pMyInterface, path, dwPermissions);
|
|
}
|
|
else
|
|
{
|
|
pKey = new CMetaKey(pMyInterface, path);
|
|
}
|
|
|
|
if (NULL == pKey)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
err = pKey->QueryResult();
|
|
}
|
|
SAFE_DELETE(pKey);
|
|
|
|
CheckForMetabaseAccess_Exit:
|
|
return err;
|
|
}
|