Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

7192 lines
138 KiB

/*++
Copyright (c) 1994-1998 Microsoft Corporation
Module Name :
cinetmgr.cpp
Abstract:
Snapin object
Author:
Ronald Meijer (ronaldm)
Project:
Internet Services Manager
Revision History:
--*/
//
// Include Files
//
#include "stdafx.h"
#include "inetmgr.h"
#include "cinetmgr.h"
#include "connects.h"
#include "dataobj.h"
#include "afxdlgs.h"
#include "constr.h"
#include "metaback.h"
#include "shutdown.h"
#include <shlwapi.h>
#if !MSDEV_BUILD
//
// An odd difference between vc++ and sdk environments.
//
#include <atlimpl.cpp>
#endif !MSDEV_BUILD
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//
// Image background colour for the toolbar buttons
//
#define RGB_BK_IMAGES (RGB(255,0,255)) // purple
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
static HRESULT
GetSnapinHelpFile(LPOLESTR * lpCompiledHelpFile);
//
// Toolbar Definition. String IDs for menu and tooltip text will be resolved at initialization
//
static MMCBUTTON SnapinButtons[] =
{
{ IDM_CONNECT - 1, IDM_CONNECT, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_MENU_CONNECT, (BSTR)IDS_MENU_TT_CONNECT },
// { IDM_DISCOVER - 1, IDM_DISCOVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_MENU_DISCOVER, (BSTR)IDS_MENU_TT_CONNECT },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, _T(" "), _T("") },
{ IDM_START - 1, IDM_START, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_MENU_START, (BSTR)IDS_MENU_TT_START },
{ IDM_STOP - 1, IDM_STOP, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_MENU_STOP, (BSTR)IDS_MENU_TT_STOP },
{ IDM_PAUSE - 1, IDM_PAUSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_MENU_PAUSE, (BSTR)IDS_MENU_TT_PAUSE },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, _T(" "), _T("") },
//
// Add-on tools come here
//
};
#define NUM_BUTTONS (ARRAYLEN(SnapinButtons))
#define NUM_BITMAPS (5)
//
// Name of our taskpad group
//
const LPCTSTR g_cszTaskGroup = _T("CMTP1");
template <class TYPE>
TYPE * Extract(
IN LPDATAOBJECT lpDataObject,
IN unsigned int cf,
IN int len = -1
)
/*++
Routine Description:
Template function to extract information of type TYPE from the data object
Arguments:
LPDATAOBJECT lpDataObject : Data object to extract data from
unsigned int cf : Clipboard format describing the info type
Return Value:
Pointer to type TYPE
--*/
{
ASSERT(lpDataObject != NULL);
TYPE * p = NULL;
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
FORMATETC formatetc =
{
(CLIPFORMAT)cf,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
//
// Allocate memory for the stream
//
if (len < 0)
{
len = sizeof(TYPE);
}
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);
do
{
if (stgmedium.hGlobal == NULL)
{
break;
}
HRESULT hr = lpDataObject->GetDataHere(&formatetc, &stgmedium);
if (FAILED(hr))
{
break;
}
p = (TYPE *)stgmedium.hGlobal;
if (p == NULL)
{
break;
}
}
while (FALSE);
return p;
}
//
// Data object extraction helpers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/*
BOOL
IsMMCMultiSelectDataObject(
IN LPDATAOBJECT lpDataObject
)
{
if (lpDataObject == NULL)
{
return FALSE;
}
static UINT s_cf = 0;
if (s_cf == 0)
{
//
// Multi-select clipboard format not registered -- do it now
//
s_cf = RegisterClipboardFormat(CCF_MMC_MULTISELECT_DATAOBJECT);
}
FORMATETC fmt = {s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
return (lpDataObject->QueryGetData(&fmt) == S_OK);
}
*/
CLSID *
ExtractClassID(
IN LPDATAOBJECT lpDataObject
)
{
return Extract<CLSID>(lpDataObject, CDataObject::m_cfCoClass);
}
GUID *
ExtractNodeType(
IN LPDATAOBJECT lpDataObject
)
{
return Extract<GUID>(lpDataObject, CDataObject::m_cfNodeType);
}
wchar_t *
ExtractMachineName(
IN LPDATAOBJECT lpDataObject
)
{
wchar_t * lpszMachineName = Extract<wchar_t>(
lpDataObject,
CDataObject::m_cfISMMachineName,
(MAX_PATH + 1) * sizeof(wchar_t)
);
if (lpszMachineName == NULL)
{
//
// This is an extension -- grab the computer management
// name instead.
//
lpszMachineName = Extract<wchar_t>(
lpDataObject,
CDataObject::m_cfMyComputMachineName,
(MAX_PATH + 1) * sizeof(wchar_t)
);
}
return lpszMachineName;
}
INTERNAL *
ExtractInternalFormat(
IN LPDATAOBJECT lpDataObject
)
{
ASSERT(lpDataObject != NULL);
return Extract<INTERNAL>(lpDataObject, CDataObject::m_cfInternal);
}
//
// IEnumTask Implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CEnumTasks::CEnumTasks()
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
N/A
--*/
: m_pObject(NULL)
{
}
CEnumTasks::~CEnumTasks()
/*++
Routine Description:
Destructor
Arguments:
None
Return Value:
None
--*/
{
}
HRESULT
CEnumTasks::Next(
IN ULONG celt,
IN MMC_TASK * rgelt,
IN ULONG * pceltFetched
)
/*++
Routine Description:
Add next task to taskpad
Arguments:
ULONG celt,
MMC_TASK * rgelt,
ULONG * pceltFetched
Return Value:
HRESULT
--*/
{
//
// Callee fills MMC_TASK elements (via CoTaskMemAlloc)
//
ASSERT(!IsBadWritePtr(rgelt, celt * sizeof(MMC_TASK)));
if (m_pObject == NULL)
{
//
// Must be at the snap-in's root handle
//
return S_FALSE;
}
//
// celt will actually always only be 1
//
ASSERT(celt == 1);
HRESULT hr = S_FALSE;
for (ULONG i = 0; i < celt; ++i)
{
MMC_TASK * task = &rgelt[i];
hr = m_pObject->AddNextTaskpadItem(task);
if (FAILED(hr))
{
if (pceltFetched)
{
*pceltFetched = i;
}
break;
}
}
//
// If we get here all is well
//
if(pceltFetched)
{
*pceltFetched = celt;
}
return hr;
}
HRESULT
CEnumTasks::Skip(
IN ULONG celt
)
/*++
Routine Description:
Skip the task index
Arguments:
ULONG celt : Number of tasks to skip
Return Value:
HRESULT
--*/
{
return E_NOTIMPL;
}
HRESULT
CEnumTasks::Reset()
/*++
Routine Description:
Result the taskpad enumeration index
Arguments:
None
Return Value:
HRESULT
--*/
{
return E_NOTIMPL;
}
HRESULT
CEnumTasks::Clone(
IN IEnumTASK ** ppenum
)
/*++
Routine Description:
Close a task -- obsolete, no longer supported by mmc
Arguments:
IEnumTASK ** ppenum : Source task to clone
Return Value:
HRESULT
--*/
{
return E_NOTIMPL;
}
HRESULT
CEnumTasks::Init(
IN IDataObject * pdo,
IN LPOLESTR szTaskGroup
)
/*++
Routine Description:
Here is where we see what taskpad we are providing tasks for.
In our case we know that we only have one taskpad.
The string we test for is "CMTP1". This was the string following
the '#' that we passed in GetResultViewType.
Arguments:
IDataObject * pdo : Data object
LPOLESTR szTaskGroup : Taskpad group name
Return Value:
HRESULT
--*/
{
//
// Return ok if we can handle data object and group.
//
if (!lstrcmp(szTaskGroup, g_cszTaskGroup))
{
//
// CODEWORK: How about a helper for this!
//
INTERNAL * pInternal = ExtractInternalFormat(pdo);
if (pInternal == NULL)
{
//
// Extension
//
return S_OK;
}
m_pObject = (CIISObject *)pInternal->m_cookie;
return S_OK;
}
//
// Should never happen
//
ASSERT(FALSE);
return S_FALSE;
}
//
// CSnapin class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin);
long CSnapin::lDataObjectRefCount = 0;
CSnapin::CSnapin()
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
N/A
--*/
: m_pConsole(NULL),
m_pHeader(NULL),
m_pResult(NULL),
m_pImageResult(NULL),
m_pComponentData(NULL),
m_pToolbar(NULL),
m_pControlbar(NULL),
m_pbmpToolbar(NULL),
m_pConsoleVerb(NULL),
m_oblResultItems(),
m_strlRef(),
m_fTaskView(FALSE),
m_fSettingsChanged(FALSE),
m_fIsExtension(FALSE),
m_fWinSockInit(FALSE)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin);
#ifdef _DEBUG
dbg_cRef = 0;
#endif // _DEBUG
}
CSnapin::~CSnapin()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
#ifdef _DEBUG
ASSERT(dbg_cRef == 0);
#endif // _DEBUG
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);
SAFE_RELEASE(m_pToolbar);
SAFE_RELEASE(m_pControlbar);
//
// Make sure the interfaces have been released
//
ASSERT(m_pConsole == NULL);
ASSERT(m_pHeader == NULL);
ASSERT(m_pToolbar == NULL);
if (m_pbmpToolbar)
{
m_pbmpToolbar->DeleteObject();
delete m_pbmpToolbar;
}
//
// Should have been removed via notification, but just in case:
//
ASSERT(m_oblResultItems.GetCount() == 0);
m_oblResultItems.RemoveAll();
}
LPTSTR
CSnapin::StringReferenceFromResourceID(
IN UINT nID
)
/*++
Routine Description:
Load a string from the resource segment, add it to the internal
string table, and return a pointer to it. The pointer will be
valid for the entire scope of the CSnapin object
Arguments
UINT nID : Resource ID
Return Value:
A pointer to the string.
--*/
{
CString str;
VERIFY(str.LoadString(nID));
m_strlRef.AddTail(str);
CString & strRef = m_strlRef.GetAt(m_strlRef.GetTailPosition());
return (LPTSTR)(LPCTSTR)strRef;
}
BOOL
CSnapin::IsEnumerating(
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Return TRUE if we are enumerating our main folder
Arguments:
LPDATAOBJECT lpDataObject : Data object
Return Value:
TRUE if we are enumerating our main folder, FALSE if not
--*/
{
BOOL bResult = FALSE;
ASSERT(lpDataObject);
GUID * nodeType = ExtractNodeType(lpDataObject);
//
// Is this my main node (static folder node type)
//
bResult = ::IsEqualGUID(*nodeType, cInternetRootNode);
//
// Free resources
//
FREE_DATA(nodeType);
return bResult;
}
//
// CSnapin's IComponent implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CSnapin::GetResultViewType(
IN MMC_COOKIE cookie,
OUT BSTR * ppViewType,
OUT long * pViewOptions
)
/*++
Routine Description:
Tell MMC what our result view looks like
Arguments:
MMC_COOKIE cookie : Currently selected cookie
BSTR * ppViewType : Return view type here
long * pViewOptions : View options
Return Value:
S_FALSE to use default view type, S_OK indicates the
view type is returned in *ppViewType
--*/
{
//
// Taskpads not supported for beta2
//
#if TASKPADS_SUPPORTED
if (m_fTaskView)
{
//
// We will use the default DHTML provided by MMC. It actually
// resides as a resource inside MMC.EXE. We just get the path
// to it and use that.
//
// The one piece of magic here is the text following the '#'. That
// is the special way we have of identifying they taskpad we are
// talking about. Here we say we are wanting to show a taskpad
// that we refer to as "CMTP1". We will actually see this string
// pass back to us later. If someone is extending our taskpad,
// they also need to know what this secret string is.
//
*pViewOptions = MMC_VIEW_OPTIONS_NONE;
CString strResURL;
HRESULT hr = BuildResURL(strResURL, NULL);
if (FAILED(hr))
{
return hr;
}
strResURL += _T("/default.htm#");
strResURL += g_cszTaskGroup;
TRACEEOLID("Taskpad URL is " << strResURL);
*ppViewType = CoTaskDupString((LPCOLESTR)strResURL);
return S_OK;
}
#endif // TASKPADS_SUPPORTED
//
// Use default view
//
*pViewOptions = MMC_VIEW_OPTIONS_USEFONTLINKING;
//*pViewOptions = MMC_VIEW_OPTIONS_USEFONTLINKING
// | MMC_VIEW_OPTIONS_LEXICAL_SORT;
return S_FALSE;
}
STDMETHODIMP
CSnapin::Initialize(
IN LPCONSOLE lpConsole
)
/*++
Routine Description:
Initialize the console
Arguments"
LPCONSOLE lpConsole : Pointer to console
Return Value:
HRESULT
--*/
{
ASSERT(lpConsole != NULL);
::AfxEnableControlContainer();
//
// Initialize IISUI extension DLL
//
#ifndef _COMSTATIC
//
// Initialize IISUI extension DLL
//
InitIISUIDll();
#endif // _COMSTATIC
//
// Initialise winsock
//
// ISSUE: If proxy is installed, this might take a long time
// if the proxy server is in a hung state.
//
WSADATA wsaData;
m_fWinSockInit = (::WSAStartup(MAKEWORD(1, 1), &wsaData) == 0);
//
// Save the IConsole pointer
//
m_pConsole = lpConsole;
m_pConsole->AddRef();
//
// Load resource strings
//
LoadResources();
//
// QI for a IHeaderCtrl
//
HRESULT hr = m_pConsole->QueryInterface(
IID_IHeaderCtrl,
(void **)&m_pHeader
);
//
// Give the console the header control interface pointer
//
if (SUCCEEDED(hr))
{
m_pConsole->SetHeader(m_pHeader);
}
m_pConsole->QueryInterface(
IID_IResultData,
(void **)&m_pResult
);
m_pConsole->QueryResultImageList(&m_pImageResult);
m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
//
// Resolve tool tips texts
//
CString str;
static BOOL fInitialised = FALSE;
if (!fInitialised)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
for (int i = 0; i < NUM_BUTTONS; ++i)
{
if (SnapinButtons[i].idCommand != 0)
{
SnapinButtons[i].lpButtonText = StringReferenceFromResourceID(
(UINT)PtrToUlong(SnapinButtons[i].lpButtonText));
SnapinButtons[i].lpTooltipText = StringReferenceFromResourceID(
(UINT)PtrToUlong(SnapinButtons[i].lpTooltipText));
}
}
fInitialised = TRUE;
}
return S_OK;
}
STDMETHODIMP
CSnapin::Notify(
IN LPDATAOBJECT lpDataObject,
IN MMC_NOTIFY_TYPE event,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Notification handler
Arguments:
LPDATAOBJECT lpDataObject : Data object
MMC_NOTIFY_TYPE event : Event
LPARAM arg : Argument
LPARAM param : Parameter
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
INTERNAL * pInternal = NULL;
MMC_COOKIE cookie;
switch(event)
{
case MMCN_REFRESH:
case MMCN_RENAME:
//
// Delegate it to the IComponentData
//
ASSERT(m_pComponentData != NULL);
hr = m_pComponentData->Notify(lpDataObject, event, arg, param);
case MMCN_PROPERTY_CHANGE:
hr = OnPropertyChange(lpDataObject);
break;
case MMCN_DELETE:
//
// Let IComponentData do the deletion, then refresh the parent object
//
ASSERT(m_pComponentData != NULL);
hr = m_pComponentData->Notify(lpDataObject, event, arg, param);
m_pComponentData->Notify(lpDataObject, MMCN_REFRESH, arg, param);
case MMCN_VIEW_CHANGE:
hr = OnUpdateView(lpDataObject);
break;
case MMCN_SNAPINHELP:
case MMCN_CONTEXTHELP:
{
LPOLESTR pCompiledHelpFile = NULL;
if (SUCCEEDED(hr = GetSnapinHelpFile(&pCompiledHelpFile)))
{
IDisplayHelp * pdh;
if (SUCCEEDED(hr = m_pConsole->QueryInterface(
IID_IDisplayHelp, (void **)&pdh)))
{
CString topic = PathFindFileName(pCompiledHelpFile);
topic += _T("::/iint1.htm");
LPTSTR p = topic.GetBuffer(topic.GetLength());
hr = pdh->ShowTopic(p);
topic.ReleaseBuffer();
pdh->Release();
}
}
if (FAILED(hr))
{
CError err(hr);
err.MessageBoxOnFailure();
}
CoTaskMemFree(pCompiledHelpFile);
}
break;
default:
//
// don't process the internal format if the dataobject is null.
//
if (lpDataObject == NULL)
{
return S_OK;
}
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal == NULL)
{
//
// Extension
//
TRACEEOLID("This is an (CSnapin) EXTENSION");
cookie = NULL;
CIISObject::m_fIsExtension = m_fIsExtension = TRUE;
}
else
{
cookie = pInternal->m_cookie;
FREE_DATA(pInternal);
}
switch(event)
{
case MMCN_CLICK:
case MMCN_DBLCLICK:
hr = OnResultItemClkOrDblClk(cookie, (event == MMCN_DBLCLICK));
break;
case MMCN_ADD_IMAGES:
OnAddImages(cookie, arg, param);
break;
case MMCN_SHOW:
hr = OnShow(cookie, arg, param);
break;
case MMCN_ACTIVATE:
hr = OnActivate(cookie, arg, param);
break;
case MMCN_MINIMIZED:
hr = OnMinimize(cookie, arg, param);
break;
case MMCN_BTN_CLICK:
break;
case MMCN_SELECT:
HandleStandardVerbs(arg, lpDataObject);
break;
case MMCN_COLUMN_CLICK:
break;
case MMCN_MENU_BTNCLICK:
break;
default:
ASSERT(FALSE); // Handle new messages
hr = E_UNEXPECTED;
break;
}
}
return hr;
}
STDMETHODIMP
CSnapin::Destroy(
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Destruction handler
Arguments:
MMC_COOKIE cookie : Currently selected cookie
Return Value:
HRESULT
--*/
{
//
// Release the interfaces that we QI'ed
//
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (m_pConsole != NULL)
{
//
// Tell the console to release the header control interface
//
m_pConsole->SetHeader(NULL);
SAFE_RELEASE_SETTONULL(m_pHeader);
SAFE_RELEASE_SETTONULL(m_pResult);
SAFE_RELEASE_SETTONULL(m_pImageResult);
SAFE_RELEASE_SETTONULL(m_pConsole);
SAFE_RELEASE_SETTONULL(m_pComponentData);
SAFE_RELEASE_SETTONULL(m_pConsoleVerb);
SAFE_RELEASE_SETTONULL(m_pToolbar);
SAFE_RELEASE_SETTONULL(m_pControlbar);
}
//
// Terminate use of the WinSock routines.
//
if (m_fWinSockInit)
{
::WSACleanup();
m_fWinSockInit = FALSE;
}
//
// Everything OK
//
return S_OK;
}
STDMETHODIMP
CSnapin::QueryDataObject(
IN MMC_COOKIE cookie,
IN DATA_OBJECT_TYPES type,
OUT LPDATAOBJECT * ppDataObject
)
/*++
Routine Description:
Get dataobject info
Arguments:
MMC_COOKIE cookie : cookie
DATA_OBJECT_TYPES : Data object type
LPDATAOBJECT * : Returns the data object
Return Value:
HRESULT
--*/
{
//
// Delegate it to the IComponentData
//
ASSERT(m_pComponentData != NULL);
return m_pComponentData->QueryDataObject(cookie, type, ppDataObject);
}
void
CSnapin::LoadResources()
/*++
Routine Description:
Load resource belong to the main snapin
Arguments:
None
Return Value:
None
--*/
{
//
// Load strings from resources
//
}
//
// IExtendPropertySheet Implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CSnapin::CreatePropertyPages(
IN LPPROPERTYSHEETCALLBACK lpProvider,
IN LONG_PTR handle,
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Create the property pages for the given object
Arguments:
LPPROPERTYSHEETCALLBACK lpProvider : Provider
LONG_PTR handle : Handle
LPDATAOBJECT lpDataObject : Data object
Return Value:
HRESULT
--*/
{
return static_cast<CComponentDataImpl *>(m_pComponentData)->CreatePropertyPages(
lpProvider,
handle,
lpDataObject
);
}
STDMETHODIMP
CSnapin::QueryPagesFor(
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Check to see if a property sheet should be brought up for this data
object
Arguments:
LPDATAOBJECT lpDataObject : Data object
Return Value:
S_OK, if properties may be brought up for this item, S_FALSE otherwise
--*/
{
return static_cast<CComponentDataImpl *>(m_pComponentData)->QueryPagesFor(
lpDataObject
);
}
HRESULT
CSnapin::InitializeHeaders(
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Initialize the result view headers for this cookie
Arguments:
MMC_COOKIE cookie : Current cookie
Return Value:
HRESULT
--*/
{
CIISObject * pObject = (CIISObject *)cookie;
//
// The result pane is always one level behind the scope pane
// for a folder object
//
if (pObject == NULL)
{
CIISMachine::InitializeHeaders(m_pHeader);
}
else
{
pObject->InitializeChildHeaders(m_pHeader);
}
return S_OK;
}
class CImage : public CObjectPlus
/*++
Class Description:
A structure to tie a bitmap together with a background
colour mask
Public Interface:
CImage : Constructor
~CImage : Destructor
Notes: This image owns the bitmap and will delete it upon
destruction.
--*/
{
//
// Constructor/Destructor
//
public:
CImage(
IN CBitmap * pbmp,
IN COLORREF rgb
)
: m_pbmp(pbmp),
m_rgb(rgb)
{
}
~CImage()
{
ASSERT(m_pbmp != NULL);
m_pbmp->DeleteObject();
delete m_pbmp;
}
//
// Access
//
public:
//
// Get the bitmap object
//
CBitmap & GetBitmap() { return *m_pbmp; }
//
// Get the background colour definition
//
COLORREF & GetBkColor() { return m_rgb; }
private:
CBitmap * m_pbmp;
COLORREF m_rgb;
};
//
// Global oblists of service bitmaps -- used by scope and result side
//
CObListPlus g_obl16x16;
CObListPlus g_obl32x32;
//
// Add-on-tools definitions
//
CObListPlus g_oblAddOnTools;
HRESULT
CSnapin::InitializeBitmaps(
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Initialize the service bitmaps
Arguments:
MMC_COOKIE cookie : Currently selected cookie (CIISObject *)
Return Value:
HRESULT
--*/
{
ASSERT(m_pImageResult != NULL);
CBitmap bmp16x16,
bmp32x32,
bmpMgr16x16,
bmpMgr32x32;
{
//
// Load the bitmaps from the dll
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
VERIFY(bmp16x16.LoadBitmap(IDB_VIEWS16));
VERIFY(bmp32x32.LoadBitmap(IDB_VIEWS32));
VERIFY(bmpMgr16x16.LoadBitmap(IDB_INETMGR16));
VERIFY(bmpMgr32x32.LoadBitmap(IDB_INETMGR16));
}
//
// Set the images
//
HRESULT hr = m_pImageResult->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)bmp16x16,
(LONG_PTR *)(HBITMAP)bmp32x32,
0,
RGB_BK_IMAGES
);
ASSERT(hr == S_OK);
//
// Add on inetmgr bitmap
//
hr = m_pImageResult->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)bmpMgr16x16,
(LONG_PTR *)(HBITMAP)bmpMgr32x32,
BMP_INETMGR,
RGB_BK_IMAGES
);
//
// Add the ones from the service config DLLs
//
POSITION pos16x16 = g_obl16x16.GetHeadPosition();
POSITION pos32x32 = g_obl32x32.GetHeadPosition();
int i = BMP_SERVICE;
while (pos16x16 && pos32x32)
{
CImage * pimg16x16 = (CImage *)g_obl16x16.GetNext(pos16x16);
CImage * pimg32x32 = (CImage *)g_obl32x32.GetNext(pos32x32);
ASSERT(pimg16x16 && pimg32x32);
hr = m_pImageResult->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)pimg16x16->GetBitmap(),
(LONG_PTR *)(HBITMAP)pimg32x32->GetBitmap(),
i++,
pimg16x16->GetBkColor()
);
ASSERT(hr == S_OK);
}
return hr;
}
STDMETHODIMP
CSnapin::GetDisplayInfo(
IN LPRESULTDATAITEM lpResultDataItem
)
/*++
Routine Description:
Get display info for result item
Arguments:
LPRESULTDATAITEM lpResultDataItem : Address of result data tiem
Return Value:
HRESULT
--*/
{
wchar_t * szString = _T("");
ASSERT(lpResultDataItem != NULL);
static int nImage = -1;
static CString str;
if (lpResultDataItem)
{
CIISObject * pObject = (CIISObject *)lpResultDataItem->lParam;
ASSERT(pObject != NULL);
if (pObject != NULL && pObject->IsValidObject())
{
pObject->GetResultDisplayInfo(lpResultDataItem->nCol, str, nImage);
lpResultDataItem->str = (LPTSTR)(LPCTSTR)str;
lpResultDataItem->nImage = nImage;
return S_OK;
}
}
return S_FALSE;
}
//
// IExtendContextMenu Implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
STDMETHODIMP
CSnapin::AddMenuItems(
IN LPDATAOBJECT lpDataObject,
IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
IN long * pInsertionAllowed
)
/*++
Routine Description:
Add menu items -- pass it on the the component date
Arguments:
LPDATAOBJECT lpDataObject : Data object
LPCONTEXTMENUCALLBACK lpContextMenuCallback : Context menu
long * pInsertionAllowed : TRUE if insertion is allowed
Return Value:
HRESULT
--*/
{
//
// Cut support for taskpads in beta2
//
#if TASKPADS_SUPPORTED
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW)
{
//
// Add View Menu Items
//
CIISObject::AddMenuItemByCommand(
lpContextMenuCallback,
IDM_VIEW_TASKPAD,
m_fTaskView ? MF_CHECKED : 0
);
}
#endif // TASKPADS_SUPPORTED
//
// Pass it on to CComponentDataImpl
//
return static_cast<CComponentDataImpl *>(m_pComponentData)->AddMenuItems(
lpDataObject,
lpContextMenuCallback,
pInsertionAllowed
);
}
STDMETHODIMP
CSnapin::Command(
IN long nCommandID,
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Command handler -- pass it on the component data
Arguments:
long nCommandID : Command ID
LPDTATAOBJECT lpDataObject : Data object
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
INTERNAL * pInternal = NULL;
switch(nCommandID)
{
case -1:
//
// Built-in views -- everything handled.
//
m_fTaskView = FALSE;
m_fSettingsChanged = TRUE;
break;
#if TASKPADS_SUPPORTED
//
// No taskpad support in beta2
//
case IDM_VIEW_TASKPAD:
//
// Handle view change
//
m_fTaskView = !m_fTaskView;
m_fSettingsChanged = TRUE;
//
// Reselect current scope item to force view change
//
pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal != NULL)
{
CIISObject * pObject = (CIISObject *)pInternal->m_cookie;
FREE_DATA(pInternal);
if (pObject)
{
m_pConsole->SelectScopeItem(pObject->GetScopeHandle());
}
else
{
//
// Must be the root item
//
m_pConsole->SelectScopeItem(
static_cast<CComponentDataImpl *>(m_pComponentData)->GetRootHandle()
);
}
}
break;
#endif // TASKPADS_SUPPORTED
default:
//
// Pass it on to CComponentDataImpl
//
hr = static_cast<CComponentDataImpl *>(m_pComponentData)->Command(
nCommandID,
lpDataObject
);
}
return hr;
}
//
// ITaskPad implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
HRESULT
CSnapin::TaskNotify(
IN IDataObject * pdo,
IN VARIANT * pvarg,
IN VARIANT * pvparam
)
/*++
Routine Description:
Handle notification from taskpad
Arguments:
IDataObject * pdo,
VARIANT * pvarg,
VARIANT * pvparam
Return Value:
HRESULT
--*/
{
if (pvarg->vt == VT_I4)
{
//
// Pass it on to CComponentDataImpl
//
return static_cast<CComponentDataImpl *>(m_pComponentData)->Command(
pvarg->lVal,
pdo
);
}
return S_OK;
}
HRESULT
CSnapin::GetTitle(
IN LPOLESTR szGroup,
OUT LPOLESTR * lpszTitle
)
/*++
Routine Description:
Get the title of the taskpad
Arguments:
LPOLESTR szGroup : Group name
LPOLESTR * szTitle : Returns title
Return Value:
HRESULT
--*/
{
OLECHAR sztitle[] = L"IIS TaskPad";
*lpszTitle = CoTaskDupString(sztitle);
return *lpszTitle != NULL ? S_OK : E_OUTOFMEMORY;
}
HRESULT
CSnapin::GetDescriptiveText(
IN LPOLESTR szGroup,
OUT LPOLESTR * lpszDescriptiveText
)
/*++
Routine Description:
Get the descriptive text
Arguments:
LPOLESTR szGroup : Group name
LPOLESTR * szTitle : Returns title
Return Value:
HRESULT
--*/
{
return E_NOTIMPL;
}
HRESULT
CSnapin::GetBanner(
IN LPOLESTR szGroup,
OUT LPOLESTR * pszBitmapResource
)
/*++
Routine Description:
Get the banner resource
Arguments:
LPOLESTR szGroup : Group name
LPOLESTR * pszBitmapResource : Returns bitmap resource
Return Value:
HRESULT
--*/
{
CString strResURL;
HRESULT hr = BuildResURL(strResURL);
if (FAILED(hr))
{
return hr;
}
strResURL += _T("/img\\ntbanner.gif");
TRACEEOLID(strResURL);
*pszBitmapResource = CoTaskDupString((LPCOLESTR)strResURL);
return *pszBitmapResource != NULL ? S_OK : E_OUTOFMEMORY;
}
HRESULT
CSnapin::GetBackground(
IN LPOLESTR szGroup,
OUT MMC_TASK_DISPLAY_OBJECT * pTDO
)
/*++
Routine Description:
Get the background resource
Arguments:
LPOLESTR szGroup : Group name
LPOLESTR * pszBitmapResource : Returns bitmap resource
Return Value:
HRESULT
--*/
{
return E_NOTIMPL;
}
HRESULT
CSnapin::EnumTasks(
IN IDataObject * pdo,
IN LPOLESTR szTaskGroup,
OUT IEnumTASK ** ppEnumTASK
)
/*++
Routine Description:
Enumerate the tasks on the taskpad
Arguments:
IDataObject * pdo : Data object selected;
LPOLESTR szTaskGroup, : Taskgroup name
IEnumTASK ** ppEnumTASK : Returns enumtask interface
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
try
{
ASSERT(ppEnumTASK != NULL);
CComObject<CEnumTasks>* pObject;
CComObject<CEnumTasks>::CreateInstance(&pObject);
ASSERT(pObject != NULL);
VERIFY(SUCCEEDED(pObject->Init(pdo, szTaskGroup)));
hr = pObject->QueryInterface(
IID_IEnumTASK,
reinterpret_cast<void **>(ppEnumTASK)
);
}
catch(CMemoryException * e)
{
e->Delete();
hr = E_OUTOFMEMORY;
}
return hr;
}
//
// IExtendControlbar implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CSnapin::SetControlbar(
IN LPCONTROLBAR lpControlbar
)
/*++
Routine Description:
Set the control bar
Arguments:
LPCONTROLBAR lpControlbar : Pointer to control bar
Return Value:
HRESULT
--*/
{
if (lpControlbar != NULL)
{
//
// Hold on to the controlbar interface.
//
if (m_pControlbar != NULL)
{
m_pControlbar->Release();
}
m_pControlbar = lpControlbar;
m_pControlbar->AddRef();
HRESULT hr = S_FALSE;
//
// Create the Toolbar
//
if (!m_pToolbar)
{
hr = m_pControlbar->Create(TOOLBAR, this, (LPUNKNOWN *)&m_pToolbar);
ASSERT(SUCCEEDED(hr));
m_pbmpToolbar = new CBitmap;
{
//
// Add the bitmap
//
AFX_MANAGE_STATE(AfxGetStaticModuleState());
m_pbmpToolbar->LoadBitmap(IDB_TOOLBAR);
}
//
// Add 16x16 bitmaps
//
hr = m_pToolbar->AddBitmap(
NUM_BITMAPS,
(HBITMAP)*m_pbmpToolbar,
16,
16,
TB_COLORMASK
);
ASSERT(SUCCEEDED(hr));
//
// Add the buttons to the toolbar
//
hr = m_pToolbar->AddButtons(NUM_BUTTONS, SnapinButtons);
ASSERT(SUCCEEDED(hr));
//
// Now add the add-on tools
//
POSITION pos = g_oblAddOnTools.GetHeadPosition();
//
// Toolbar buttons were created using buttonface
// background colour
//
COLORREF rgbMask = ::GetSysColor(COLOR_BTNFACE);
while (pos != NULL)
{
CISMShellExecutable * pTool =
(CISMShellExecutable *)g_oblAddOnTools.GetNext(pos);
ASSERT(pTool != NULL);
if (pTool->ShowInToolBar())
{
if (pTool->InitializedOK())
{
//
// Add 16x16 image
//
hr = m_pToolbar->AddBitmap(
1,
pTool->GetBitmap(),
16,
16,
rgbMask
);
ASSERT(SUCCEEDED(hr));
hr = m_pToolbar->AddButtons(1, pTool->GetButton());
ASSERT(SUCCEEDED(hr));
}
}
}
}
}
else
{
SAFE_RELEASE_SETTONULL(m_pControlbar);
}
return S_OK;
}
CISMShellExecutable *
CSnapin::GetCommandAt(
IN CObListPlus & obl,
IN int nIndex
)
/*++
Routine Description:
Get the add-on tool at the given index.
Arguments:
int nIndex : Index where to look for the add-on tool
Return Value:
Shell Executable object pointer, or NULL if the index was not valid
--*/
{
if (nIndex < 0 || nIndex >= obl.GetCount())
{
TRACEEOLID("Invalid tool index requested");
return NULL;
}
return (CISMShellExecutable *)obl.GetAt(obl.FindIndex(nIndex));
}
HRESULT
CSnapin::SetToolbarStates(
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Set toolbar states based on current selection
Arguments:
MMC_COOKIE cookie : Currently selected scope item cookie (CIISObject *)
Return Value:
HRESULT
--*/
{
CIISObject * pObject = (CIISObject *)cookie;
if (m_pToolbar)
{
m_pToolbar->SetButtonState(
IDM_CONNECT,
ENABLED,
!CIISObject::m_fIsExtension
);
m_pToolbar->SetButtonState(
IDM_PAUSE,
ENABLED,
pObject && pObject->IsPausable()
);
m_pToolbar->SetButtonState(
IDM_START,
ENABLED,
pObject && pObject->IsStartable()
);
m_pToolbar->SetButtonState(
IDM_STOP,
ENABLED,
pObject && pObject->IsStoppable()
);
m_pToolbar->SetButtonState(
IDM_PAUSE,
BUTTONPRESSED,
pObject && pObject->IsPaused()
);
}
return S_OK;
}
HRESULT
CSnapin::OnButtonClick(
IN LPDATAOBJECT lpDataObject,
IN long lID
)
/*++
Routine Description:
Handle toolbar button click
Arguments:
LPDATAOBJECT lpDataObject : Current data object
LONG lID : Button ID pressed
Return Value:
HRESULT
--*/
{
//
// Check to see if the button ID is in the add-on tools
// range
//
if (lID >= IDM_TOOLBAR)
{
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
CIISObject * pObject = pInternal
? (CIISObject *)pInternal->m_cookie
: NULL;
//
// Button ID was in the add-on tools range. Match
// up the ID with the add-on tool, and execute same.
//
CISMShellExecutable * pTool = GetCommandAt(
g_oblAddOnTools,
lID - IDM_TOOLBAR
);
ASSERT(pTool != NULL);
if (pTool != NULL)
{
CError err;
if (pObject == NULL)
{
//
// Nothing selected, execute with no parameters
//
err = pTool->Execute();
}
else
{
//
// Pass server/service to the add-on tool
//
LPCTSTR lpstrServer = pObject->GetMachineName();
LPCTSTR lpstrService = pObject->GetServiceName();
err = pTool->Execute(lpstrServer, lpstrService);
}
if (err.Failed())
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
err.MessageBox();
}
}
FREE_DATA(pInternal);
}
else
{
//
// Otherwise, it maps to a menu command, pass it on to the
// component data
//
ASSERT(m_pComponentData != NULL);
((CComponentDataImpl *)m_pComponentData)->Command(lID, lpDataObject);
}
return S_OK;
}
void
CSnapin::HandleStandardVerbs(
IN LPARAM arg,
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Set the standard verb states based on current selection
Arguments:
LPARAM arg : Argument
LPDATAOBJECT lpDataObject : Selected data object
Return Value:
None
--*/
{
if (lpDataObject == NULL || m_pConsoleVerb == NULL)
{
return;
}
CIISObject * pObject = NULL;
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal != NULL)
{
pObject = (CIISObject *)pInternal->m_cookie;
}
m_pConsoleVerb->SetVerbState(
MMC_VERB_RENAME,
ENABLED,
pObject && pObject->IsRenamable()
);
m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE);
m_pConsoleVerb->SetVerbState(
MMC_VERB_DELETE,
ENABLED,
pObject && pObject->IsDeletable()
);
m_pConsoleVerb->SetVerbState(
MMC_VERB_REFRESH,
ENABLED,
pObject && pObject->IsRefreshable()
);
#ifdef MMC_PAGES
BOOL fConfig = pObject && pObject->IsMMCConfigurable();
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED,fConfig);
if (pObject && pObject->IsLeafNode())
{
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
}
else
{
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
}
#else
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, TRUE);
#endif
}
void
CSnapin::HandleToolbar(
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Handle toolbar states
Arguments:
LPARAM arg : Selection change notification argument
LPARAM param : Selection change notification parameter
Return Value:
None.
--*/
{
INTERNAL * pInternal = NULL;
CIISObject * pObject = NULL;
HRESULT hr;
LPDATAOBJECT lpDataObject = NULL;
BOOL bScope = (BOOL)LOWORD(arg);
BOOL bSelect = (BOOL)HIWORD(arg);
if (bScope)
{
lpDataObject = (LPDATAOBJECT)param;
if (lpDataObject != NULL)
{
pInternal = ExtractInternalFormat(lpDataObject);
}
if (pInternal == NULL)
{
return;
}
pObject = (CIISObject *)pInternal->m_cookie;
//
// Attach the toolbars to the window
//
if (m_pControlbar != NULL)
{
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN)m_pToolbar);
ASSERT(SUCCEEDED(hr));
}
}
else
{
//
// Result Pane -- disable all if nothing selected.
//
if (bSelect)
{
lpDataObject = (LPDATAOBJECT)param;
if (lpDataObject != NULL)
{
pInternal = ExtractInternalFormat(lpDataObject);
}
if (pInternal == NULL)
{
return;
}
pObject = (CIISObject *)pInternal->m_cookie;
//
// Attach the toolbars to the window
//
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN)m_pToolbar);
ASSERT(SUCCEEDED(hr));
}
}
if (pInternal)
{
FREE_DATA(pInternal);
}
SetToolbarStates((MMC_COOKIE)pObject);
}
STDMETHODIMP
CSnapin::ControlbarNotify(
IN MMC_NOTIFY_TYPE event,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Handle control bar notification
Arguments:
MMC_NOTIFY_TYPE event : Notification event
LPARAM arg : argument as needed
LPARAM param : Parameter ad needed
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
switch (event)
{
case MMCN_BTN_CLICK:
//
// Note for MMC: it seems to be that arg and param
// should be reversed here. The MMCN_SELECT
// casts the dataobject to the param (which makes
// more sense anyway).
//
TRACEEOLID("CSnapin::ControlbarNotify - MMCN_BTN_CLICK");
OnButtonClick((LPDATAOBJECT)arg, (long)PtrToUlong((PVOID)param));
break;
case MMCN_SELECT:
TRACEEOLID("CSnapin::ControlbarNotify - MMCN_SEL_CHANGE");
HandleToolbar(arg, param);
break;
case MMCN_HELP:
break; // New
default:
//
// Unhandled event
//
ASSERT(FALSE);
}
return hr;
}
STDMETHODIMP
CSnapin::CompareObjects(
IN LPDATAOBJECT lpDataObjectA,
IN LPDATAOBJECT lpDataObjectB
)
/*++
Routine Description:
Compare two data objects. This method is used to see if a property
sheet for the given data object is already open
Arguments:
LPDATAOBJECT lpDataObjectA : A data object
LPDATAOBJECT lpDataObjectB : B data object
Return Value:
S_OK if they match, S_FALSE otherwise
--*/
{
//
// Delegate it to the IComponentData
//
ASSERT(m_pComponentData != NULL);
return m_pComponentData->CompareObjects(lpDataObjectA, lpDataObjectB);
}
/* virtual */
HRESULT
CSnapin::Compare(
IN RDCOMPARE * prdc,
OUT int * pnResult
)
/*++
Routine Description:
Compare method
Arguments:
RDCOMPARE * prdc : Compare structure
int * pnResult : Returns result
Return Value:
HRESULT
--*/
{
if (!pnResult || !prdc || !prdc->prdch1->cookie || !prdc->prdch2->cookie)
{
ASSERT(FALSE);
return E_POINTER;
}
CIISObject * pObjectA = (CIISObject *)prdc->prdch1->cookie;
CIISObject * pObjectB = (CIISObject *)prdc->prdch2->cookie;
*pnResult = pObjectA->Compare(prdc->nColumn, pObjectB);
return S_OK;
}
//
// IPersistStream interface members
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CSnapin::GetClassID(
OUT CLSID * pClassID
)
/*++
Routine Description:
Get class ID
Arguments:
CLSID * pClassID : Returns class ID
Return Value:
HRESULT
--*/
{
ASSERT(pClassID != NULL);
//
// Copy the CLSID for this snapin
//
*pClassID = CLSID_Snapin;
return E_NOTIMPL;
}
STDMETHODIMP
CSnapin::IsDirty()
/*++
Routine Description:
Checks to see if the snapin's persistence stream is dirty
Arguments:
None
Return Value:
S_OK if the stream needs to be updated, S_FALSE otherwise
--*/
{
return m_fSettingsChanged ? S_OK : S_FALSE;
}
STDMETHODIMP
CSnapin::Load(
IN IStream * pStm
)
/*++
Routine Description:
Load the persisted information
Arguments:
IStream * pStm : Persistence stream
Return Value:
HRESULT
--*/
{
ASSERT(pStm != NULL);
//
// Verify a simple signature
//
DWORD dw = 0x1234;
DWORD dw2;
DWORD cBytesRead;
HRESULT hr = S_OK;
do
{
hr = pStm->Read(&dw2, sizeof(dw2), &cBytesRead);
if (FAILED(hr))
{
break;
}
ASSERT(cBytesRead == sizeof(dw2) && dw2 == dw);
//
// Read settings
//
hr = pStm->Read(
&m_fTaskView,
sizeof(m_fTaskView),
&cBytesRead
);
if (cBytesRead == 0)
{
//
// Old style console file
//
TRACEEOLID("Warning: old-style console file encountered");
m_fTaskView = FALSE;
}
else
{
ASSERT(cBytesRead == sizeof(m_fTaskView));
}
}
while(FALSE);
#if !TASKPADS_SUPPORTED
m_fTaskView = FALSE;
#endif // TASKPADS_SUPPORTED
return hr;
}
STDMETHODIMP
CSnapin::Save(
IN IStream * pStm,
IN BOOL fClearDirty
)
/*++
Routine Description:
Save persistence information
Arguments:
IStream * pStm : Persistence stream
BOOL fClearDirty : TRUE to clear the dirty flag
Return Value:
HRESULT
--*/
{
ASSERT(pStm != NULL);
//
// Write a simple signature
//
DWORD dw = 0x1234;
DWORD cBytesWritten;
HRESULT hr = STG_E_CANTSAVE;
do
{
hr = pStm->Write(&dw, sizeof(dw), &cBytesWritten);
if (FAILED(hr))
{
break;
}
ASSERT(cBytesWritten == sizeof(dw));
hr = pStm->Write(&m_fTaskView, sizeof(m_fTaskView), &cBytesWritten);
ASSERT(cBytesWritten == sizeof(m_fTaskView));
}
while(FALSE);
return hr;
}
STDMETHODIMP
CSnapin::GetSizeMax(
ULARGE_INTEGER * pcbSize
)
/*++
Routine Description:
Get max size of persistence information
Arguments:
ULARGE_INTEGER * pcbSize : Returns the size
Return Value:
HRESULT
--*/
{
ASSERT(pcbSize != NULL);
//
// Set the size of the string to be saved
//
pcbSize->QuadPart = (ULONGLONG)sizeof(DWORD) + sizeof(m_fTaskView);
return S_OK;
}
STDMETHODIMP
CSnapin::GetHelpTopic(LPOLESTR *lpCompiledHelpFile)
{
return GetSnapinHelpFile(lpCompiledHelpFile);
}
//
// IComponentData implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl);
CComponentDataImpl::CComponentDataImpl()
/*++
Routine Description:
Contructor
Arguments:
None
Return Value:
N/A
--*/
: m_pScope(NULL),
m_pConsole(NULL),
m_hIISRoot(NULL),
m_fIsCacheDirty(FALSE),
m_fIsExtension(FALSE),
m_strlCachedServers(),
m_ullDiscoveryMask((ULONGLONG)0L)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl);
EmptyServerList();
#ifdef _DEBUG
m_cDataObjects = 0;
#endif
}
CComponentDataImpl::~CComponentDataImpl()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
SAFE_RELEASE(m_pScope);
SAFE_RELEASE(m_pConsole);
DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl);
//
// Some snap-in is hanging on to data objects.
// If they access, it will crash!!!
//
ASSERT(m_cDataObjects == 0);
}
STDMETHODIMP
CComponentDataImpl::Initialize(
IN LPUNKNOWN pUnknown
)
/*++
Routine Description:
Initalize the component data
Arguments:
LPUNKNOWN pUnknown : Pointer to IUnknown implementation
Return Value:
HRESULT
--*/
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
ASSERT(pUnknown != NULL);
HRESULT hr;
//
// MMC should only call ::Initialize once!
//
ASSERT(m_pScope == NULL);
pUnknown->QueryInterface(IID_IConsoleNameSpace, (void **)&m_pScope);
CIISObject::AttachScopeView(m_pScope);
//
// add the images for the scope tree
//
LPIMAGELIST lpScopeImage;
hr = pUnknown->QueryInterface(IID_IConsole2, (void **)&m_pConsole);
ASSERT(hr == S_OK);
hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
ASSERT(hr == S_OK);
//
// Load the config services DLLs
//
GetServicesDLL();
//
// Get the add-on tools
//
GetToolMenu();
//
// Get the DLLs which contain computer property pages
//
GetISMMachinePages();
CBitmap bmp16x16,
bmp32x32,
bmpMgr16x16,
bmpMgr32x32;
//
// Load the bitmaps from the dll
//
// Must AFX_MANAGE_STATE here
//
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
VERIFY(bmp16x16.LoadBitmap(IDB_VIEWS16));
VERIFY(bmp32x32.LoadBitmap(IDB_VIEWS32));
VERIFY(bmpMgr16x16.LoadBitmap(IDB_INETMGR16));
VERIFY(bmpMgr32x32.LoadBitmap(IDB_INETMGR16));
}
//
// Set the images
//
hr = lpScopeImage->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)bmp16x16,
(LONG_PTR *)(HBITMAP)bmp32x32,
0,
RGB_BK_IMAGES
);
ASSERT(hr == S_OK);
//
// Add on inetmgr bitmap
//
hr = lpScopeImage->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)bmpMgr16x16,
(LONG_PTR *)(HBITMAP)bmpMgr32x32,
BMP_INETMGR,
RGB_BK_IMAGES
);
ASSERT(hr == S_OK);
//
// Add the ones from the service config DLL's
//
POSITION pos16x16 = g_obl16x16.GetHeadPosition();
POSITION pos32x32 = g_obl32x32.GetHeadPosition();
int i = BMP_SERVICE;
while (pos16x16 && pos32x32)
{
CImage * pimg16x16 = (CImage *)g_obl16x16.GetNext(pos16x16);
CImage * pimg32x32 = (CImage *)g_obl32x32.GetNext(pos32x32);
ASSERT(pimg16x16 && pimg32x32);
hr = lpScopeImage->ImageListSetStrip(
(LONG_PTR *)(HBITMAP)pimg16x16->GetBitmap(),
(LONG_PTR *)(HBITMAP)pimg32x32->GetBitmap(),
i++,
pimg16x16->GetBkColor()
);
ASSERT(hr == S_OK);
}
lpScopeImage->Release();
return hr;
}
STDMETHODIMP
CComponentDataImpl::CreateComponent(
IN LPCOMPONENT * ppComponent
)
/*++
Routine Description:
Create component
Arguments:
LPCOMPONENT * ppComponent : Address if COMPONENT
Return Value:
HRESULT
--*/
{
ASSERT(ppComponent != NULL);
CComObject<CSnapin>* pObject;
CComObject<CSnapin>::CreateInstance(&pObject);
ASSERT(pObject != NULL);
//
// Store IComponentData
//
pObject->SetIComponentData(this);
return pObject->QueryInterface(IID_IComponent, (void **)ppComponent);
}
BOOL
CComponentDataImpl::FindOpenPropSheetOnNodeAndDescendants(
IN LPPROPERTYSHEETPROVIDER piPropertySheetProvider,
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Starting with the current node, check to see if an open
property sheet exists. Keep looking through descendants also.
As soon as an open property sheet is found, return TRUE.
Arguments:
MMC_COOKIE cookie : Cookie for currently selected item
Return Value:
TRUE if an open property sheet is found, FALSE if not.
Notes:
Function is called recursively
--*/
{
HSCOPEITEM hScopeItem = NULL;
CIISObject * pObject = (CIISObject *)cookie;
if (pObject != NULL)
{
hScopeItem = pObject->GetScopeHandle();
}
//
// Check the current node
//
HRESULT hr = piPropertySheetProvider->FindPropertySheet(
(MMC_COOKIE)hScopeItem,
NULL,
NULL
);
if (hr == S_OK)
{
//
// Found a sheet
//
return TRUE;
}
//
// Now check the descendants for open sheets
//
ASSERT(m_pScope != NULL);
//
// Look for machine object off the root
//
HSCOPEITEM hChildItem;
hr = m_pScope->GetChildItem(hScopeItem, &hChildItem, &cookie);
while (hr == S_OK && hChildItem != NULL)
{
CIISObject * pObject = (CIISObject *)cookie;
if (FindOpenPropSheetOnNodeAndDescendants(
piPropertySheetProvider,
cookie
))
{
//
// Found a sheet
//
return TRUE;
}
//
// Advance to next child of the same parent.
//
hr = m_pScope->GetNextItem(hChildItem, &hChildItem, &cookie);
}
//
// Not found
//
return FALSE;
}
/* INTRINSA suppress=null_pointers, uninitialized */
STDMETHODIMP
CComponentDataImpl::Notify(
IN LPDATAOBJECT lpDataObject,
IN MMC_NOTIFY_TYPE event,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Notification message handler
Arguments:
LPDATAOBJECT lpDataObject : Selected item
MMC_NOTIFY_TYPE event : Notification message
LPARAM arg : Notification Argument
LPARAM param : Notification Parameter
Return Value:
HRESULT
--*/
{
if (event == MMCN_PROPERTY_CHANGE)
{
return OnProperties(param);
}
ASSERT(m_pScope != NULL);
HRESULT hr = S_OK;
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
MMC_COOKIE cookie;
if (pInternal == NULL)
{
TRACEEOLID("Extension (CComponentDataImpl) Snapin");
CIISObject::m_fIsExtension = m_fIsExtension = TRUE;
cookie = NULL;
}
else
{
cookie = pInternal->m_cookie;
FREE_DATA(pInternal);
}
switch(event)
{
case MMCN_REFRESH:
RefreshIISObject((CIISObject *)cookie, TRUE, arg);
break;
case MMCN_DELETE:
DeleteObject((CIISObject *)cookie);
break;
case MMCN_RENAME:
hr = OnRename(cookie, arg, param);
break;
case MMCN_REMOVE_CHILDREN:
hr = OnRemoveChildren(arg);
break;
case MMCN_EXPAND:
hr = OnExpand(lpDataObject, arg, param);
break;
case MMCN_SELECT:
hr = OnSelect(cookie, arg, param);
break;
case MMCN_CONTEXTMENU:
hr = OnContextMenu(cookie, arg, param);
break;
default:
break;
}
return hr;
}
STDMETHODIMP
CComponentDataImpl::Destroy()
/*++
Routine Description:
Destroy component data
Arguments:
None
Return Value:
HRESULT
--*/
{
SAFE_RELEASE_SETTONULL(m_pScope);
SAFE_RELEASE_SETTONULL(m_pConsole);
m_hIISRoot = NULL;
//
// Scope items will clean themselves up
//
return S_OK;
}
STDMETHODIMP
CComponentDataImpl::QueryDataObject(
IN MMC_COOKIE cookie,
IN DATA_OBJECT_TYPES type,
OUT LPDATAOBJECT * ppDataObject
)
/*++
Routine Description:
Query data object
Arguments:
MMC_COOKIE cookie : Private data (i.e. a CIISObject *)
DATA_OBJECT_TYPES type : Data object type
LPDATAOBJECT * ppDataObject : Returns LPDATAOBJECT
Return Value:
HRESULT
--*/
{
ASSERT(ppDataObject != NULL);
CComObject<CDataObject>* pObject;
CComObject<CDataObject>::CreateInstance(&pObject);
ASSERT(pObject != NULL);
if (pObject == NULL)
return E_UNEXPECTED;
//
// Save cookie and type for delayed rendering
//
pObject->SetType(type);
pObject->SetCookie(cookie);
#ifdef _DEBUG
pObject->SetComponentData(this);
#endif
//
// Store the coclass with the data object
//
pObject->SetClsid(GetCoClassID());
return pObject->QueryInterface(IID_IDataObject, (void **)ppDataObject);
}
//
// IExtendPropertySheet Implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CComponentDataImpl::CreatePropertyPages(
IN LPPROPERTYSHEETCALLBACK lpProvider,
IN LONG_PTR handle,
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Create the property pages for the given object
Arguments:
LPPROPERTYSHEETCALLBACK lpProvider : Provider
LONG_PTR handle : Handle.
LPDATAOBJECT lpDataObject : Data object
Return Value:
HRESULT
--*/
{
#ifdef MMC_PAGES
CIISObject * pObject = NULL;
if (lpDataObject != NULL)
{
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal)
{
pObject = (CIISObject *)pInternal->m_cookie;
FREE_DATA(pInternal);
}
}
ASSERT(pObject && pObject->IsMMCConfigurable());
CError err(pObject->ConfigureMMC(lpProvider, (LPARAM)pObject, handle));
//
// ISSUE: MMC silently fails on this error. Perhaps it should
// write the error message?
//
if (err.Failed())
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
err.MessageBox();
}
return err;
#else
return E_NOTIMPL;
#endif // MMC_PAGES
}
STDMETHODIMP
CComponentDataImpl::QueryPagesFor(
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Check to see if a property sheet should be brought up for this data
object
Arguments:
LPDATAOBJECT lpDataObject : Data object
Return Value:
S_OK, if properties may be brought up for this item, S_FALSE otherwise
--*/
{
#ifdef MMC_PAGES
CIISObject * pObject = NULL;
if (lpDataObject != NULL)
{
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal)
{
pObject = (CIISObject *)pInternal->m_cookie;
FREE_DATA(pInternal);
}
}
return pObject && pObject->IsMMCConfigurable() ? S_OK : S_FALSE;
#else
return S_FALSE;
#endif // MMC_PAGES
}
//
// IPersistStream interface members
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CComponentDataImpl::GetClassID(
OUT CLSID * pClassID
)
/*++
Routine Description:
Return the objects class ID
Arguments:
CLSID pClassID : Returns the class ID
Return Value:
HRESULT
--*/
{
ASSERT(pClassID != NULL);
//
// Copy the CLSID for this snapin
//
*pClassID = CLSID_Snapin;
return S_OK;
}
STDMETHODIMP
CComponentDataImpl::IsDirty()
/*++
Routine Description:
Determine if we need to save the cache
Arguments:
None
Return Value:
S_OK if the stream needs to be updated, S_FALSE otherwise
--*/
{
if (m_fIsExtension)
{
//
// Extension to computer management -- no private cache
//
return S_FALSE;
}
//
// Primary snapin
//
return IsCacheDirty() ? S_OK : S_FALSE;
}
STDMETHODIMP
CComponentDataImpl::Load(
IN IStream * pStm
)
/*++
Routine Description:
Load the persisted information
Arguments:
IStream * pStm : Persistence stream
Return Value:
HRESULT
--*/
{
ASSERT(pStm);
DWORD cch;
DWORD cBytesRead;
LPTSTR lpstr;
if (m_fIsExtension)
{
//
// Extension to computer management -- no private cache
//
return S_OK;
}
//
// First read the size of the string array
//
HRESULT hr = pStm->Read(&cch, sizeof(cch), &cBytesRead);
if (FAILED(hr))
{
return E_FAIL;
}
//
// Virgin cache
//
if (cBytesRead != sizeof(cch) || cch == 0)
{
return S_OK;
}
lpstr = AllocTString(cch);
if (lpstr == NULL)
{
return E_FAIL;
}
hr = pStm->Read(lpstr, cch * sizeof(TCHAR), &cBytesRead);
ASSERT(SUCCEEDED(hr) && cBytesRead == cch * sizeof(TCHAR));
if (FAILED(hr))
{
return E_FAIL;
}
CStringList strl;
ConvertDoubleNullListToStringList(lpstr, strl);
for (POSITION pos = strl.GetHeadPosition(); pos!= NULL; )
{
CString & str = strl.GetNext(pos);
AddServerToCache(str, FALSE);
}
FreeMem(lpstr);
return hr;
}
STDMETHODIMP
CComponentDataImpl::Save(
IN IStream * pStm,
IN BOOL fClearDirty
)
/*++
Routine Description:
Save persistence information
Arguments:
IStream * pStm : Persistence stream
BOOL fClearDirty : TRUE to clear the dirty flag
Return Value:
HRESULT
--*/
{
ASSERT(pStm);
if (m_fIsExtension)
{
//
// Extension to computer management -- no private cache
//
return S_OK;
}
//
// Flatten the cache
//
DWORD cch;
LPTSTR lpstr;
DWORD cBytesWritten;
HRESULT hr = S_OK;
DWORD err = ConvertStringListToDoubleNullList(
GetCachedServers(),
cch,
lpstr
);
if (err == ERROR_SUCCESS)
{
//
// First write the total size
//
hr = pStm->Write(&cch, sizeof(cch), &cBytesWritten);
ASSERT(SUCCEEDED(hr) && cBytesWritten == sizeof(cch));
if (FAILED(hr))
{
return STG_E_CANTSAVE;
}
//
// Now write the body.
//
hr = pStm->Write(lpstr, cch * sizeof(TCHAR), &cBytesWritten);
ASSERT(SUCCEEDED(hr) && cBytesWritten == cch * sizeof(TCHAR));
if (FAILED(hr))
{
return STG_E_CANTSAVE;
}
if (fClearDirty)
{
ClearCacheDirty();
}
FreeMem(lpstr);
}
return S_OK;
}
STDMETHODIMP
CComponentDataImpl::GetSizeMax(
OUT ULARGE_INTEGER * pcbSize
)
/*++
Routine Description:
Get max size of persistence information
Arguments:
ULARGE_INTEGER * pcbSize : Returns the size
Return Value:
HRESULT
--*/
{
ASSERT(pcbSize);
//
// Set the size of the string to be saved
//
pcbSize->QuadPart = (ULONGLONG)0;
return S_OK;
}
//
// IExtendContextMenu implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
STDMETHODIMP
CComponentDataImpl::AddMenuItems(
IN LPDATAOBJECT lpDataObject,
IN LPCONTEXTMENUCALLBACK lpContextMenuCallback,
IN long * pInsertionAllowed
)
/*++
Routine Description:
Add menu items to the right-click context menu
Arguments:
LPDATAOBJECT pDataObject : Select
LPCONTEXTMENUCALLBACK pContextMenuCallback : Context menu callback function
long * pInsertionAllowed : ???
Return Value:
HRESULT
--*/
{
if (!(*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP))
{
//
// Nothing to add to the action menu.
//
return S_OK;
}
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
if (pInternal == NULL)
{
//
// Extensions not supported yet.
//
ASSERT(FALSE);
return S_OK;
}
CIISObject * pObject = (CIISObject *)pInternal->m_cookie;
FREE_DATA(pInternal);
if (pObject == NULL)
{
//
// Must be the static root, add connect menu item only.
//
CIISObject::AddMenuItemByCommand(lpContextMenuCallback, IDM_CONNECT);
return S_OK;
}
return pObject->AddMenuItems(lpContextMenuCallback);
}
BOOL
CComponentDataImpl::DoChangeState(
IN CIISObject * pObject,
IN int nNewState
)
/*++
Routine Description:
Change the state of the selected object
Arguments:
CIISObject * pObject : Selected object
int nNewState : Desired new state
Return Value:
TRUE for success, FALSE for failure.
Notes:
In case of failure, this method will already have displayed
an error message with the cause
--*/
{
ASSERT(pObject != NULL);
ASSERT(pObject->IsControllable());
int nNumRunningChange = pObject->IsRunning()
? -1
: 0;
CError err;
//
// Temporarily override some messages
//
TEMP_ERROR_OVERRIDE(ERROR_BAD_DEV_TYPE, IDS_CLUSTER_ENABLED);
TEMP_ERROR_OVERRIDE(ERROR_INVALID_PARAMETER, IDS_CANT_START_SERVICE);
{
//
// Needed for CWaitCursor
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CWaitCursor wait;
err = pObject->ChangeState(nNewState);
}
if (err.Failed())
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
err.MessageBox();
}
//
// Refresh regardless
//
pObject->RefreshDisplayInfo();
nNumRunningChange += pObject->IsRunning()
? +1
: 0;
AddToNumRunning(nNumRunningChange);
//UpdateStatusBarNumbers();
return err.Succeeded();
}
void
CComponentDataImpl::OnMetaBackRest(
IN CIISObject * pObject
)
/*++
Routine Description:
Perform metabase backup/restore
Arguments:
CIISObject * pObject : Selected object (should be machine node)
Return Value:
None
--*/
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ASSERT(pObject->QueryGUID() == cMachineNode);
CBackupDlg dlg(pObject->GetMachineName());
dlg.DoModal();
if (dlg.HasChangedMetabase())
{
RefreshIISObject(pObject, TRUE);
}
}
void
CComponentDataImpl::OnIISShutDown(
IN CIISObject * pObject
)
/*++
Routine Description:
Bring up IIS shutdown/restart dialogs
Arguments:
CIISObject * pObject : Selected object (should be machine node)
Return Value:
None
--*/
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ASSERT(pObject->QueryGUID() == cMachineNode);
LPCTSTR lpszMachineName = pObject->GetMachineName();
//
// If a property sheet is open for this item, don't
// allow deletion.
//
LPPROPERTYSHEETPROVIDER piPropertySheetProvider = NULL;
HRESULT hr = m_pConsole->QueryInterface(
IID_IPropertySheetProvider,
(void **)&piPropertySheetProvider
);
if (FindOpenPropSheetOnNodeAndDescendants(
piPropertySheetProvider,
(ULONG_PTR)pObject
))
{
//
// Already had properties open
//
::AfxMessageBox(IDS_PROP_OPEN_SHUTDOWN);
return;
}
CIISShutdownDlg dlg(lpszMachineName);
dlg.DoModal();
if (dlg.ServicesWereRestarted())
{
//
// Rebind all metabase handles on this server
//
CServerInfo * pServerInfo;
CObListIter obli(m_oblServers);
while (pServerInfo = (CServerInfo *)obli.Next())
{
if (!::lstrcmpi(pServerInfo->QueryServerName(), lpszMachineName))
{
TRACEEOLID(
"Rebinding against "
<< pServerInfo->GetShortName()
<< " on "
<< lpszMachineName
);
pServerInfo->ISMRebind();
}
}
//
// Now do a refresh on the computer node. Since we've forced
// the rebinding here, we should not get the disconnect warning.
//
RefreshIISObject(pObject, TRUE);
}
}
void
CComponentDataImpl::OnConnectOne()
/*++
Routine Description:
Connect to a single server
Arguments:
None
Return Value:
None
--*/
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
TEMP_ERROR_OVERRIDE(EPT_S_NOT_REGISTERED, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_SERVER_UNAVAILABLE, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE);
TEMP_ERROR_OVERRIDE(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
ConnectServerDlg dlg;
if (dlg.DoModal() == IDOK)
{
//
// Clean up name.
//
CString strServerName(dlg.QueryServerName());
int cServices = 0;
//
// The function will report the errors
//
CError err;
{
CWaitCursor wait;
err = AddServerToList(
TRUE, // Cache
FALSE, // Handle errors
strServerName,
cServices
);
}
if (err.Failed())
{
err.MessageBoxFormat(
IDS_ERROR_CONNECTING,
MB_OK,
NO_HELP_CONTEXT,
(LPCTSTR)strServerName
);
}
else if (cServices == 0)
{
//
// No errors, but no services found
//
::AfxMessageBox(IDS_NO_SERVICE);
}
}
}
void
CComponentDataImpl::DoConfigure(
IN CIISObject * pObject
)
/*++
Routine Description:
Configure the given iis object
Arguments:
CIISObject * pObject : Object to be configured
Return Value:
None
--*/
{
CError err;
//
// We need a window handle for this, but MMC won't
// give us one. Fortunately, we know MMC to be
// an MFC app, so we can sleazily grab it anyway.
//
CWnd * pMainWnd = NULL;
{
HWND hwnd;
err = m_pConsole->GetMainWindow(&hwnd);
if (err.Succeeded())
{
pMainWnd = CWnd::FromHandle(hwnd);
}
}
ASSERT(pMainWnd != NULL);
CWnd wnd;
if (pMainWnd == NULL)
{
//
// No main window in MMC? Use NULL handle
//
pMainWnd = &wnd;
}
ASSERT(m_pConsole);
ASSERT(pObject->IsConfigurable());
err = pObject->Configure(pMainWnd);
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
if (!err.MessageBoxOnFailure())
{
//
// Refresh and display the entry
//
OnProperties((LPARAM)pObject);
}
}
BOOL
CComponentDataImpl::DeleteObject(
IN CIISObject * pObject
)
/*++
Routine Description:
Delete the given iisobject. Ask for confirmation first.
Arguments:
CIISObject * pObject : Object to be deleted
Return Value:
TRUE if the item was deleted successfully,
FALSE otherwise.
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
BOOL fReturn = FALSE;
//
// If a property sheet is open for this item, don't
// allow deletion.
//
LPPROPERTYSHEETPROVIDER piPropertySheetProvider = NULL;
HRESULT hr = m_pConsole->QueryInterface(
IID_IPropertySheetProvider,
(void **)&piPropertySheetProvider
);
if (FindOpenPropSheetOnNodeAndDescendants(
piPropertySheetProvider,
(ULONG_PTR)pObject
))
{
//
// Already had properties open
//
::AfxMessageBox(IDS_PROP_OPEN);
}
else
{
CError err;
// Before we go and delete this baby,
// let's check if it's got a Cluster property set.
if (pObject->IsClusterEnabled())
{
::AfxMessageBox(IDS_CLUSTER_ENABLED_2);
}
else
{
if (!pObject->HandleUI() || NoYesMessageBox(IDS_CONFIRM_DELETE))
{
CWaitCursor wait;
err = pObject->Delete();
if (pObject->HandleUI())
{
//
// Only complain if we're to handle the error messages.
// In e.g. the file system, explorer handles all error
// messages
//
err.MessageBoxOnFailure();
}
if (err.Succeeded())
{
ASSERT(m_pScope);
//
// Delete the item from the view, but be careful that
// result item nodes store a scope handle, but which
// actually refers to the _parent_'s scope handle.
//
if (!pObject->ScopeHandleIsParent())
{
m_pScope->DeleteItem(pObject->GetScopeHandle(), TRUE);
delete pObject;
}
fReturn = TRUE;
}
}
}
}
piPropertySheetProvider->Release();
return fReturn;
}
void
CComponentDataImpl::DisconnectItem(
IN CIISObject * pObject
)
/*++
Routine Description:
Delete the given iisobject. Ask for confirmation first.
Arguments:
CIISObject * pObject : Object to be deleted
Return Value:
None
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
//
// If a property sheet is open for this item, don't
// allow deletion.
//
LPPROPERTYSHEETPROVIDER piPropertySheetProvider = NULL;
HRESULT hr = m_pConsole->QueryInterface(
IID_IPropertySheetProvider,
(void **)&piPropertySheetProvider
);
if (FindOpenPropSheetOnNodeAndDescendants(
piPropertySheetProvider,
(ULONG_PTR)pObject
))
{
//
// Already had properties open
//
::AfxMessageBox(IDS_PROP_OPEN);
}
else
{
CString strMachine(pObject->GetMachineName());
CString str, str2;
VERIFY(str.LoadString(IDS_CONFIRM_DISCONNECT));
str2.Format(str, strMachine);
if (NoYesMessageBox(str2))
{
//
// Remove from Cache and oblist
//
CError err(RemoveServerFromList(TRUE, strMachine));
if (!err.MessageBoxOnFailure())
{
ASSERT(m_pScope);
m_pScope->DeleteItem(pObject->GetScopeHandle(), TRUE);
delete pObject;
}
}
}
piPropertySheetProvider->Release();
}
STDMETHODIMP
CComponentDataImpl::Command(
IN long nCommandID,
IN LPDATAOBJECT lpDataObject
)
/*++
Routine Description:
Command handler
Arguments:
long nCommandID : Command ID
LPDATAOBJECT lpDataObject : Selected Data object
Return Value:
HRESULT
--*/
{
if (nCommandID == IDM_CONNECT)
{
//
// This is the only case that doesn't require a selected
// data object.
//
OnConnectOne();
return S_OK;
}
/*
if (IsMMCMultiSelectDataObject(lpDataObject))
{
//
// Do something for multi-select?
//
TRACEEOLID("Multiple selection");
}
*/
INTERNAL * pInternal = lpDataObject
? ExtractInternalFormat(lpDataObject)
: NULL;
if (pInternal == NULL)
{
return S_OK;
}
CIISObject * pObject = (CIISObject *)pInternal->m_cookie;
FREE_DATA(pInternal);
CError err;
switch (nCommandID)
{
case IDM_METABACKREST:
OnMetaBackRest(pObject);
break;
case IDM_SHUTDOWN:
OnIISShutDown(pObject);
break;
case IDM_DISCONNECT:
DisconnectItem(pObject);
break;
case IDM_CONFIGURE:
DoConfigure(pObject);
break;
case IDM_STOP:
DoChangeState(pObject, INetServiceStopped);
m_pConsole->UpdateAllViews(lpDataObject, 0L, (LONG_PTR)pObject);
break;
case IDM_START:
DoChangeState(pObject, INetServiceRunning);
m_pConsole->UpdateAllViews(lpDataObject, 0L, (LONG_PTR)pObject);
break;
case IDM_PAUSE:
DoChangeState(
pObject,
pObject->IsPaused() ? INetServiceRunning : INetServicePaused
);
m_pConsole->UpdateAllViews(lpDataObject, 0L, (LONG_PTR)pObject);
break;
case IDM_EXPLORE:
pObject->Explore();
break;
case IDM_OPEN:
pObject->Open();
break;
case IDM_BROWSE:
pObject->Browse();
break;
case IDM_TASK_SECURITY_WIZARD:
{
//
// Launch the security wizard
//
err = pObject->SecurityWizard();
err.MessageBoxOnFailure();
}
break;
case IDM_NEW_INSTANCE:
{
//
// Executed from another instance of the same type
//
ISMINSTANCEINFO ii;
CServerInfo * pServerInfo = pObject->GetServerInfo();
ASSERT(pServerInfo);
err = pServerInfo->AddInstance(&ii, sizeof(ii));
if (err.Succeeded())
{
CIISInstance * pInstance = new CIISInstance(&ii, pServerInfo);
//
// Add the new instance grouped with the service type,
// and select it
//
BOOL fNext;
HSCOPEITEM hParent = FindServerInfoParent(
GetRootHandle(),
pServerInfo
);
ASSERT(hParent != NULL);
HSCOPEITEM hSibling = FindNextInstanceSibling(
hParent,
pInstance,
&fNext
);
HSCOPEITEM hItem = AddIISObject(
hParent,
pInstance,
hSibling,
fNext
);
//
// hItem could return NULL if the hParent
// was not yet expanded.
//
if (hItem)
{
m_pConsole->SelectScopeItem(hItem);
}
}
}
break;
case IDM_NEW_VROOT:
CIISChildNode * pChild;
err = pObject->AddChildNode(pChild);
if (err.Succeeded())
{
//
// Insert prior to file/dir nodes, and select the item
//
HSCOPEITEM hItem = AddIISObject(
pObject->GetScopeHandle(),
pChild,
FindNextVDirSibling(pObject->GetScopeHandle(), pChild)
);
//
// hItem could return NULL if the parent object
// was not yet expanded.
//
if (hItem)
{
m_pConsole->SelectScopeItem(hItem);
}
}
break;
default:
//
// Now try to get to the service that we're
// supposed to create a new instance for.
//
if (nCommandID >= IDM_NEW_EX_INSTANCE)
{
int nID = nCommandID - IDM_NEW_EX_INSTANCE;
CNewInstanceCmd * pcmd =
(CNewInstanceCmd *)m_oblNewInstanceCmds.Index(nID);
ASSERT(pcmd != NULL);
if (pcmd)
{
ISMINSTANCEINFO ii;
CServerInfo * pServerInfo = FindServerInfo(
pObject->GetMachineName(),
pcmd->GetServiceInfo()
);
if (pServerInfo == NULL)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
::AfxMessageBox(IDS_ERR_SERVICE_NOT_INSTALLED);
break;
}
ASSERT(pServerInfo);
err = pServerInfo->AddInstance(&ii, sizeof(ii));
if (err.Succeeded())
{
//
// Add and select the item
//
CIISInstance * pInstance = new CIISInstance(
&ii,
pServerInfo
);
BOOL fNext;
HSCOPEITEM hSibling = FindNextInstanceSibling(
pObject->GetScopeHandle(),
pInstance,
&fNext
);
HSCOPEITEM hItem = AddIISObject(
pObject->GetScopeHandle(),
pInstance,
hSibling,
fNext
);
m_pConsole->SelectScopeItem(hItem);
}
}
}
else
{
//
// Unknown command!
//
ASSERT(FALSE);
}
break;
}
return S_OK;
}
//
// Notification handlers for IComponentData
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
HRESULT
CComponentDataImpl::OnAdd(
IN MMC_COOKIE cookie,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Add handler
Arguments:
MMC_COOKIE cookie : Scope item cookie (CIISObject *)
LPARAM arg : Argument
LPARAM param : Parameter
Return Value:
HRESULT
--*/
{
return E_UNEXPECTED;
}
HRESULT
CComponentDataImpl::OnDelete(
IN MMC_COOKIE cookie
)
/*++
Routine Description:
Handle deletion of the given scope item (CIISObject *)
Arguments:
MMC_COOKIE cookie : Casts to a CIISObject *
Return Value:
HRESULT
--*/
{
CIISObject * pObject = (CIISObject *)cookie;
if (pObject == NULL)
{
return S_FALSE;
}
delete pObject;
return S_OK;
}
HRESULT
CComponentDataImpl::OnRename(
IN MMC_COOKIE cookie,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Rename notification handler
Arguments:
MMC_COOKIE cookie : Currently selected cookie (CIISObject *)
LPARAM arg : Notification argument
LPARAM param : Notification parameter
Return Value:
HRESULT
--*/
{
CIISObject * pObject = (CIISObject *)cookie;
if (pObject == NULL)
{
//
// Can't rename this one
//
return S_FALSE;
}
if (!arg)
{
//
// Check to see if we're renamable
//
return pObject->IsRenamable() ? S_OK : S_FALSE;
}
TEMP_ERROR_OVERRIDE(ERROR_ALREADY_EXISTS, IDS_ERR_DUP_VROOT);
CError err;
//
// Do an actual rename
//
LPCTSTR lpstrNewName = (LPCTSTR)param;
err = pObject->Rename(lpstrNewName);
if (err.Succeeded())
{
//
// Force a refresh on the children
//
pObject->DirtyChildren();
}
else
{
if (pObject->HandleUI())
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
err.MessageBox();
}
}
return err.Succeeded() ? S_OK : S_FALSE;
}
HRESULT
CComponentDataImpl::OnRemoveChildren(
IN LPARAM arg
)
/*++
Routine Description:
'Remove Children' notification handler
Arguments:
LPARAM arg : Notification argument
Return Value:
HRESULT
--*/
{
m_strlCachedServers.RemoveAll();
return S_OK;
}
HRESULT
CComponentDataImpl::OnExpand(
LPDATAOBJECT lpDataObject,
LPARAM arg,
LPARAM param
)
/*++
Routine Description:
Expand notification handler
Arguments:
LPDATAOBJECT lpDataObject : Currently selected cookie (CIISObject *)
LPARAM arg : Notification argument
LPARAM param : Notification parameter
Return Value:
HRESULT
--*/
{
if (arg)
{
//
// Did Initialize get called?
//
ASSERT(m_pScope != NULL);
EnumerateScopePane(lpDataObject, param);
}
return S_OK;
}
HRESULT
CComponentDataImpl::OnSelect(
IN MMC_COOKIE cookie,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Selection notification handler
Arguments:
MMC_COOKIE cookie : Currently selected cookie (CIISObject *)
LPARAM arg : Notification argument
LPARAM param : Notification parameter
Return Value:
HRESULT
--*/
{
return E_UNEXPECTED;
}
HRESULT
CComponentDataImpl::OnContextMenu(
IN MMC_COOKIE cookie,
IN LPARAM arg,
IN LPARAM param
)
/*++
Routine Description:
Context Menu notification handler
Arguments:
MMC_COOKIE cookie : Currently selected cookie (CIISObject *)
LPARAM arg : Notification argument
LPARAM param : Notification parameter
Return Value:
HRESULT
--*/
{
return S_OK;
}
HRESULT
CComponentDataImpl::OnProperties(
IN LPARAM param
)
/*++
Routine Description:
Properties change notification handler
Arguments:
LPARAM arg : Notification argument (CIISObject *)
Return Value:
HRESULT
--*/
{
if (param == NULL)
{
return S_OK;
}
CIISObject * pObject = (CIISObject *)param;
ASSERT(pObject != NULL);
if (pObject != NULL)
{
CString strOldPath(pObject->QueryPhysicalPath());
CString strOldRedirect(pObject->QueryRedirPath());
BOOL fOldChildRedirOnly = pObject->IsChildOnlyRedir();
//
// Refresh the data to see if either the physical or redirection
// path has changed. If it has, refresh the child objects
//
CError err(pObject->RefreshData());
//
// Determine if the file system needs to be refreshed
//
BOOL fRefreshFileSystem = err.Succeeded()
&& pObject->SupportsChildren()
&& pObject->ChildrenExpanded()
&& pObject->SupportsFileSystem()
&& strOldPath.CompareNoCase(pObject->QueryPhysicalPath()) != 0;
//
// Determine if everything needs to be refreshed
//
BOOL fFullRefresh = err.Succeeded()
&& pObject->SupportsChildren()
&& pObject->ChildrenExpanded()
&& (strOldRedirect.CompareNoCase(pObject->QueryRedirPath()) != 0
|| fOldChildRedirOnly != pObject->IsChildOnlyRedir());
TRACEEOLID("Refresh files: "
<< fRefreshFileSystem
<< " Full Refresh: "
<< fFullRefresh
);
RefreshIISObject(pObject, fFullRefresh);
if (!fFullRefresh && fRefreshFileSystem)
{
//
// Not a full refresh -- the file system only.
//
CString strPhysicalPath, strMetaRoot;
pObject->BuildPhysicalPath(strPhysicalPath);
pObject->BuildFullPath(strMetaRoot, FALSE);
//
// Note: we can't use ExpandIISObject, because we're only
// replacing specific nodes, not the entire subtree
//
AddFileSystem(
pObject->GetScopeHandle(),
strPhysicalPath,
strMetaRoot,
pObject->FindOwnerInstance(),
GET_DIRECTORIES,
DELETE_CURRENT_DIR_TREE
);
//
// Mark this node to indicate that the child nodes
// have been added.
//
pObject->CleanChildren();
}
//
// Re-enumerate the result side if the current item is
// selected.
//
if ((fRefreshFileSystem || fFullRefresh) && pObject->IsScopeSelected())
{
ASSERT(m_pConsole);
m_pConsole->SelectScopeItem(pObject->GetScopeHandle());
}
}
return S_OK;
}
CServerInfo *
CComponentDataImpl::FindServerInfo(
IN LPCTSTR lpstrMachine,
IN CServiceInfo * pServiceInfo
)
/*++
Routine Description:
Find specific server info (i.e. machine name / service info
combination type)
Arguments:
LPCTSTR lpstrMachine : Machine name
CServiceInfo * pServiceInfo : Service info
Return Value:
Server Info object pointer, or NULL
--*/
{
CServerInfo * pServerInfo;
CObListIter obli(m_oblServers);
//
// Search is sequential, because we don't foresee more then a few
// of these objects in the cache
//
while (pServerInfo = (CServerInfo *)obli.Next())
{
if (!::lstrcmpi(pServerInfo->QueryServerName(), lpstrMachine)
&& pServerInfo->GetServiceInfo() == pServiceInfo)
{
//
// Found it
//
return pServerInfo;
}
}
return NULL;
}
void
CComponentDataImpl::RefreshIISObject(
IN CIISObject * pObject,
IN BOOL fExpandTree,
IN HSCOPEITEM pParent
)
/*++
Routine Description:
Refresh object, and optionally re-enumerate its display
Arguments:
CIISObject * pObject : Object to be refreshed
BOOL fExpandTree : TRUE to expand its tree
Return Value:
None
--*/
{
ASSERT(pObject != NULL);
CError err;
CServerInfo * pServer = pObject->GetServerInfo();
CMetaInterface * pInterface = NULL;
if (pServer)
{
pInterface = GetMetaKeyFromHandle(pServer->GetHandle());
}
if (pInterface)
{
BEGIN_ASSURE_BINDING_SECTION
err = pObject->RefreshData();
END_ASSURE_BINDING_SECTION(err, pInterface, RPC_S_SERVER_UNAVAILABLE);
}
else
{
err = pObject->RefreshData();
}
if (err.Failed())
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
err.MessageBox();
return;
}
pObject->RefreshDisplayInfo();
//
// Reenumerate its children if requested to do so and its necessary
//
if (fExpandTree)
{
if (pObject->ChildrenExpanded())
{
HSCOPEITEM hNode = pObject->GetScopeHandle();
if (KillChildren(
hNode,
IDS_PROP_OPEN_REFRESH,
DELETE_EVERYTHING,
DONT_CONTINUE_ON_OPEN_SHEET
))
{
pObject->DirtyChildren();
ExpandIISObject(hNode, pObject);
}
}
//
// Re-enumerate the result side, if the current item is
// selected.
//
if (pObject->IsScopeSelected())
{
ASSERT(m_pConsole);
m_pConsole->SelectScopeItem(pObject->GetScopeHandle());
}
}
}
void
CComponentDataImpl::LoadDynamicExtensions(
IN HSCOPEITEM hParent,
IN CIISObject * pObject
)
/*++
Routine Description:
Load dynamic snap-in extensions for the given node type.
Arguments:
None
Return Value:
None (if it fails, it always fails silently)
--*/
{
//
// We'll look here (on the server) to see if we need to load
// extension snap-ins.
//
const TCHAR SERVICES_KEY[] = SZ_REMOTEIISEXT;
if (pObject == NULL)
{
//
// This should never happen, right?
//
ASSERT(FALSE);
return;
}
CString str, strKey;
//
// Get base path for the given node type
//
strKey.Format(
_T("%s\\%s"),
SERVICES_KEY,
GUIDToCString(pObject->QueryGUID(), str)
);
TRACEEOLID(
pObject->GetMachineName() <<
" Attempting to dynamically load extensions for " <<
strKey);
CError err;
CRMCRegKey rkExtensions(REG_KEY, strKey, KEY_READ, pObject->GetMachineName());
CComQIPtr<IConsoleNameSpace2, &IID_IConsoleNameSpace2> pIConsoleNameSpace2
= m_pConsole;
if (pIConsoleNameSpace2 && rkExtensions.Ok())
{
DWORD dwType;
GUID guidExtension;
CRMCRegValueIter rkValues(rkExtensions);
//
// Loop through, and attempt to add each extension found in the
// registry
//
while (rkValues.Next(&str, &dwType) == ERROR_SUCCESS)
{
TRACEEOLID("Found dynamic extension: " << str);
err = ::CLSIDFromString((LPTSTR)(LPCTSTR)str, &guidExtension);
if (err.Succeeded())
{
err = pIConsoleNameSpace2->AddExtension(hParent, &guidExtension);
}
TRACEEOLID("DynaLoad returned " << err);
}
}
}
void
CComponentDataImpl::ExpandIISObject(
IN HSCOPEITEM hParent,
IN CIISObject * pObject,
IN LPTSTR lpszMachineName
)
/*++
Routine Description:
Expand the given IIS object tree
Arguments:
HSCOPEITEM hParent : Handle to parent item
CIISObject * pObject : IISObject to expand
Return Value:
None
--*/
{
CError err;
if (pObject != NULL)
{
ASSERT(hParent == pObject->GetScopeHandle());
}
//
// make sure we QI'ed for the interface
//
ASSERT(m_pScope != NULL);
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
{
CWaitCursor wait;
if (m_hIISRoot == NULL)
{
//
// Store the IIS root node for future use
//
m_hIISRoot = hParent;
}
if (pObject == NULL)
{
//
// Static root node -- populate with computers.
//
// This is done only once per session
//
ASSERT(GetRootHandle() == hParent);
TRACEEOLID("Inserting static root node");
AddCachedServersToView();
CServerInfo * pServerInfo = NULL;
CObListIter obli(m_oblServers);
if (m_fIsExtension)
{
//
// Since we're extending the computer management
// snap-in, only add the one server info parent
// object (only one computer, after all).
// This is also necessary, because for some reason
// I can't get the child item nodes of my parent,
// even if I've added them myself, and so we'd get
// duplicates.
//
if (lpszMachineName != NULL && *lpszMachineName != 0)
{
CServerInfo * p;
while (p = (CServerInfo *)obli.Next())
{
if (!::lstrcmpi(p->QueryServerName(), lpszMachineName))
{
pServerInfo = p;
break;
}
}
}
else
pServerInfo = (CServerInfo *)obli.Next();
ASSERT(pServerInfo != NULL);
if (pServerInfo)
{
AddServerInfoParent(hParent, pServerInfo);
}
}
else
{
//
// We're the primary snap-in, add all the server info
// parent objects (computers) to the view
//
while (pServerInfo = (CServerInfo *)obli.Next())
{
if (pServerInfo->IsServiceSelected())
{
//
// Add each item in the tree
//
AddServerInfoParent(hParent, pServerInfo);
}
}
}
}
else
{
if (!pObject->ChildrenExpanded())
{
//
// Delete whatever children there may be
//
if (pObject->QueryGUID() == cMachineNode)
{
CIISMachine * pMachine = (CIISMachine *)pObject;
CServerInfo * pServerInfo;
CObListIter obli(m_oblServers);
while (pServerInfo = (CServerInfo *)obli.Next())
{
if (pServerInfo->MatchServerName(pMachine->GetMachineName())
&& pServerInfo->IsServiceSelected())
{
//
// Add each item in the tree
//
AddServerInfo(hParent, pServerInfo, FALSE);
}
}
}
CString strMetaPath;
if (pObject->SupportsChildren())
{
pObject->BuildFullPath(strMetaPath, FALSE);
//
// Expand the children off the root
//
AddVirtualRoots(
hParent,
strMetaPath,
pObject->FindOwnerInstance()
);
}
if (pObject->SupportsFileSystem())
{
if (strMetaPath.IsEmpty())
{
pObject->BuildFullPath(strMetaPath, FALSE);
}
//
// Expand file system objects
//
CString strPhysicalPath;
pObject->BuildPhysicalPath(strPhysicalPath);
AddFileSystem(
hParent,
strPhysicalPath,
strMetaPath,
pObject->FindOwnerInstance(),
GET_DIRECTORIES,
DONT_DELETE_CURRENT_DIR_TREE
);
}
//
// Now load the dynamic extensions
//
LoadDynamicExtensions(hParent, pObject);
//
// Mark this node to indicate that the child nodes
// have been added.
//
pObject->CleanChildren();
}
}
}
err.MessageBoxOnFailure();
}
void
CComponentDataImpl::EnumerateScopePane(
IN LPDATAOBJECT lpDataObject,
IN HSCOPEITEM hParent
)
/*++
Routine Description:
Handle expansion of hParent scope item.
Arguments:
LPDATAOBJECT lpDataObject : Selected data object
HSCOPEITEM hParent : Scope handle of parent item or NULL
Return Value:
None
--*/
{
ASSERT(lpDataObject != NULL);
INTERNAL * pInternal = ExtractInternalFormat(lpDataObject);
MMC_COOKIE cookie = 0L;
LPTSTR lpszMachine = NULL;
if (pInternal == NULL)
{
//
// Not mine -- must be an extension; Get the machine name
//
ASSERT(m_fIsExtension);
lpszMachine = ExtractMachineName(lpDataObject);
TRACEEOLID(lpszMachine);
CString strServerName = PURE_COMPUTER_NAME(lpszMachine);
if (strServerName.IsEmpty())
{
//
// MyComputer reports "" for the computer name.
// This means the local machine is indicated
//
DWORD dwSize = MAX_SERVERNAME_LEN;
if (::GetComputerName(strServerName.GetBuffer(dwSize + 1), &dwSize))
{
strServerName.ReleaseBuffer();
}
}
//
// Since we're an extension, the cache will not be
// loaded from the persistence stream, and we can
// therefore guarantee that this will be the only
// item in the cache.
//
AddServerToCache(strServerName, FALSE);
}
else
{
cookie = pInternal->m_cookie;
FREE_DATA(pInternal);
}
#ifdef _DEBUG
CIISObject * pObject = (CIISObject *)cookie;
if (pObject)
{
ASSERT(hParent == pObject->GetScopeHandle());
}
#endif // _DEBUG
ExpandIISObject(hParent, (CIISObject *)cookie, lpszMachine);
}
STDMETHODIMP
CComponentDataImpl::GetDisplayInfo(
IN LPSCOPEDATAITEM lpScopeDataItem
)
/*++
Routine Description:
Get display info (text, bitmap) for the selected scope item
Arguments:
LPSCOPEDATAITEM lpScopeDataItem : Selected item
Return Value:
HRESULT
--*/
{
ASSERT(lpScopeDataItem != NULL);
if (lpScopeDataItem == NULL)
{
return E_POINTER;
}
static CString strText;
CIISObject * pObject = (CIISObject *)lpScopeDataItem->lParam;
ASSERT(lpScopeDataItem->mask & SDI_STR);
pObject->GetDisplayText(strText);
lpScopeDataItem->displayname = (LPTSTR)(LPCTSTR)strText;
ASSERT(lpScopeDataItem->displayname != NULL);
return S_OK;
}
STDMETHODIMP
CComponentDataImpl::CompareObjects(
IN LPDATAOBJECT lpDataObjectA,
IN LPDATAOBJECT lpDataObjectB
)
/*++
Routine Description:
Compare two data objects. This is used by MMC to determine whether a
given node has a property sheet already open for it.
Arguments:
LPDATAOBJECT lpDataObjectA : Data object 1
LPDATAOBJECT lpDataObjectB : Data object 2
Return Value:
S_OK if the objects are identical, S_FALSE otherwise
--*/
{
if (lpDataObjectA == NULL || lpDataObjectB == NULL)
{
return E_POINTER;
}
//
// Make sure both data object are mine
//
INTERNAL * pA;
INTERNAL * pB;
HRESULT hr = S_FALSE;
pA = ExtractInternalFormat(lpDataObjectA);
pB = ExtractInternalFormat(lpDataObjectA);
if (pA != NULL && pB != NULL)
{
//hr = (*pA == *pB) ? S_OK : S_FALSE;
return S_OK;
}
FREE_DATA(pA);
FREE_DATA(pB);
return hr;
}
void
CComponentDataImpl::GetISMMachinePages()
/*++
Routine Description:
Load the names of the DLL providing ISM machine property
page extentions
Arguments:
Return Value:
--*/
{
/* OBSOLETE
OBSOLETE
OBSOLETE
OBSOLETE
OBSOLETE
CString strValueName;
DWORD dwValueType;
CRMCRegKey rkMachine(REG_KEY, SZ_ADDONMACHINEPAGES, KEY_READ);
if (rkMachine.Ok())
{
return;
}
CRMCRegValueIter rvi(rkMachine);
CIISMachine::AttachPages(&m_oblISMMachinePages);
try
{
while (rvi.Next(&strValueName, &dwValueType) == ERROR_SUCCESS)
{
CString strValue;
rkMachine.QueryValue(strValueName, strValue);
TRACEEOLID("Registering machine pages in " << strValue);
m_oblISMMachinePages.AddTail(new CISMMachinePageExt(strValue));
}
}
catch(CException * e)
{
TRACEEOLID("!!!exception building ISM machine page list");
e->ReportError();
e->Delete();
}
*/
}
void
CComponentDataImpl::ConvertBitmapFormats(
IN CBitmap & bmpSource,
OUT CBitmap & bmp16x16,
OUT CBitmap & bmp32x32
)
/*++
Routine Description:
Convert a ISM service config bitmap to 16x16 and 32x32 exactly.
Downlevel services only included a single sized bitmap (usually
16x16) for use in ISM. We need a small one and a large one,
so we expand as needed.
Arguments:
IN CBitmap & bmpSource : Source bitmap
OUT CBitmap & bmp16x16 : 16x16 output bitmap
OUT CBitmap & bmp32x32 : 32x32 output bitmap
Return Value:
None
--*/
{
CDC dcImage;
CDC dc16x16;
CDC dc32x32;
VERIFY(dcImage.CreateCompatibleDC(NULL));
VERIFY(dc16x16.CreateCompatibleDC(NULL));
VERIFY(dc32x32.CreateCompatibleDC(NULL));
CBitmap * pOld = dcImage.SelectObject(&bmpSource);
BITMAP bm;
VERIFY(bmpSource.GetObject(sizeof(bm), &bm));
VERIFY(bmp16x16.CreateBitmap(16, 16, bm.bmPlanes, bm.bmBitsPixel, NULL));
VERIFY(bmp32x32.CreateBitmap(32, 32, bm.bmPlanes, bm.bmBitsPixel, NULL));
CBitmap * pOld16x16 = dc16x16.SelectObject(&bmp16x16);
CBitmap * pOld32x32 = dc32x32.SelectObject(&bmp32x32);
dc16x16.StretchBlt(0, 0, 16, 16, &dcImage, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
dc32x32.StretchBlt(0, 0, 32, 32, &dcImage, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
dc16x16.SelectObject(pOld16x16);
dc32x32.SelectObject(pOld32x32);
dcImage.SelectObject(pOld);
}
BOOL
CComponentDataImpl::VerifyBitmapSize(
IN HBITMAP hBitmap,
IN LONG nHeight,
IN LONG nWidth
)
/*++
Routine Description:
Verify the given bitmap is of the right size
Arguments:
HBITMAP hBitmap : Bitmap handle
LONG nHeight : Height the bitmap should be
LONG nWidth : Width the bitmap should be
Return Value:
TRUE if the bitmap is of the right size, FALSE otherwise
--*/
{
BITMAP bm;
int cb = GetObject(hBitmap, sizeof(BITMAP), &bm);
return (cb == sizeof(BITMAP)
&& bm.bmWidth == nWidth
&& bm.bmHeight == nHeight
);
}
BOOL
CComponentDataImpl::GetBitmapParms(
IN CServiceInfo * pServiceInfo,
IN BMP_TYPES bmpt,
OUT CBitmap *& pbmp16x16,
OUT CBitmap *& pbmp32x32,
OUT COLORREF & rgbMask
)
/*++
Routine Description:
Get bitmap information from service info object
Arguments:
CServiceInfo * pServiceInfo : Service info
BMP_TYPES bmpt : Type of info requested
COLORREF & rgbMask : Returns background mask
Return Value:
None.
--*/
{
ASSERT(pServiceInfo != NULL);
UINT nID16x16 = 0;
UINT nID32x32 = 0;
HINSTANCE hMod = NULL;
if (pServiceInfo->InitializedOK())
{
switch(bmpt)
{
case BMT_BUTTON:
nID16x16 = pServiceInfo->QueryButtonBitmapID();
nID32x32 = 0;
rgbMask = pServiceInfo->QueryButtonBkMask();
break;
case BMT_SERVICE:
nID16x16 = pServiceInfo->QueryServiceBitmapID();
nID32x32 = pServiceInfo->QueryLargeServiceBitmapID();
rgbMask = pServiceInfo->QueryServiceBkMask();
break;
case BMT_VROOT:
ASSERT(pServiceInfo->SupportsChildren());
nID16x16 = pServiceInfo->QueryChildBitmapID();
nID32x32 = pServiceInfo->QueryLargeChildBitmapID();
rgbMask = pServiceInfo->QueryChildBkMask();
break;
}
if (nID16x16 != 0)
{
hMod = pServiceInfo->QueryInstanceHandle();
}
else
{
//
// No bitmap provided by the service DLL, provide one from our
// own resource segment.
//
nID16x16 = IDB_UNKNOWN;
nID32x32 = 0;
hMod = ::AfxGetResourceHandle();
rgbMask = TB_COLORMASK;
}
}
else
{
//
// Add a disabled dummy button for a service
// that didn't load.
//
nID16x16 = IDB_NOTLOADED;
nID32x32 = 0;
hMod = ::AfxGetResourceHandle();
rgbMask = TB_COLORMASK;
}
if (nID16x16 == 0)
{
return FALSE;
}
pbmp16x16 = new CBitmap;
pbmp32x32 = new CBitmap;
if (pbmp16x16 == NULL || pbmp32x32 == NULL)
{
return FALSE;
}
HINSTANCE hOld = ::AfxGetResourceHandle();
::AfxSetResourceHandle(hMod);
if (nID32x32 != 0)
{
//
// Have explicit large and small images
//
VERIFY(pbmp16x16->LoadBitmap(nID16x16));
VERIFY(pbmp32x32->LoadBitmap(nID32x32));
//
// Check to make sure they're the right size
//
if (!VerifyBitmapSize((HBITMAP)*pbmp16x16, 16, 16) ||
!VerifyBitmapSize((HBITMAP)*pbmp32x32, 32, 32))
{
ASSERT(FALSE);
TRACEEOLID("Bogus bitmap size provided by service bitmap");
//
// Synthesize based on small image.
//
delete pbmp32x32;
CBitmap * pTmp = pbmp16x16;
ConvertBitmapFormats(*pTmp, *pbmp16x16, *pbmp32x32);
delete pTmp;
}
}
else
{
//
// Only have one image. Synthesize small and large from this
// image.
//
CBitmap bmp;
VERIFY(bmp.LoadBitmap(nID16x16));
//
// Convert to 16x16 and 32x32 image
//
ConvertBitmapFormats(bmp, *pbmp16x16, *pbmp32x32);
}
::AfxSetResourceHandle(hOld);
return TRUE;
}
void
CComponentDataImpl::GetToolMenu()
/*++
Routine Description:
Load the add-on tools
Arguments:
None.
Return Value:
None.
--*/
{
CString strValueName;
DWORD dwValueType;
int cTools = 0;
CRMCRegKey rkMachine(REG_KEY, SZ_ADDONTOOLS, KEY_READ);
if (!rkMachine.Ok())
{
//
// No registry entry
//
return;
}
CRMCRegValueIter rvi(rkMachine);
static BOOL fInitialised = FALSE;
if (fInitialised)
{
TRACEEOLID("Toolbar already initialised");
return;
}
try
{
int nButton = IDM_TOOLBAR;
while (rvi.Next(&strValueName, &dwValueType) == ERROR_SUCCESS)
{
CString strValue;
BOOL fExpanded;
rkMachine.QueryValue(
strValueName,
strValue,
EXPANSION_ON,
&fExpanded
);
TRACEEOLID("Adding tool: " << strValueName);
TRACEEOLID("From Path: " << strValue);
TRACEEOLID("Expansion: " << fExpanded);
CISMShellExecutable * pNewAddOnTool = new CISMShellExecutable(
strValue,
nButton - 1,
nButton
);
if (!pNewAddOnTool->HasBitmap())
{
TRACEEOLID("Tossing useless toolbar item");
delete pNewAddOnTool;
continue;
}
g_oblAddOnTools.AddTail(pNewAddOnTool);
++nButton;
}
}
catch(CException * e)
{
TRACEEOLID("!!!exception building tool menu");
e->ReportError();
e->Delete();
}
fInitialised = TRUE;
}
void
CComponentDataImpl::MatchupSuperDLLs()
/*++
Routine Description:
Match up all dlls with superceed dlls
Arguments:
None
Return Value:
None
--*/
{
POSITION pos = m_oblServices.GetHeadPosition();
while(pos)
{
CServiceInfo * pService = (CServiceInfo *)m_oblServices.GetNext(pos);
ASSERT(pService != NULL);
if (pService->RequiresSuperDll())
{
//
// Match up the super DLL
//
POSITION pos2 = m_oblServices.GetHeadPosition();
while (pos2)
{
CServiceInfo * pService2 =
(CServiceInfo *)m_oblServices.GetNext(pos2);
if (pService2->IsSuperDllFor(pService))
{
pService->AssignSuperDll(pService2);
break;
}
}
ASSERT(pService->HasSuperDll());
}
}
}
void
CComponentDataImpl::GetServicesDLL()
/*++
Routine Description:
Load the add-on services.
Arguments:
None
Return Value:
None
--*/
{
int cServices = 0;
HRESULT hr = S_OK;
LPIMAGELIST lpScopeImage = NULL;
LPIMAGELIST lpResultImage = NULL;
ASSERT(m_pConsole);
hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
ASSERT(SUCCEEDED(hr));
hr = m_pConsole->QueryResultImageList(&lpResultImage);
ASSERT(SUCCEEDED(hr));
//
// Run through the list of installed services,
// load its associated cfg dll, and build up
// a discovery mask for each service.
//
CString strValueName;
DWORD dwValueType;
CRMCRegKey rkMachine(REG_KEY, SZ_ADDONSERVICES, KEY_READ);
if (rkMachine.Ok())
{
CRMCRegValueIter rvi(rkMachine);
CIISMachine::AttachNewInstanceCmds(&m_oblNewInstanceCmds);
try
{
//
// Now load the services
//
// AFX_MANAGE_STATE required to load service bitmaps
// from the dlls
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
int nBmpIndex = BMP_SERVICE;
while (rvi.Next(&strValueName, &dwValueType) == ERROR_SUCCESS)
{
//
// Expand environment variables in path if present.
//
CString strValue;
BOOL fExpanded;
rkMachine.QueryValue(
strValueName,
strValue,
EXPANSION_ON,
&fExpanded
);
CServiceInfo * pServiceInfo = NULL;
{
CWaitCursor wait;
TRACEEOLID("Adding service DLL: " << strValue);
pServiceInfo = new CServiceInfo(cServices, strValue);
}
CError err(pServiceInfo->QueryReturnCode());
if (err.Failed())
{
if (err.Win32Error() == ERROR_INVALID_PARAMETER)
{
//
// The ERROR_INVALID_PARAMETER error return code
// gets sent when the info buffer provided is too
// small for the configuration DLL
//
::AfxMessageBox(
IDS_VERSION_INCOMPATIBLE,
MB_OK | MB_ICONEXCLAMATION
);
}
else
{
err.MessageBoxFormat(
IDS_ERR_NO_LOAD,
MB_OK | MB_ICONEXCLAMATION,
NO_HELP_CONTEXT,
(LPCTSTR)pServiceInfo->QueryDllName()
);
}
//
// Don't add it to the list
//
delete pServiceInfo;
continue;
}
AddServiceToList(pServiceInfo);
//
// If this service use inetsloc discovery,
// add it to the mask.
//
if (pServiceInfo->UseInetSlocDiscover())
{
m_ullDiscoveryMask |= pServiceInfo->QueryDiscoveryMask();
}
//
// Add a bitmap representing the service
// to the image list
//
CBitmap * pbmp16x16 = NULL;
CBitmap * pbmp32x32 = NULL;
COLORREF rgbMask;
if (GetBitmapParms(
pServiceInfo,
BMT_SERVICE,
pbmp16x16,
pbmp32x32,
rgbMask
))
{
g_obl16x16.AddTail(new CImage(pbmp16x16, rgbMask));
g_obl32x32.AddTail(new CImage(pbmp32x32, rgbMask));
pServiceInfo->SetBitmapIndex(nBmpIndex++);
}
//
// Add to the 'new instance' menu commands
//
if (pServiceInfo->SupportsInstances())
{
//
// Add to new instances menu object
//
m_oblNewInstanceCmds.AddTail(new CNewInstanceCmd(pServiceInfo));
}
if (pServiceInfo->SupportsChildren())
{
if (GetBitmapParms(
pServiceInfo,
BMT_VROOT,
pbmp16x16,
pbmp32x32,
rgbMask
))
{
g_obl16x16.AddTail(new CImage(pbmp16x16, rgbMask));
g_obl32x32.AddTail(new CImage(pbmp32x32, rgbMask));
pServiceInfo->SetChildBitmapIndex(nBmpIndex++);
}
}
++cServices;
}
MatchupSuperDLLs();
}
catch(CException * e)
{
TRACEEOLID("Exception loading library");
e->ReportError();
e->Delete();
}
}
if (cServices == 0)
{
//
// No services installed
//
CString str;
VERIFY(str.LoadString(IDS_NO_SERVICES_INSTALLED));
AfxMessageBox(str);
}
}
BOOL
CComponentDataImpl::RemoveServerFromCache(
IN LPCTSTR lpstrServer
)
/*++
Routine Description:
Remove machine from cache.
Arguments:
LPCTSTR lpstrServer : computer name to be removed from cache
Return Value:
None
--*/
{
CStringList & strList = GetCachedServers();
TRACEEOLID("Removing " << lpstrServer << " from cache");
POSITION posOld;
POSITION pos = strList.GetHeadPosition();
int nResult;
while(pos)
{
posOld = pos;
CString & str = strList.GetNext(pos);
nResult = str.CompareNoCase(lpstrServer);
if (nResult == 0)
{
strList.RemoveAt(posOld);
SetCacheDirty(TRUE);
return TRUE;
}
if (nResult > 0)
{
//
// We're not going to find it.
//
break;
}
}
//
// Didn't exist
//
ASSERT(FALSE && "Attempting to remove non-existent server from cache");
return FALSE;
}
void
CComponentDataImpl::AddServerToCache(
IN LPCTSTR lpstrServer,
IN BOOL fSetCacheDirty OPTIONAL
)
/*++
Routine Description:
Add machine name to the cache
Arguments:
LPCTSTR lpstrServer : computer name to be added to the cache.
BOOL fSetCacheDirty : TRUE to dirty the cache
Return Value:
None
--*/
{
CStringList & strList = GetCachedServers();
TRACEEOLID("Adding " << lpstrServer << " to cache");
CString strServer(lpstrServer);
POSITION posOld;
POSITION pos = strList.GetHeadPosition();
int nResult;
while(pos)
{
posOld = pos;
CString & str = strList.GetNext(pos);
nResult = str.CompareNoCase(strServer);
if (nResult == 0)
{
//
// Already existed in the case, ignore
//
return;
}
else if (nResult > 0)
{
//
// Found the proper place
//
strList.InsertBefore(posOld, strServer);
if (fSetCacheDirty)
{
SetCacheDirty();
}
return;
}
}
//
// Didn't exist yet, so add to list here
//
strList.AddTail(strServer);
if (fSetCacheDirty)
{
SetCacheDirty();
}
}
static BOOL
GetCommandLineServer(LPTSTR * pStr)
{
BOOL bRes = FALSE;
LPTSTR pCmdLine = GetCommandLine();
int n;
LPTSTR * pArgv = CommandLineToArgvW(pCmdLine, &n);
*pStr = NULL;
if (pArgv != NULL)
{
TCHAR szCmd[] = _T("/SERVER:");
int len = sizeof(szCmd) / sizeof(TCHAR) - 1;
for (int i = 0; i < n; i++)
{
if (CSTR_EQUAL == CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE, pArgv[i], len, szCmd, len))
{
LPTSTR p = pArgv[i] + len;
int count = 0;
while (*p != _T(' ') && *p != 0)
{
p++;
count++;
}
*pStr = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * (count + 1));
if (*pStr != NULL)
{
lstrcpyn(*pStr, pArgv[i] + len, count + 1);
bRes = TRUE;
}
break;
}
}
GlobalFree(pArgv);
}
return bRes;
}
void
CComponentDataImpl::AddCachedServersToView()
/*++
Routine Description:
Move the cached servers to the scope view.
Arguments:
None
Return Value:
None
--*/
{
CStringList & strlList = GetCachedServers();
BOOL bCmdLine = FALSE;
LPTSTR pCmdLine = NULL;
if (GetCommandLineServer(&pCmdLine))
{
bCmdLine = TRUE;
EmptyServerList();
AddServerToCache(pCmdLine, FALSE);
if (pCmdLine != NULL)
LocalFree(pCmdLine);
}
else if (strlList.IsEmpty())
{
//
// Nothing pre-selected or cached.
// Add the local machine.
//
CString str;
DWORD dwSize = MAX_SERVERNAME_LEN;
if (::GetComputerName(str.GetBuffer(dwSize + 1), &dwSize))
{
//
// Add local machine, though don't persist this later
//
str.ReleaseBuffer();
AddServerToCache(str, FALSE);
}
}
//
// Now add everything cached to the current
// view
//
CError err;
for(POSITION pos = strlList.GetHeadPosition(); pos != NULL; )
{
CString & strMachine = strlList.GetNext(pos);
int cServices;
err = AddServerToList(
FALSE,
bCmdLine ? TRUE : FALSE,
strMachine,
cServices,
m_oblServices
);
TRACEEOLID("adding " << strMachine << " to the view returned error code " << err);
if (err.Failed())
{
//
// Temporarily map RPC errors to friendlier error message
//
TEMP_ERROR_OVERRIDE(EPT_S_NOT_REGISTERED, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_SERVER_UNAVAILABLE, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE);
TEMP_ERROR_OVERRIDE(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
//
// Give the option of removing from cache
//
if (err.MessageBoxFormat(
IDS_ERROR_CONNECTING_CACHE,
MB_YESNO | MB_DEFBUTTON1,
NO_HELP_CONTEXT,
(LPCTSTR)strMachine) != IDYES)
{
VERIFY(RemoveServerFromCache(strMachine));
}
}
else if (cServices == 0)
{
//
// No errors, but no services found
//
::AfxMessageBox(IDS_NO_SERVICE);
}
}
}
CServiceInfo *
CComponentDataImpl::GetServiceAt(
IN int nIndex
)
/*++
Routine Description:
Get the service object at the given index.
Arguments:
int nIndex : Index where to look for the service info object
Return Value:
Service info pointer, or NULL if the index was not valid
--*/
{
if (nIndex < 0 || nIndex >= m_oblServices.GetCount())
{
TRACEEOLID("Invalid service index requested");
return NULL;
}
return (CServiceInfo *)m_oblServices.GetAt(m_oblServices.FindIndex(nIndex));
}
void
CComponentDataImpl::EmptyServerList()
/*++
Routine Description:
Empty server list
Arguments:
None
Return Value:
None
--*/
{
m_oblServers.RemoveAll();
m_cServers = m_cServicesRunning = 0;
}
DWORD
CComponentDataImpl::AddServerToList(
IN BOOL fCache,
IN LPINET_SERVER_INFO lpServerInfo,
IN OUT CObListPlus & oblServices
)
/*++
Routine Description:
Add a service object for each service discovered
to be belonging to this server.
Arguments:
BOOL fCache : TRUE to cache
LPINET_SERVER_INFO lpServerInfo : Discovery information (from inetsloc)
CObListPlus & oblServices : List of installed services
Return Value:
Error return code
--*/
{
TRACEEOLID("For Server " << lpServerInfo->ServerName);
CServerInfo * pServerInfo;
DWORD err = ERROR_SUCCESS;
for (DWORD j = 0; j < lpServerInfo->Services.NumServices; ++j)
{
LPINET_SERVICE_INFO lpServiceInfo = lpServerInfo->Services.Services[j];
try
{
//
// Attempt to create a server info block
//
pServerInfo = new CServerInfo(
lpServerInfo->ServerName,
lpServiceInfo,
oblServices
);
if (pServerInfo->IsConfigurable())
{
TRACEEOLID("Adding " << (DWORD)lpServiceInfo->ServiceMask);
if (!AddToList(fCache, pServerInfo))
{
TRACEEOLID("It already existed in the list");
delete pServerInfo;
}
}
else
{
//
// Toss it
//
TRACEEOLID("Tossing " << (DWORD)lpServiceInfo->ServiceMask);
delete pServerInfo;
}
}
catch(CMemoryException * e)
{
TRACEEOLID("AddServerList: memory exception");
err = ERROR_NOT_ENOUGH_MEMORY;
e->Delete();
}
}
return err;
}
DWORD
CComponentDataImpl::AddServerToList(
IN BOOL fCache,
IN BOOL fHandleErrors,
IN CString & strServerName,
OUT int & cServices,
IN OUT CObListPlus & oblServices
)
/*++
Routine Description:
Add a service object for each service running
on the machine listed above.
Arguments:
BOOL fCache : TRUE to cache the server
BOOL fHandleErrors : TRUE to display error messages, FALSE to abort
on error
CString & strServerName : Name of this server
int & cServices : # Services added
CObListPlus & oblServices : List of installed services
Return Value:
Error return code
--*/
{
TEMP_ERROR_OVERRIDE(EPT_S_NOT_REGISTERED, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_SERVER_UNAVAILABLE, IDS_ERR_RPC_NA);
TEMP_ERROR_OVERRIDE(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE);
TEMP_ERROR_OVERRIDE(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
//
// Loop through the services, and find out which ones
// are installed on the target machine, if any.
//
CObListIter obli(oblServices);
CServiceInfo * psi;
cServices = 0;
CError err;
ISMSERVERINFO ServerInfo;
CServerInfo::CleanServerName(strServerName);
//
// See if we can make contact with the machine
//
if (!DoesServerExist(strServerName))
{
//
// No, quit right here
//
err = RPC_S_SERVER_UNAVAILABLE;
if (fHandleErrors)
{
err.MessageBox();
}
return err.Win32Error();
}
while (psi = (CServiceInfo *)obli.Next())
{
int cErrors = 0;
if (psi->InitializedOK())
{
TRACEEOLID("Trying: " << psi->GetShortName());
ServerInfo.dwSize = sizeof(ServerInfo);
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CWaitCursor wait;
err = psi->ISMQueryServerInfo(
strServerName,
&ServerInfo
);
}
if (err.Win32Error() == ERROR_SERVICE_DOES_NOT_EXIST)
{
TRACEEOLID("Service not installed -- acceptable response");
err.Reset();
}
else if (err.Win32Error() == ERROR_SERVICE_START_HANG)
{
TRACEEOLID("Service is hanging -- ignore silently");
err.Reset();
}
else if (err.Succeeded())
{
//
// Yes, this service is running on this
// machine.
//
++cServices;
//
// Add to list
//
try
{
CServerInfo * pNewServer = new CServerInfo(
strServerName,
&ServerInfo,
psi
);
if (!AddToList(fCache, pNewServer, TRUE))
{
TRACEEOLID("It already existed in the list");
delete pNewServer;
}
}
catch(CMemoryException * e)
{
TRACEEOLID("AddServerList: memory exception");
err = ERROR_NOT_ENOUGH_MEMORY;
e->Delete();
}
}
if (err.Failed())
{
if (!fHandleErrors)
{
//
// Let the calling process handle the errors,
// we're stopping.
//
break;
}
++cErrors;
//
// Display error about the service
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
err.MessageBoxFormat(
IDS_ERR_ENUMERATE_SVC,
MB_OK,
NO_HELP_CONTEXT,
(LPCTSTR)psi->GetShortName(),
(LPCTSTR)strServerName
);
//
// Optionally cancel here on no response.
//
//break;
}
}
}
return err.Win32Error();
}
DWORD
CComponentDataImpl::RemoveServerFromList(
IN BOOL fCache,
IN CString & strServerName
)
/*++
Routine Description:
Remove each service in the list belonging to the given computer name.
Arguments:
CString & strServerName : Name of this server
Return Value:
Error return code
--*/
{
CServerInfo::CleanServerName(strServerName);
CServerInfo * pEntry;
POSITION pos1, pos2;
pos1 = m_oblServers.GetHeadPosition();
while(pos1)
{
pos2 = pos1;
pEntry = (CServerInfo *)m_oblServers.GetNext(pos1);
if (pEntry->MatchServerName(strServerName))
{
m_oblServers.RemoveAt(pos2);
}
}
if (fCache)
{
RemoveServerFromCache(strServerName);
}
return ERROR_SUCCESS;
}
void
CComponentDataImpl::Refresh()
/*++
Routine Description:
Refresh the server list
Arguments:
None
Return Value:
None
--*/
{
//
// AFX_MANAGE_STATE required for wait cursor
//
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
POSITION pos;
CWaitCursor wait;
CServerInfo * pEntry;
for(pos = m_oblServers.GetHeadPosition(); pos != NULL; /**/ )
{
pEntry = (CServerInfo *)m_oblServers.GetNext(pos);
int oldState = pEntry->QueryServiceState();
if (pEntry->Refresh() == ERROR_SUCCESS)
{
if (oldState != pEntry->QueryServiceState())
{
//
// Take away this service from the total
// running count if it was part of it
// before, and (re-) add it if it's currently
// running.
//
if (oldState == INetServiceRunning)
{
--m_cServicesRunning;
}
if (pEntry->IsServiceRunning())
{
++m_cServicesRunning;
}
}
//UpdateAllViews(NULL, HINT_REFRESHITEM, pEntry);
}
}
}
BOOL
CComponentDataImpl::AddToList(
IN BOOL fCache,
IN CServerInfo * pServerInfo,
IN BOOL fSelect
)
/*++
Routine Description:
Add the service to the list if it didn't exist already,
otherwise refresh the info if it did exist. Return
TRUE if the service was added, FALSE, if already
existed and was refreshed.
Arguments:
CServerInfo * pServerInfo : Server to add
BOOL fSelect : If TRUE, select the newly added item
Return Value:
TRUE if added, FALSE otherwise
--*/
{
POSITION pos;
BOOL fFoundService = FALSE;
BOOL fFoundServer = FALSE;
BOOL fServiceAdded = FALSE;
//int nAddHint = fSelect ? HINT_ADDITEM_SELECT : HINT_ADDITEM;
CServerInfo * pEntry;
for( pos = m_oblServers.GetHeadPosition();
pos != NULL;
m_oblServers.GetNext(pos)
)
{
pEntry = (CServerInfo *)m_oblServers.GetAt(pos);
if (pEntry->CompareByServer(pServerInfo) == 0)
{
fFoundServer = TRUE;
//
// Found the server, also the service?
//
if (pEntry->CompareByService(pServerInfo) == 0)
{
//
// Yes, the service was found also -- update the information
// if the service state has changed.
//
TRACEEOLID("Entry Already Existed");
fFoundService = TRUE;
if (pEntry->QueryServiceState()
!= pServerInfo->QueryServiceState())
{
TRACEEOLID("Service State has changed -- refreshing");
//
// Decrement the running counter if this service
// was part of that counter. The counter will be
// re-added if the service is still running
//
if (pEntry->IsServiceRunning())
{
--m_cServicesRunning;
}
*pEntry = *pServerInfo;
if (pEntry->IsServiceRunning())
{
++m_cServicesRunning;
}
//UpdateAllViews(NULL, HINT_REFRESHITEM, pEntry);
}
break;
}
}
else
{
if (fFoundServer)
{
//
// Server name no longer matches, but did match
// the last time, so we didn't find the service.
// Insert it at the end of the services belonging
// to this guy.
//
TRACEEOLID("Found new service belonging to known server");
m_oblServers.InsertBefore(pos, pServerInfo);
fServiceAdded = TRUE; // Don't add again.
if (pServerInfo->IsServiceRunning())
{
++m_cServicesRunning;
}
//UpdateAllViews(NULL, nAddHint, pServerInfo);
break;
}
}
}
if (!fFoundService && !fServiceAdded)
{
//
// Came to the end of the list without
// finding the service -- add a new one
// at the end.
//
TRACEEOLID("Adding new entry to tail");
m_oblServers.AddTail(pServerInfo);
if (pServerInfo->IsServiceRunning())
{
++m_cServicesRunning;
}
if (!fFoundServer)
{
++m_cServers;
if (fCache)
{
AddServerToCache(pServerInfo->QueryServerName(), TRUE);
}
}
if (fCache && GetRootHandle() != NULL)
{
//
// View has already been expanded -- add it here.
//
if (pServerInfo->IsServiceSelected())
{
AddServerInfoParent(GetRootHandle(), pServerInfo);
}
}
}
return !fFoundService;
}
static HRESULT
GetSnapinHelpFile(LPOLESTR * lpCompiledHelpFile)
{
if (lpCompiledHelpFile == NULL)
return E_INVALIDARG;
CString strFilePath, strWindowsPath, strBuffer;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Use system API to get windows directory.
UINT uiResult = GetWindowsDirectory(strWindowsPath.GetBuffer(MAX_PATH),
MAX_PATH);
strWindowsPath.ReleaseBuffer();
if (uiResult <= 0 || uiResult > MAX_PATH)
{
return E_FAIL;
}
if (!strFilePath.LoadString(IDS_HELPFILE))
{
return E_FAIL;
}
strBuffer = strWindowsPath;
strBuffer += _T('\\');
strBuffer += strFilePath;
*lpCompiledHelpFile
= reinterpret_cast<LPOLESTR>(CoTaskMemAlloc((strBuffer.GetLength() + 1)
* sizeof(_TCHAR)));
if (*lpCompiledHelpFile == NULL)
return E_OUTOFMEMORY;
USES_CONVERSION;
_tcscpy(*lpCompiledHelpFile, T2OLE((LPTSTR)(LPCTSTR)strBuffer));
return S_OK;
}
STDMETHODIMP
CComponentDataImpl::GetHelpTopic(LPOLESTR *lpCompiledHelpFile)
{
return GetSnapinHelpFile(lpCompiledHelpFile);
}
//
// About implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinAboutImpl);
CSnapinAboutImpl::CSnapinAboutImpl()
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
N/A
--*/
{
}
CSnapinAboutImpl::~CSnapinAboutImpl()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapinAboutImpl);
}
HRESULT
CSnapinAboutImpl::AboutHelper(
IN UINT nID,
OUT LPOLESTR * lpPtr
)
/*++
Routine Description:
"About" helper function
Arguments:
UINT nID : String resource ID
LPOLESTR * lpPtr : Return buffer for the string
Return Value:
HRESULT
--*/
{
if (lpPtr == NULL)
{
return E_POINTER;
}
CString s;
VERIFY(::LoadString(
_Module.GetModuleInstance(),
nID,
s.GetBuffer(255),
255));
s.ReleaseBuffer();
*lpPtr = (LPOLESTR)CoTaskMemAlloc((s.GetLength() + 1) * sizeof(wchar_t));
if (*lpPtr == NULL)
{
return E_OUTOFMEMORY;
}
lstrcpy(*lpPtr, (LPCTSTR)s);
return S_OK;
}
STDMETHODIMP
CSnapinAboutImpl::GetSnapinDescription(
OUT LPOLESTR * lpDescription
)
/*++
Routine Description:
Get the snapin description
Arguments:
LPOLESTR * lpDescription : String return buffer
Return Value:
HRESULT
--*/
{
return AboutHelper(IDS_SNAPIN_DESC, lpDescription);
}
STDMETHODIMP
CSnapinAboutImpl::GetProvider(
OUT LPOLESTR * lpName
)
/*++
Routine Description:
Get the snapin provider string
Arguments:
LPOLESTR * lpName : String return buffer
Return Value:
HRESULT
--*/
{
return AboutHelper(IDS_COMPANY, lpName);
}
STDMETHODIMP
CSnapinAboutImpl::GetSnapinVersion(
IN LPOLESTR * lpVersion
)
/*++
Routine Description:
Get the snapin version string:
Arguments:
LPOLESTR * lpVersion : Version string
Return Value:
HRESULT
--*/
{
return AboutHelper(IDS_VERSION, lpVersion);
}
STDMETHODIMP
CSnapinAboutImpl::GetSnapinImage(
IN HICON * hAppIcon
)
/*++
Routine Description:
Get the icon for this snapin
Arguments:
HICON * hAppIcon : Return handle to the icon
Return Value:
HRESULT
--*/
{
if (hAppIcon == NULL)
{
return E_POINTER;
}
*hAppIcon = LoadIcon(
_Module.GetModuleInstance(),
MAKEINTRESOURCE(IDI_ICON));
ASSERT(*hAppIcon != NULL);
return (*hAppIcon != NULL) ? S_OK : E_FAIL;
}
STDMETHODIMP
CSnapinAboutImpl::GetStaticFolderImage(
OUT HBITMAP * phSmallImage,
OUT HBITMAP * phSmallImageOpen,
OUT HBITMAP * phLargeImage,
OUT COLORREF * prgbMask
)
/*++
Routine Description:
Get the static folder image
Arguments:
HBITMAP * phSmallImage : Small folder
HBITMAP * phSmallImageOpen : Small open folder
HBITMAP * phLargeImage : Large image
COLORREF * prgbMask : Mask
Return Value:
HRESULT
--*/
{
if (!phSmallImage || !phSmallImageOpen || !phLargeImage || !prgbMask)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
*phSmallImage = (HBITMAP)LoadImage(
_Module.GetModuleInstance(),
MAKEINTRESOURCE(IDB_INETMGR16),
IMAGE_BITMAP,
0,
0,
LR_DEFAULTCOLOR
);
*phSmallImageOpen = (HBITMAP)LoadImage(
_Module.GetModuleInstance(),
MAKEINTRESOURCE(IDB_INETMGR16),
IMAGE_BITMAP,
0,
0,
LR_DEFAULTCOLOR
);
*phLargeImage = (HBITMAP)LoadImage(
_Module.GetModuleInstance(),
MAKEINTRESOURCE(IDB_INETMGR32),
IMAGE_BITMAP,
0,
0,
LR_DEFAULTCOLOR
);
*prgbMask = RGB_BK_IMAGES;
return *phSmallImage && *phLargeImage ? S_OK : E_FAIL;
}