997 lines
34 KiB
C++
997 lines
34 KiB
C++
/*
|
|
* ComponentData.cxx
|
|
*
|
|
*
|
|
* Copyright (c) 1998-1999 Microsoft Corporation
|
|
*
|
|
* PURPOSE: Defines the CComponentData class.
|
|
*
|
|
*
|
|
* OWNER: ptousig
|
|
*/
|
|
|
|
#include "headers.hxx"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
CComponentData::CComponentData(CBaseSnapin *psnapin)
|
|
{
|
|
Trace(tagBaseSnapinIComponentData, _T("--> CComponentData::CComponentData(psnapin=0x%08X)"), psnapin);
|
|
|
|
ASSERT(psnapin);
|
|
|
|
m_psnapin = psnapin;
|
|
m_fIsRealComponentData = FALSE;
|
|
m_pitemStandaloneRoot = NULL;
|
|
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- CComponentData::CComponentData has constructed 0x%08X"), this);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Destructor doesn't do anything, but it's useful to have one for debugging
|
|
// purposes.
|
|
//
|
|
CComponentData::~CComponentData(void)
|
|
{
|
|
Trace(tagBaseSnapinIComponentData, _T("--> CComponentData::~CComponentData(), this=0x%08X"), this);
|
|
|
|
Psnapin()->ScOwnerDying(this);
|
|
if (m_pitemStandaloneRoot)
|
|
{
|
|
Psnapin()->ScReleaseIfRootItem(m_pitemStandaloneRoot);
|
|
}
|
|
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- CComponentData::~CComponentData has destructed 0x%08X"), this);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// This version of Pitem() is a shortcut, it forwards the call to the
|
|
// CBaseSnapin with the correct CComponentData parameter.
|
|
//
|
|
CBaseSnapinItem *CComponentData::Pitem( LPDATAOBJECT lpDataObject,
|
|
HSCOPEITEM hscopeitem,
|
|
long cookie)
|
|
{
|
|
return Psnapin()->Pitem(this, NULL, lpDataObject, hscopeitem, cookie);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// The registration routine expects to find this method on the CComponentData
|
|
// but the real implementation is on the CBaseSnapin, so we just forward
|
|
// the call.
|
|
//
|
|
SC CComponentData::ScRegister(BOOL fRegister)
|
|
{
|
|
CBaseSnapin* pSnapin = Psnapin();
|
|
return pSnapin->ScRegister(fRegister);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Is called by the MMC to initialize the object. We QueryInterface
|
|
// for pointers to the name space and console, which we cache in
|
|
// local variables. This is called only once, when the user clicks on
|
|
// the snapin.
|
|
//
|
|
// $REVIEW (ptousig) I am not sure which of interfaces we are allowed to QI
|
|
// for from the parameter. The MMC docs are no help (as usual),
|
|
//
|
|
SC CComponentData::ScInitialize(LPUNKNOWN pUnknown)
|
|
{
|
|
SC sc = S_OK;
|
|
IImageListPtr ipScopeImageList;
|
|
|
|
ASSERT(pUnknown != NULL);
|
|
ASSERT(m_ipConsoleNameSpace == NULL);
|
|
|
|
m_fIsRealComponentData = TRUE;
|
|
|
|
sc = Psnapin()->ScInitBitmaps();
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// These are CComQIPtr so they will call QueryInterface.
|
|
m_ipConsoleNameSpace = pUnknown;
|
|
m_ipConsole = pUnknown;
|
|
m_ipResultData = pUnknown;
|
|
m_ipPropertySheetProvider = pUnknown;
|
|
|
|
// Get a pointer to the scope pane's IImageList.
|
|
sc = m_ipConsole->QueryScopeImageList(&ipScopeImageList);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Set the icon strip for the scope pane.
|
|
sc = ipScopeImageList->ImageListSetStrip(
|
|
reinterpret_cast<long *>(static_cast<HBITMAP>(Psnapin()->BitmapSmall())),
|
|
reinterpret_cast<long *>(static_cast<HBITMAP>(Psnapin()->BitmapLarge())),
|
|
0, RGB(255, 0, 255));
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScInitialize"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Handles component data event notification.
|
|
// See MMC docs for the meaning of 'arg' and 'param'.
|
|
//
|
|
SC CComponentData::ScNotify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
|
|
{
|
|
SC sc = S_OK;
|
|
|
|
switch (event)
|
|
{
|
|
case MMCN_BTN_CLICK:
|
|
sc = ScOnButtonClick(lpDataObject, (MMC_CONSOLE_VERB) param);
|
|
break;
|
|
|
|
case MMCN_DELETE:
|
|
sc = ScOnDelete(lpDataObject);
|
|
break;
|
|
|
|
case MMCN_RENAME:
|
|
sc = Psnapin()->ScOnRename(lpDataObject, reinterpret_cast<LPCTSTR>(param), IpConsole());
|
|
break;
|
|
|
|
case MMCN_EXPAND:
|
|
sc = ScOnExpand(lpDataObject, arg != FALSE, param);
|
|
break;
|
|
|
|
case MMCN_EXPANDSYNC:
|
|
sc = ScOnExpandSync(lpDataObject, reinterpret_cast<MMC_EXPANDSYNC_STRUCT *>(param));
|
|
break;
|
|
|
|
case MMCN_PROPERTY_CHANGE:
|
|
sc = Psnapin()->ScOnPropertyChange(arg != FALSE, param, IpConsoleNameSpace(), IpConsole());
|
|
break;
|
|
|
|
case MMCN_REMOVE_CHILDREN:
|
|
sc = ScOnRemoveChildren(lpDataObject, arg);
|
|
break;
|
|
|
|
default:
|
|
sc = S_FALSE;
|
|
ASSERT(_T("CComponentData::ScNotify: unimplemented event %x"));
|
|
break;
|
|
}
|
|
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScNotify"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Releases all interfaces.
|
|
//
|
|
SC CComponentData::ScDestroy(void)
|
|
{
|
|
m_ipConsole.Release();
|
|
m_ipConsoleNameSpace.Release();
|
|
m_ipResultData.Release();
|
|
m_ipPropertySheetProvider.Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CComponentData::ScQueryDispatch
|
|
*
|
|
* PURPOSE: Dummy implementation. Does nothing.
|
|
*
|
|
* PARAMETERS:
|
|
* MMC_COOKIE cookie :
|
|
* DATA_OBJECT_TYPES type :
|
|
* LPDISPATCH* ppDispatch :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CComponentData::ScQueryDispatch(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDISPATCH* ppDispatch)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CComponentData::ScQueryDispatch"));
|
|
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
// The component data can handle cookie types of CCT_SNAPIN_MANAGER and CCT_SCOPE.
|
|
// CCT_RESULT are handled by CComponent.
|
|
ASSERT(type==CCT_SCOPE);
|
|
|
|
//
|
|
// If the cookie does not correspond to a known object, return E_UNEXPECTED.
|
|
// This is correct and is also a workaround for an MMC bug. See X5:74405.
|
|
//
|
|
if (cookie && (Psnapin()->Pcookielist()->find(cookie) == Psnapin()->Pcookielist()->end() ) )
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
return sc;
|
|
}
|
|
|
|
pitem = Pitem(NULL, 0, cookie);
|
|
ASSERT(pitem);
|
|
|
|
sc = pitem->ScQueryDispatch(cookie, type, ppDispatch);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Load information from the first root item.
|
|
//
|
|
// $REVIEW (ptousig) Why does the root item implement ScLoad() ?
|
|
// If a snapin extends two nodes it has two root items, yet
|
|
// only one of which will be saved/loaded.
|
|
//
|
|
SC CComponentData::ScLoad(IStream *pstream)
|
|
{
|
|
SC sc = S_OK;
|
|
|
|
// Load the snapin's serialized information.
|
|
sc = Psnapin()->ScLoad(pstream);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Load the root item's serialized information.
|
|
// Only makes sense for standalone snapins.
|
|
sc = Pitem()->ScLoad(pstream);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScLoad"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Determines whether any settings have changed since the last time the file
|
|
// was saved.
|
|
//
|
|
// $REVIEW (ptousig) We are never dirty !!! Shouldn't we ask the Pitem() ?
|
|
//
|
|
SC CComponentData::ScIsDirty(void)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// If one of the commands added to the context menu is
|
|
// subsequently selected, MMC calls Command.
|
|
//
|
|
// Even though this method "looks" like the one in CComponent,
|
|
// the use of the Pitem() shortcut makes them different. This
|
|
// version does not pass a component to the real Pitem().
|
|
//
|
|
SC CComponentData::ScCommand(long nCommandID, LPDATAOBJECT pDataObject)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
pitem = Pitem(pDataObject);
|
|
ASSERT(pitem);
|
|
|
|
sc = pitem->ScCommand(nCommandID);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScCommand"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Gets display information for a scope pane item
|
|
// Warning: This is called very very often (on WM_PAINT) so it is important
|
|
// we don't take any high latency actions (ie Network or Disk access).
|
|
//
|
|
SC CComponentData::ScGetDisplayInfo(LPSCOPEDATAITEM pScopeItem)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
pitem = Pitem(NULL, 0, pScopeItem->lParam);
|
|
ASSERT(pitem);
|
|
|
|
sc = pitem->ScGetDisplayInfo(pScopeItem);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScGetDisplayInfo"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::CompareObjects"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::CompareObjects(lpDataObjectA=0x%08X, lpDataObjectB=0x%08X), this=0x%08X"), StrSnapinClassName(), lpDataObjectA, lpDataObjectB, this);
|
|
ADMIN_TRY;
|
|
sc=Psnapin()->ScCompareObjects(lpDataObjectA, lpDataObjectB);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::CompareObjects is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::GetDisplayInfo(LPSCOPEDATAITEM pItem)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::GetDisplayInfo"));
|
|
Trace(tagBaseSnapinIComponentDataGetDisplayInfo, _T("--> %s::IComponentData::GetDisplayInfo(cookie=0x%08X), this=0x%08X"), StrSnapinClassName(), pItem->lParam, this);
|
|
ADMIN_TRY;
|
|
sc=ScGetDisplayInfo(pItem);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentDataGetDisplayInfo, _T("<-- %s::IComponentData::GetDisplayInfo is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::QueryDataObject(long cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT * ppDataObject)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::QueryDataObject"));
|
|
Trace(tagBaseSnapinIComponentDataQueryDataObject, _T("--> %s::IComponentData::QueryDataObject(cookie=0x%08X, type=%s), this=0x%08X"), StrSnapinClassName(), cookie, SzGetDebugNameOfDATA_OBJECT_TYPES(type), this);
|
|
ADMIN_TRY;
|
|
//
|
|
// If we receive E_UNEXPECTED we don't want to call MMCHrFromSc because
|
|
// that will bring up an error message. We don't want an error message
|
|
// in this case because of a known MMC bug (see bug X5:74405).
|
|
// The bug says that we might receive QueryDataObject on items that
|
|
// we were told no longer exists (by MMCN_REMOVE_CHILDREN).
|
|
//
|
|
sc = ScQueryDataObject(cookie, type, ppDataObject);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentDataQueryDataObject, _T("<-- %s::IComponentData::QueryDataObject is returning hr=%s, *ppDataObject=0x%08X"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()), *ppDataObject);
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Notify"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::Notify(lpDataObject=0x%08X, event=%s, arg=0x%08X, param=0x%08X), this=0x%08X"), StrSnapinClassName(), lpDataObject, SzGetDebugNameOfMMC_NOTIFY_TYPE(event), arg, param, this);
|
|
ADMIN_TRY;
|
|
sc=ScNotify(lpDataObject, event, arg, param);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::Notify is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::CreateComponent(LPCOMPONENT * ppComponent)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::CreateComponent"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::CreateComponent(...), this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
sc=ScCreateComponent(ppComponent);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::CreateComponent is returning hr=%s, *ppComponent=0x%08X"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()), *ppComponent);
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Initialize(LPUNKNOWN pUnknown)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Initialize"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::Initialize(pUnknown=0x%08X), this=0x%08X"), StrSnapinClassName(), pUnknown, this);
|
|
ADMIN_TRY;
|
|
sc=ScInitialize(pUnknown);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::Initialize is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Destroy(void)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Destroy"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::Destroy(), , this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
sc=ScDestroy();
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::Destroy is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::QueryDispatch(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDISPATCH* ppDispatch)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::QueryDispatch"));
|
|
Trace(tagBaseSnapinIComponentData, _T("--> %s::IComponentData::QueryDispatch(), , this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
sc=ScQueryDispatch(cookie, type, ppDispatch);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIComponentData, _T("<-- %s::IComponentData::QueryDispatch is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK ipContextMenuCallback, long *pInsertionAllowed)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::AddMenuItems"));
|
|
Trace(tagBaseSnapinIExtendContextMenu, _T("--> %s::IExtendContextMenu::AddMenuItems(pDataObject=0x%08X), this=0x%08X"), StrSnapinClassName(), pDataObject, this);
|
|
ADMIN_TRY;
|
|
// By calling Pitem() at this time, we will force the creation of the ghost
|
|
// root node, if necessary.
|
|
Pitem(pDataObject);
|
|
sc=Psnapin()->ScAddMenuItems(pDataObject, ipContextMenuCallback, pInsertionAllowed);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIExtendContextMenu, _T("<-- %s::IExtendContextMenu::AddMenuItems is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Command(long nCommandID, LPDATAOBJECT pDataObject)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Command"));
|
|
Trace(tagBaseSnapinIExtendContextMenu, _T("--> %s::IExtendContextMenu::Command(nCommandID=%ld, pDataObject=0x%08X), this=0x%08X"), StrSnapinClassName(), nCommandID, pDataObject, this);
|
|
ADMIN_TRY;
|
|
sc=ScCommand(nCommandID, pDataObject);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIExtendContextMenu, _T("<-- %s::IExtendContextMenu::Command is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, long handle, LPDATAOBJECT lpDataObject)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::CreatePropertyPages"));
|
|
Trace(tagBaseSnapinIExtendPropertySheet, _T("--> %s::IExtendPropertySheet::CreatePropertyPages(lpDataObject=0x%08X), this=0x%08X"), StrSnapinClassName(), lpDataObject, this);
|
|
ADMIN_TRY;
|
|
// Why are we ignoring E_UNEXPECTED ?
|
|
// Because when we are called by the snapin manager, and the user hits cancel we
|
|
// need to return E_UNEXPECTED to MMC.
|
|
sc = ScCreatePropertyPages(lpProvider, handle, lpDataObject);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIExtendPropertySheet, _T("<-- %s::IExtendPropertySheet::CreatePropertyPages is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::QueryPagesFor(LPDATAOBJECT lpDataObject)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::QueryPagesFor"));
|
|
Trace(tagBaseSnapinIExtendPropertySheet, _T("--> %s::IExtendPropertySheet::QueryPagesFor(lpDataObject=0x%08X), this=0x%08X"), StrSnapinClassName(), lpDataObject, this);
|
|
ADMIN_TRY;
|
|
sc=ScQueryPagesFor(lpDataObject);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIExtendPropertySheet, _T("<-- %s::IExtendPropertySheet::QueryPagesFor is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::GetSizeMax"));
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::GetSizeMax(...), , this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
pcbSize->LowPart = cMaxStreamSizeLow;
|
|
pcbSize->HighPart = cMaxStreamSizeHigh;
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::GetSizeMax is returning hr=%s, (*pcbSize).LowPart=%d"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()), (*pcbSize).LowPart);
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::IsDirty(void)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::IsDirty"));
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::IsDirty(), this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
sc=ScIsDirty();
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::IsDirty is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Load(IStream *pstream)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Load"));
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::Load(...), this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
sc=ScLoad(pstream);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::Load is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Save(IStream *pstream, BOOL fClearDirty)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Save"));
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::Save(fClearDirty=%S), this=0x%08X"), StrSnapinClassName(), fClearDirty ? "TRUE" : "FALSE", this);
|
|
ADMIN_TRY;
|
|
sc=ScSave(pstream, fClearDirty);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::Save is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::InitNew(void)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::InitNew"));
|
|
// We don't have anything to do, but we still want to log the call.
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::InitNew(), this=0x%08X"), StrSnapinClassName(), this);
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::InitNew is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::GetClassID(CLSID *pclsid)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::GetClassID"));
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("--> %s::IPersistStreamInit::GetClassID(...), this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
*pclsid = *(Psnapin()->PclsidSnapin());
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIPersistStreamInit, _T("<-- %s::IPersistStreamInit::GetClassID is returning hr=%s"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()));
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CComponentData::Compare(RDCOMPARE * prdc, int * pnResult)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::Compare"));
|
|
Trace(tagBaseSnapinIResultDataCompare, _T("--> %s::IResultDataCompare::Compare(cookieA=0x%08X, cookieB=0x%08X), this=0x%08X"), StrSnapinClassName(), prdc->prdch1->cookie, prdc->prdch2->cookie, this);
|
|
ADMIN_TRY;
|
|
ASSERT(pnResult);
|
|
ASSERT(prdc);
|
|
ASSERT(prdc->prdch1);
|
|
ASSERT(prdc->prdch2);
|
|
sc=Psnapin()->ScCompare(prdc->prdch1->cookie, prdc->prdch2->cookie, prdc->nColumn, pnResult);
|
|
ADMIN_CATCH_HR
|
|
Trace(tagBaseSnapinIResultDataCompare, _T("<-- %s::IResultDataCompare::Compare is returning hr=%s, *pnResult=%d"), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()), *pnResult);
|
|
return(sc.ToHr());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Returns the full path of the compiled file (.chm) for the snapin.
|
|
//
|
|
HRESULT CComponentData::GetHelpTopic(LPOLESTR *lpCompiledHelpFile)
|
|
{
|
|
DECLARE_SC(sc,_T("CComponentData::GetHelpTopic"));
|
|
tstring strCompiledHelpFile;
|
|
USES_CONVERSION;
|
|
|
|
Trace(tagBaseSnapinISnapinHelp, _T("--> %s::ISnapinHelp::GetHelpTopic(...), this=0x%08X"), StrSnapinClassName(), this);
|
|
ADMIN_TRY;
|
|
|
|
if (lpCompiledHelpFile == NULL)
|
|
{
|
|
sc = E_POINTER;
|
|
goto Error;
|
|
}
|
|
|
|
// Automatically displays an error box.
|
|
sc = Psnapin()->ScGetHelpTopic(strCompiledHelpFile);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
if (strCompiledHelpFile.empty())
|
|
{
|
|
sc=S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
*lpCompiledHelpFile = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc( (strCompiledHelpFile.length()+1)*sizeof(TCHAR)) );
|
|
sc = ScCheckPointers(*lpCompiledHelpFile, E_OUTOFMEMORY);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
wcscpy(*lpCompiledHelpFile, T2CW(strCompiledHelpFile.data()) );
|
|
}
|
|
|
|
if (sc)
|
|
goto Error; // an exception was caught
|
|
|
|
Cleanup:
|
|
Trace(tagBaseSnapinISnapinHelp, _T("<-- %s::ISnapinHelp::GetHelpTopic is returning hr=%s, lpCompiledHelpFile=\"%s\""), StrSnapinClassName(), SzGetDebugNameOfHr(sc.ToHr()), strCompiledHelpFile.data());
|
|
return(sc.ToHr());
|
|
Error:
|
|
TraceError(_T("CComponentData::GetHelpTopic"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Creates a data object of the appropriate type, and returns the IDataObject interface
|
|
// on it
|
|
//
|
|
SC CComponentData::ScQueryDataObject(long cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
// The component data can handle cookie types of CCT_SNAPIN_MANAGER and CCT_SCOPE.
|
|
// CCT_RESULT are handled by CComponent.
|
|
ASSERT(type==CCT_SNAPIN_MANAGER || type==CCT_SCOPE);
|
|
|
|
//
|
|
// If the cookie does not correspond to a known object, return E_UNEXPECTED.
|
|
// This is correct and is also a workaround for an MMC bug. See X5:74405.
|
|
//
|
|
if (cookie && (Psnapin()->Pcookielist()->find(cookie) == Psnapin()->Pcookielist()->end() ) )
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pitem = Pitem(NULL, 0, cookie);
|
|
ASSERT(pitem);
|
|
|
|
sc = pitem->ScQueryDataObject(cookie, type, ppDataObject);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScQueryDataObject"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Handles the MMCN_EXPAND notification sent to IComponentData::Notify
|
|
//
|
|
SC CComponentData::ScOnExpand(LPDATAOBJECT lpDataObject, BOOL fExpand, HSCOPEITEM hscopeitem)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
if (fExpand == FALSE) // do nothing on a "contract"
|
|
goto Cleanup;
|
|
|
|
pitem = Pitem(lpDataObject, hscopeitem);
|
|
ASSERT(pitem);
|
|
|
|
// Use this opportunity to correlate the CSnapinItem and the HSCOPEITEM.
|
|
// $REVIEW (ptousig) Should be done inside Pitem().
|
|
pitem->SetHscopeitem(hscopeitem);
|
|
pitem->SetComponentData(this);
|
|
|
|
if (pitem->PitemChild())
|
|
{
|
|
// We have a list of partial children. We need to remove
|
|
// them because we are going to ask the snapin to enumerate
|
|
// all of it's children. Do not get rid of this node.
|
|
// This can happen if a node creates new children before it is
|
|
// expanded.
|
|
//
|
|
// $REVIEW (ptousig) Creating a child when the parent is not expanded
|
|
// should simply not add the child.
|
|
//
|
|
sc = pitem->ScDeleteSubTree(FALSE);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
|
|
// If we're creating the children, make sure there aren't any around.
|
|
ASSERT(pitem->PitemChild() == NULL);
|
|
|
|
sc = pitem->ScCreateChildren();
|
|
if (sc)
|
|
goto Error;
|
|
|
|
if (pitem->PitemChild())
|
|
{
|
|
// Add or remove children to/from the console.
|
|
sc = pitem->PitemChild()->ScInsertScopeItem(this, fExpand, hscopeitem);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
|
|
pitem->SetWasExpanded(TRUE);
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScOnExpand"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Called by the MMC to delete the cookies for the entire subtree under a node. This
|
|
// is only to clean up allocated objects. Do NOT call IConsoleNameSpace::DeleteItem.
|
|
//
|
|
SC CComponentData::ScOnRemoveChildren(LPDATAOBJECT lpDataObject, HSCOPEITEM hscopeitem)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
pitem = Pitem(lpDataObject, hscopeitem);
|
|
ASSERT(pitem);
|
|
|
|
// Get rid of the children.
|
|
sc = pitem->ScDeleteSubTree(FALSE);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Release the given node if it is one of the root nodes
|
|
sc = Psnapin()->ScReleaseIfRootItem(pitem);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScOnRemoveChildren"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Allows a snapin to control whether it will populate the scope pane
|
|
// in the background or not.
|
|
//
|
|
SC CComponentData::ScOnExpandSync(LPDATAOBJECT lpDataObject, MMC_EXPANDSYNC_STRUCT *pmes)
|
|
{
|
|
// We don't care.
|
|
return S_OK;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// The user has asked to delete this node.
|
|
//
|
|
SC CComponentData::ScOnDelete(LPDATAOBJECT pDataObject)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
BOOL fDeleted = FALSE;
|
|
BOOL fPagesUp = FALSE;
|
|
tstring strMsg;
|
|
|
|
pitem = Pitem(pDataObject);
|
|
ASSERT(pitem);
|
|
|
|
// The ComponentData should only receive notifications for scope pane items.
|
|
ASSERT(pitem->FIsContainer());
|
|
|
|
sc = pitem->ScIsPropertySheetOpen(&fPagesUp);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
if (fPagesUp)
|
|
{
|
|
ASSERT(FALSE && "Add below resource");
|
|
//strMsg.LoadString(_Module.GetResourceInstance(), idsPropsUpNoDelete);
|
|
strMsg += (*pitem->PstrDisplayName());
|
|
MMCErrorBox(strMsg.data());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Ask the item to delete the underlying object.
|
|
sc = pitem->ScOnDelete(&fDeleted);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
if (fDeleted == FALSE)
|
|
// The item did not want to be deleted.
|
|
goto Cleanup;
|
|
|
|
// Container items need to be deleted from the document
|
|
// Delete the item and everything below it.
|
|
sc = IpConsoleNameSpace()->DeleteItem(pitem->Hscopeitem(), TRUE);
|
|
if (sc)
|
|
goto Error;
|
|
pitem->SetHscopeitem(0);
|
|
|
|
// At this point, the item exists only in the tree, if at all.
|
|
// Remove it from the tree.
|
|
pitem->Unlink();
|
|
// Get rid of it for good from the tree of items.
|
|
pitem->Pdataobject()->Release();
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScOnDelete"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Toolbar button clicked.
|
|
//
|
|
SC CComponentData::ScOnButtonClick(LPDATAOBJECT lpDataObject, MMC_CONSOLE_VERB mcvVerb)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Used to insert a new item into the tree of items, and, if the item is a container,
|
|
// into the namespace as well. The tree and the namespace are document, not view,
|
|
// concept. This insertion is done only once.
|
|
//
|
|
SC CComponentData::ScOnDocumentChangeInsertItem(CBaseSnapinItem *pitemNew)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem * pitemParent = NULL;
|
|
|
|
ASSERT(pitemNew);
|
|
|
|
// Insert exactly once.
|
|
if (pitemNew->FInserted())
|
|
goto Cleanup;
|
|
|
|
// The parent should have already been filled in
|
|
pitemParent = pitemNew->PitemParent();
|
|
ASSERT(pitemParent);
|
|
|
|
if (pitemParent->FIncludesChild(pitemNew) == FALSE)
|
|
{
|
|
sc = pitemParent->ScAddChild(pitemNew);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
|
|
if (pitemNew->FIsContainer())
|
|
{
|
|
if (pitemParent->FWasExpanded())
|
|
{
|
|
sc = pitemNew->ScInsertScopeItem(this, TRUE, pitemParent->Hscopeitem());
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
// Only insert the item once.
|
|
pitemNew->SetInserted(TRUE);
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScOnDocumentChangeInsertItem"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Tests whether the given item has already enumerated its children.
|
|
//
|
|
SC CComponentData::ScWasExpandedOnce(CBaseSnapinItem *pitem, BOOL *pfWasExpanded)
|
|
{
|
|
SC sc = S_OK;
|
|
SCOPEDATAITEM sdi;
|
|
|
|
if (pitem->Hscopeitem() == 0)
|
|
{
|
|
//
|
|
// If we don't have an HSCOPEITEM then we are not displayed in
|
|
// the scope pane, therefore we have never been expanded (and
|
|
// probably never will).
|
|
//
|
|
*pfWasExpanded = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Ask for the state member of SCOPEDATAITEM
|
|
//
|
|
::ZeroMemory(&sdi, sizeof(SCOPEDATAITEM));
|
|
sdi.mask = SDI_STATE;
|
|
sdi.ID = pitem->Hscopeitem();
|
|
|
|
sc = IpConsoleNameSpace()->GetItem(&sdi);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
//
|
|
// If the MMC_SCOPE_ITEM_STATE_EXPANDEDONCE is on it means we have
|
|
// been asked to expand ourselves at least once before.
|
|
//
|
|
*pfWasExpanded = (sdi.nState & MMC_SCOPE_ITEM_STATE_EXPANDEDONCE) != 0;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
|
|
Error:
|
|
TraceError(_T("CComponentData::ScWasExpandedOnce"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Adds property pages for the given data object, taking into account the context and also
|
|
// whether the data object is for a new object that is being created.
|
|
//
|
|
SC CComponentData::ScCreatePropertyPages(LPPROPERTYSHEETCALLBACK ipPropertySheetCallback, long handle, LPDATAOBJECT pDataObject)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem *pitem = NULL;
|
|
|
|
pitem = Pitem(pDataObject);
|
|
ASSERT(pitem);
|
|
|
|
if (pitem->FIsSnapinManager())
|
|
{
|
|
sc = pitem->ScCreateSnapinMgrPropertyPages(ipPropertySheetCallback);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
else
|
|
{
|
|
// Simple version
|
|
sc = pitem->ScCreatePropertyPages(ipPropertySheetCallback);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Complete version - for snapins that need all information (like Recipients)
|
|
sc = pitem->ScCreatePropertyPages(ipPropertySheetCallback, handle);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScCreatePropertyPages"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Save information from the first root item.
|
|
//
|
|
// $REVIEW (ptousig) Why does the root item implement ScSave() ?
|
|
// If a snapin extends two nodes it has two root items, yet
|
|
// only one of which will be saved/loaded.
|
|
//
|
|
SC CComponentData::ScSave(IStream *pstream, BOOL fClearDirty)
|
|
{
|
|
SC sc = S_OK;
|
|
|
|
// Save the snapin's serialized information.
|
|
sc = Psnapin()->ScSave(pstream, fClearDirty);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Load the root item's serialized information.
|
|
// Only makes sense for standalone snapins.
|
|
sc = Pitem()->ScSave(pstream, fClearDirty);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScSave"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Given a dataobject, determines whether or not pages exist.
|
|
// Actually, need to return S_OK here in both cases. If no pages exist
|
|
// it is CreatePropertyPages that should return S_FALSE. Sad but true.
|
|
//
|
|
SC CComponentData::ScQueryPagesFor(LPDATAOBJECT pDataObject)
|
|
{
|
|
SC sc = S_OK;
|
|
CBaseSnapinItem * pitem = NULL;
|
|
|
|
pitem = Pitem(pDataObject);
|
|
ASSERT(pitem);
|
|
|
|
sc = pitem->ScQueryPagesFor();
|
|
if (sc)
|
|
goto Error;
|
|
|
|
Cleanup:
|
|
return sc;
|
|
Error:
|
|
TraceError(_T("CComponentData::ScQueryPagesFor"), sc);
|
|
goto Cleanup;
|
|
}
|