Leaked source code of windows server 2003
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.
 
 
 
 
 
 

6134 lines
169 KiB

//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: MTNode.cpp
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 9/17/1996 RaviR Created
//____________________________________________________________________________
//
#include "stdafx.h"
#include "nodemgr.h"
#include "comdbg.h"
#include "regutil.h"
#include "bitmap.h"
#include "dummysi.h"
#include "tasks.h"
#include "policy.h"
#include "bookmark.h"
#include "nodepath.h"
#include "siprop.h"
#include "util.h"
#include "addsnpin.h"
#include "about.h"
#include "nodemgrdebug.h"
extern const CLSID CLSID_FolderSnapin;
extern const CLSID CLSID_OCXSnapin;
extern const CLSID CLSID_HTMLSnapin;
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// {118B559C-6D8C-11d0-B503-00C04FD9080A}
const GUID IID_PersistData =
{ 0x118b559c, 0x6d8c, 0x11d0, { 0xb5, 0x3, 0x0, 0xc0, 0x4f, 0xd9, 0x8, 0xa } };
//############################################################################
//############################################################################
//
// Implementation of class CStorage
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
* class CStorage
*
*
* PURPOSE: Wrapper for IStorage. Provides several utility functions.
*
*+-------------------------------------------------------------------------*/
class CStorage
{
IStoragePtr m_spStorage;
public:
CStorage() {}
CStorage(IStorage *pStorage)
{
m_spStorage = pStorage;
}
CStorage & operator = (const CStorage &rhs)
{
m_spStorage = rhs.m_spStorage;
return *this;
}
void Attach(IStorage *pStorage)
{
m_spStorage = pStorage;
}
IStorage *Get()
{
return m_spStorage;
}
// create this storage below the specified storage
SC ScCreate(CStorage &storageParent, const wchar_t* name, DWORD grfMode, const wchar_t* instanceName)
{
SC sc;
sc = CreateDebugStorage(storageParent.Get(), name, grfMode, instanceName, &m_spStorage);
return sc;
}
SC ScMoveElementTo(const wchar_t *name, CStorage &storageDest, const wchar_t *newName, DWORD grfFlags)
{
SC sc;
if(!Get() || ! storageDest.Get())
goto PointerError;
sc = m_spStorage->MoveElementTo(name, storageDest.Get(), newName, grfFlags);
// error STG_E_FILENOTFOUND must be treated differently, since it is expected
// to occur and means the end of move operation (loop) in ScConvertLegacyNode.
// Do not trace in this case.
if(sc == SC(STG_E_FILENOTFOUND))
goto Cleanup;
if(sc)
goto Error;
Cleanup:
return sc;
PointerError:
sc = E_POINTER;
Error:
TraceError(TEXT("CStorage::ScMoveElementTo"), sc);
goto Cleanup;
}
};
//############################################################################
//############################################################################
//
// Implementation of class CStream
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
* class CStream
*
*
* PURPOSE: Wrapper for IStream. Provides several utility functions.
*
*+-------------------------------------------------------------------------*/
class CStream
{
IStreamPtr m_spStream;
typedef IStream *PSTREAM;
public:
CStream() {}
CStream(IStream *pStream)
{
m_spStream = pStream;
}
CStream & operator = (const CStream &rhs)
{
m_spStream = rhs.m_spStream;
return *this;
}
void Attach(IStream *pStream)
{
m_spStream = pStream;
}
IStream *Get()
{
return m_spStream;
}
operator IStream&()
{
return *m_spStream;
}
// create this stream below the specified storage
SC ScCreate(CStorage& storageParent, const wchar_t* name, DWORD grfMode, const wchar_t* instanceName)
{
SC sc;
sc = CreateDebugStream(storageParent.Get(), name, grfMode, instanceName, &m_spStream);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* ScRead
*
* PURPOSE: Reads the specified object from the stream.
*
* PARAMETERS:
* void * pv : The location of the object.
* size_t size : The size of the object.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC ScRead(void *pv, size_t size, bool bIgnoreErrors = false)
{
DECLARE_SC(sc, TEXT("CStream::ScRead"));
// parameter check
sc = ScCheckPointers(pv);
if (sc)
return sc;
// internal pointer check
sc = ScCheckPointers(m_spStream, E_POINTER);
if (sc)
return sc;
// read the data
ULONG bytesRead = 0;
sc = m_spStream->Read(pv, size, &bytesRead);
// if we need to ignore errors, just return.
if(bIgnoreErrors)
return sc.Clear(), sc;
if (sc)
return sc;
// since this function does not return the number of bytes read,
// failure to read as may as requested should be treated as error
if (sc == SC(S_FALSE) || bytesRead != size)
return sc = E_FAIL;
return sc;
}
/*+-------------------------------------------------------------------------*
*
* ScWrite
*
* PURPOSE: Writes the specified object to the stream
*
* PARAMETERS:
* const void :
* size_t size :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC ScWrite(const void *pv, size_t size)
{
DECLARE_SC(sc, TEXT("CStream::ScWrite"));
// parameter check
sc = ScCheckPointers(pv);
if (sc)
return sc;
// internal pointer check
sc = ScCheckPointers(m_spStream, E_POINTER);
if (sc)
return sc;
// write the data
ULONG bytesWritten = 0;
sc = m_spStream->Write(pv, size, &bytesWritten);
if (sc)
return sc;
// since this function does not return the number of bytes written,
// failure to write as may as requested should be treated as error
if (bytesWritten != size)
return sc = E_FAIL;
return sc;
}
};
/////////////////////////////////////////////////////////////////////////////
// Forward declaration of helper functions defined below
SC ScLoadBitmap (CStream &stream, HBITMAP* pBitmap);
void PersistBitmap (CPersistor &persistor, LPCTSTR name, HBITMAP& hBitmap);
static inline SC ScWriteEmptyNode(CStream &stream)
{
SC sc;
int nt = 0;
sc = stream.ScWrite(&nt, sizeof(nt));
if(sc)
goto Error;
Cleanup:
return sc;
Error:
TraceError(TEXT("ScWriteEmptyNode"), sc);
goto Cleanup;
}
static inline CLIPFORMAT GetPreLoadFormat (void)
{
static CLIPFORMAT s_cfPreLoads = 0;
if (s_cfPreLoads == 0) {
USES_CONVERSION;
s_cfPreLoads = (CLIPFORMAT) RegisterClipboardFormat (W2T(CCF_SNAPIN_PRELOADS));
}
return s_cfPreLoads;
}
//############################################################################
//############################################################################
//
// Implementation of class CMTNode
//
//############################################################################
//############################################################################
DEBUG_DECLARE_INSTANCE_COUNTER(CMTNode);
// Static member
MTNODEID CMTNode::m_NextID = ROOTNODEID;
CMTNode::CMTNode()
: m_ID(GetNextID()), m_pNext(NULL), m_pChild(NULL), m_pParent(NULL),
m_bIsDirty(true), m_cRef(1), m_usFlags(0), m_bLoaded(false),
m_bookmark(NULL), m_pPrev(NULL), m_pLastChild(NULL)
{
DEBUG_INCREMENT_INSTANCE_COUNTER(CMTNode);
Reset();
m_nImage = eStockImage_Folder;
m_nOpenImage = eStockImage_OpenFolder;
m_nState = 0;
}
void CMTNode::Reset()
{
m_idOwner = TVOWNED_MAGICWORD;
m_lUserParam = 0;
m_pPrimaryComponentData = NULL;
m_bInit = false;
m_bExtensionsExpanded = false;
m_usExpandFlags = 0;
ResetExpandedAtLeastOnce();
}
CMTNode::~CMTNode()
{
DEBUG_DECREMENT_INSTANCE_COUNTER(CMTNode);
DECLARE_SC(sc, TEXT("CMTNode::~CMTNode"));
if (IsPropertyPageDisplayed() == TRUE)
MMCIsMTNodeValid(this, TRUE);
ASSERT(m_pNext == NULL);
ASSERT(m_pPrev == NULL);
ASSERT(m_pParent == NULL);
ASSERT(m_cRef == 0);
CScopeTree *pScopeTree = CScopeTree::GetScopeTree();
sc = ScCheckPointers(pScopeTree, E_UNEXPECTED);
if (!sc)
{
sc = pScopeTree->ScUnadviseMTNode(this);
}
if (m_pChild != NULL)
{
// Don't recurse the siblings of the child.
CMTNode* pMTNodeCurr = m_pChild;
while (pMTNodeCurr)
{
m_pChild = pMTNodeCurr->Next();
pMTNodeCurr->AttachNext(NULL);
pMTNodeCurr->AttachParent(NULL);
pMTNodeCurr->AttachPrev(NULL);
pMTNodeCurr->Release();
pMTNodeCurr = m_pChild;
}
m_pChild = NULL;
}
// DON'T CHANGE THE ORDER OF THESE NULL ASSIGNMENTS!!!!!!!!!
m_spTreeStream = NULL;
m_spViewStorage = NULL;
m_spCDStorage = NULL;
m_spNodeStorage = NULL;
m_spPersistData = NULL;
if (m_pParent != NULL)
{
ASSERT(false); /* The following appears to be dead code */
if (m_pParent->m_pChild == this)
{
m_pParent->m_pChild = NULL;
if (GetStaticParent() == this)
m_pParent->SetDirty();
}
}
}
// Was MMCN_REMOVE_CHILDREN sent to the snapin owning this node or its parent
bool CMTNode::AreChildrenBeingRemoved ()
{
if (_IsFlagSet(FLAG_REMOVING_CHILDREN))
return true;
if (Parent())
return Parent()->AreChildrenBeingRemoved ();
return false;
}
CMTNode* CMTNode::FromScopeItem (HSCOPEITEM item)
{
CMTNode* pMTNode = reinterpret_cast<CMTNode*>(item);
pMTNode = dynamic_cast<CMTNode*>(pMTNode);
return (pMTNode);
}
/*+-------------------------------------------------------------------------*
* class CMMCSnapIn
*
*
* PURPOSE: The COM 0bject that exposes the SnapIn interface.
*
*+-------------------------------------------------------------------------*/
class CMMCSnapIn :
public CMMCIDispatchImpl<SnapIn>, // the View interface
public CTiedComObject<CMTSnapInNode>
{
typedef CMTSnapInNode CMyTiedObject;
typedef std::auto_ptr<CSnapinAbout> SnapinAboutPtr;
public:
BEGIN_MMC_COM_MAP(CMMCSnapIn)
END_MMC_COM_MAP()
public:
MMC_METHOD1(get_Name, PBSTR /*pbstrName*/);
STDMETHOD(get_Vendor)( PBSTR pbstrVendor );
STDMETHOD(get_Version)( PBSTR pbstrVersion );
MMC_METHOD1(get_Extensions, PPEXTENSIONS /*ppExtensions*/);
MMC_METHOD1(get_SnapinCLSID,PBSTR /*pbstrSnapinCLSID*/);
MMC_METHOD1(get_Properties, PPPROPERTIES /*ppProperties*/);
MMC_METHOD1(EnableAllExtensions, BOOL /*bEnable*/);
// not an interface method,
// just a convenient way to reach for tied object's method
MMC_METHOD1(GetSnapinClsid, CLSID& /*clsid*/);
CMTSnapInNode *GetMTSnapInNode();
private:
::SC ScGetSnapinAbout(CSnapinAbout*& pAbout);
private:
SnapinAboutPtr m_spSnapinAbout;
};
/*+-------------------------------------------------------------------------*
* class CExtension
*
*
* PURPOSE: The COM 0bject that exposes the SnapIn interface.
*
* This extension is not tied to any object. An extension snapin instance
* can be uniquely identified by combination of its class-id & its primary
* snapin's class-id. So this object just stores this data.
* See addsnpin.h for more comments.
*
*+-------------------------------------------------------------------------*/
class CExtension :
public CMMCIDispatchImpl<Extension>
{
typedef std::auto_ptr<CSnapinAbout> SnapinAboutPtr;
public:
BEGIN_MMC_COM_MAP(CExtension)
END_MMC_COM_MAP()
public:
STDMETHODIMP get_Name( PBSTR pbstrName);
STDMETHODIMP get_Vendor( PBSTR pbstrVendor);
STDMETHODIMP get_Version( PBSTR pbstrVersion);
STDMETHODIMP get_Extensions( PPEXTENSIONS ppExtensions);
STDMETHODIMP get_SnapinCLSID( PBSTR pbstrSnapinCLSID);
STDMETHODIMP EnableAllExtensions(BOOL bEnable);
STDMETHODIMP Enable(BOOL bEnable = TRUE);
CExtension() : m_clsidAbout(GUID_NULL) {}
void Init(const CLSID& clsidExtendingSnapin, const CLSID& clsidThisExtension, const CLSID& clsidAbout)
{
m_clsidExtendingSnapin = clsidExtendingSnapin;
m_clsidThisExtension = clsidThisExtension;
m_clsidAbout = clsidAbout;
}
LPCOLESTR GetVersion()
{
CSnapinAbout *pSnapinAbout = GetSnapinAbout();
if (! pSnapinAbout)
return NULL;
return pSnapinAbout->GetVersion();
}
LPCOLESTR GetVendor()
{
CSnapinAbout *pSnapinAbout = GetSnapinAbout();
if (! pSnapinAbout)
return NULL;
return pSnapinAbout->GetCompanyName();
}
private:
CSnapinAbout* GetSnapinAbout()
{
// If about object is already created just return it.
if (m_spExtensionAbout.get())
return m_spExtensionAbout.get();
if (m_clsidAbout == GUID_NULL)
return NULL;
// Else create & initialize the about object.
m_spExtensionAbout = SnapinAboutPtr (new CSnapinAbout);
if (! m_spExtensionAbout.get())
return NULL;
if (m_spExtensionAbout->GetSnapinInformation(m_clsidAbout))
return m_spExtensionAbout.get();
return NULL;
}
private:
CLSID m_clsidThisExtension;
CLSID m_clsidExtendingSnapin;
CLSID m_clsidAbout;
SnapinAboutPtr m_spExtensionAbout;
};
//############################################################################
//############################################################################
//
// Implementation of class CExtensions
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
* class CExtensions
*
*
* PURPOSE: Implements the Extensions automation interface.
*
* The Scget_Extensions uses this class as a template parameter to the typedef
* below. The typedef is an array of Extension objects, that needs atleast below
* empty class declared. Scget_Extensions adds the extensions to the array.
*
* typedef CComObject< CMMCArrayEnum<Extensions, Extension> > CMMCExtensions;
*
*+-------------------------------------------------------------------------*/
class CExtensions :
public CMMCIDispatchImpl<Extensions>,
public CTiedObject // enumerators are tied to it
{
protected:
typedef void CMyTiedObject;
};
// Helper functions used by both CMMCSnapIn as well as CExtension.
SC Scget_Extensions(const CLSID& clsidPrimarySnapin, PPEXTENSIONS ppExtensions);
SC ScEnableAllExtensions (const CLSID& clsidPrimarySnapin, BOOL bEnable);
//+-------------------------------------------------------------------
//
// Member: Scget_Extensions
//
// Synopsis: Helper function, given class-id of primary creates &
// returns the extensions collection for this snapin.
//
// Arguments: [clsidPrimarySnapin] -
// [ppExtensions] - out param, extensions collection.
//
// Returns: SC
//
// Note: Collection does not include dynamic extensions.
//
//--------------------------------------------------------------------
SC Scget_Extensions(const CLSID& clsidPrimarySnapin, PPEXTENSIONS ppExtensions)
{
DECLARE_SC(sc, TEXT("Scget_Extensions"));
sc = ScCheckPointers(ppExtensions);
if (sc)
return sc;
*ppExtensions = NULL;
// Create the extensions collection (which also implements the enumerator).
typedef CComObject< CMMCArrayEnum<Extensions, Extension> > CMMCExtensions;
CMMCExtensions *pMMCExtensions = NULL;
sc = CMMCExtensions::CreateInstance(&pMMCExtensions);
if (sc)
return sc;
sc = ScCheckPointers(pMMCExtensions, E_UNEXPECTED);
if (sc)
return sc;
typedef CComPtr<Extension> CMMCExtensionPtr;
typedef std::vector<CMMCExtensionPtr> ExtensionSnapins;
ExtensionSnapins extensions;
// Now get the extensions for this collection from this snapin.
CExtensionsCache extnsCache;
sc = MMCGetExtensionsForSnapIn(clsidPrimarySnapin, extnsCache);
if (sc)
return sc;
// Create Extension object for each non-dynamic extension.
CExtensionsCacheIterator it(extnsCache);
for (; it.IsEnd() == FALSE; it.Advance())
{
// Collection does not include dynamic extensions.
if (CExtSI::EXT_TYPE_DYNAMIC & it.GetValue())
continue;
typedef CComObject<CExtension> CMMCExtensionSnap;
CMMCExtensionSnap *pExtension = NULL;
sc = CMMCExtensionSnap::CreateInstance(&pExtension);
if (sc)
return sc;
sc = ScCheckPointers(pExtension, E_UNEXPECTED);
if (sc)
return sc;
CLSID clsidAbout;
sc = ScGetAboutFromSnapinCLSID(it.GetKey(), clsidAbout);
if (sc)
sc.TraceAndClear();
// Make the Extension aware of its primary snapin & about object.
pExtension->Init(clsidPrimarySnapin, it.GetKey(), clsidAbout);
extensions.push_back(pExtension);
}
// Fill this data into the extensions collection.
pMMCExtensions->Init(extensions.begin(), extensions.end());
sc = pMMCExtensions->QueryInterface(ppExtensions);
if (sc)
return sc;
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: ScEnableAllExtensions
//
// Synopsis: Helper function, given class-id of primary enables
// all extensions or un-checks the enable all so that
// individual extension can be disabled.
//
// Arguments: [clsidPrimarySnapin] -
// [bEnable] - enable or disable.
//
// Returns: SC
//
// Note: Collection does not include dynamic extensions.
//
//--------------------------------------------------------------------
SC ScEnableAllExtensions (const CLSID& clsidPrimarySnapin, BOOL bEnable)
{
DECLARE_SC(sc, _T("ScEnableAllExtensions"));
// Create snapin manager.
CScopeTree *pScopeTree = CScopeTree::GetScopeTree();
sc = ScCheckPointers(pScopeTree, E_UNEXPECTED);
if (sc)
return sc.ToHr();
CSnapinManager snapinMgr(pScopeTree->GetRoot());
// Ask the snapinMgr to enable/disable its extensions.
sc = snapinMgr.ScEnableAllExtensions(clsidPrimarySnapin, bEnable);
if (sc)
return sc.ToHr();
// Update the scope tree with changes made by snapin manager.
sc = pScopeTree->ScAddOrRemoveSnapIns(snapinMgr.GetDeletedNodesList(),
snapinMgr.GetNewNodes());
if (sc)
return sc.ToHr();
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: CExtension::get_Name
//
// Synopsis: Return the name of this extension.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::get_Name (PBSTR pbstrName)
{
DECLARE_SC(sc, _T("CExtension::get_Name"));
sc = ScCheckPointers(pbstrName);
if (sc)
return sc.ToHr();
*pbstrName = NULL;
tstring tszSnapinName;
bool bRet = GetSnapinNameFromCLSID(m_clsidThisExtension, tszSnapinName);
if (!bRet)
return (sc = E_FAIL).ToHr();
USES_CONVERSION;
*pbstrName = SysAllocString(T2COLE(tszSnapinName.data()));
if ( (! *pbstrName) && (tszSnapinName.length() > 0) )
return (sc = E_OUTOFMEMORY).ToHr();
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: CExtension::get_Vendor
//
// Synopsis: Get the vendor information for this extension if it exists.
//
// Arguments: [pbstrVendor] - out param, ptr to vendor info.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::get_Vendor (PBSTR pbstrVendor)
{
DECLARE_SC(sc, _T("CExtension::get_Vendor"));
sc = ScCheckPointers(pbstrVendor);
if (sc)
return sc.ToHr();
LPCOLESTR lpszVendor = GetVendor();
*pbstrVendor = SysAllocString(lpszVendor);
if ((lpszVendor) && (! *pbstrVendor))
return (sc = E_OUTOFMEMORY).ToHr();
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: CExtension::get_Version
//
// Synopsis: Get the version info for this extension if it exists.
//
// Arguments: [pbstrVersion] - out param, ptr to version info.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::get_Version (PBSTR pbstrVersion)
{
DECLARE_SC(sc, _T("CExtension::get_Version"));
sc = ScCheckPointers(pbstrVersion);
if (sc)
return sc.ToHr();
LPCOLESTR lpszVersion = GetVersion();
*pbstrVersion = SysAllocString(lpszVersion);
if ((lpszVersion) && (! *pbstrVersion))
return (sc = E_OUTOFMEMORY).ToHr();
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: CExtension::get_SnapinCLSID
//
// Synopsis: Get the extension snapin class-id.
//
// Arguments: [pbstrSnapinCLSID] - out param, snapin class-id.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::get_SnapinCLSID (PBSTR pbstrSnapinCLSID)
{
DECLARE_SC(sc, _T("CExtension::get_SnapinCLSID"));
sc = ScCheckPointers(pbstrSnapinCLSID);
if (sc)
return sc.ToHr();
CCoTaskMemPtr<OLECHAR> szSnapinClsid;
sc = StringFromCLSID(m_clsidThisExtension, &szSnapinClsid);
if (sc)
return sc.ToHr();
*pbstrSnapinCLSID = SysAllocString(szSnapinClsid);
if (! *pbstrSnapinCLSID)
sc = E_OUTOFMEMORY;
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: CExtension::ScEnable
//
// Synopsis: Enable or disable this extension
//
// Arguments: [bEnable] - enable or disable.
//
// Returns: SC
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::Enable (BOOL bEnable /*= TRUE*/)
{
DECLARE_SC(sc, _T("CExtension::ScEnable"));
/*
* 1. Create snapin manager.
* 2. Ask snapin mgr to disable this snapin.
*/
// Create snapin manager.
CScopeTree *pScopeTree = CScopeTree::GetScopeTree();
sc = ScCheckPointers(pScopeTree, E_UNEXPECTED);
if (sc)
return sc.ToHr();
CSnapinManager snapinMgr(pScopeTree->GetRoot());
// Ask the snapinMgr to disable this extension.
sc = snapinMgr.ScEnableExtension(m_clsidExtendingSnapin, m_clsidThisExtension, bEnable);
if (sc)
return sc.ToHr();
// Update the scope tree with changes made by snapin manager.
sc = pScopeTree->ScAddOrRemoveSnapIns(snapinMgr.GetDeletedNodesList(),
snapinMgr.GetNewNodes());
if (sc)
return sc.ToHr();
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: CExtension::Scget_Extensions
//
// Synopsis: Get the extensions collection for this snapin.
//
// Arguments: [ppExtensions] - out ptr to extensions collection.
//
// Returns: SC
//
//--------------------------------------------------------------------
HRESULT CExtension::get_Extensions( PPEXTENSIONS ppExtensions)
{
DECLARE_SC(sc, _T("CExtension::get_Extensions"));
sc = ScCheckPointers(ppExtensions);
if (sc)
return sc.ToHr();
*ppExtensions = NULL;
sc = ::Scget_Extensions(m_clsidThisExtension, ppExtensions);
if (sc)
return sc.ToHr();
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: CExtension::EnableAllExtensions
//
// Synopsis: Enable/Disable all the extensions of this snapin.
//
// Arguments:
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CExtension::EnableAllExtensions(BOOL bEnable)
{
DECLARE_SC(sc, TEXT("CExtension::EnableAllExtensions"));
sc = ::ScEnableAllExtensions(m_clsidThisExtension, bEnable);
if (sc)
return sc.ToHr();
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::ScGetCMTSnapinNode
//
// Synopsis: Static function, given PSNAPIN (SnapIn interface)
// return the CMTSnapInNode of that snapin.
//
// Arguments: [pSnapIn] - Snapin interface.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::ScGetCMTSnapinNode(PSNAPIN pSnapIn, CMTSnapInNode **ppMTSnapInNode)
{
DECLARE_SC(sc, _T("CMTSnapInNode::GetCMTSnapinNode"));
sc = ScCheckPointers(pSnapIn, ppMTSnapInNode);
if (sc)
return sc;
*ppMTSnapInNode = NULL;
CMMCSnapIn *pMMCSnapIn = dynamic_cast<CMMCSnapIn*>(pSnapIn);
if (!pMMCSnapIn)
return (sc = E_UNEXPECTED);
*ppMTSnapInNode = pMMCSnapIn->GetMTSnapInNode();
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::Scget_Name
//
// Synopsis: Return the name of this snapin.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::Scget_Name (PBSTR pbstrName)
{
DECLARE_SC(sc, _T("CMTSnapInNode::Scget_Name"));
sc = ScCheckPointers(pbstrName);
if (sc)
return sc;
*pbstrName = NULL;
CSnapIn *pSnapin = GetPrimarySnapIn();
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
WTL::CString strSnapInName;
sc = pSnapin->ScGetSnapInName(strSnapInName);
if (sc)
return sc;
USES_CONVERSION;
*pbstrName = strSnapInName.AllocSysString();
if ( (! *pbstrName) && (strSnapInName.GetLength() > 0) )
return (sc = E_OUTOFMEMORY);
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::Scget_Extensions
//
// Synopsis: Get the extensions collection for this snapin.
//
// Arguments: [ppExtensions] - out ptr to extensions collection.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::Scget_Extensions( PPEXTENSIONS ppExtensions)
{
DECLARE_SC(sc, _T("CMTSnapInNode::Scget_Extensions"));
sc = ScCheckPointers(ppExtensions);
if (sc)
return sc;
*ppExtensions = NULL;
CSnapIn *pSnapin = GetPrimarySnapIn();
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
sc = ::Scget_Extensions(pSnapin->GetSnapInCLSID(), ppExtensions);
if (sc)
return sc;
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::ScGetSnapinClsid
//
// Synopsis: Gets the CLSID of snapin
//
// Arguments: CLSID& clsid [out] - class id of snapin.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::ScGetSnapinClsid(CLSID& clsid)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScGetAboutClsid"));
// init out param
clsid = GUID_NULL;
CSnapIn *pSnapin = GetPrimarySnapIn();
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
clsid = pSnapin->GetSnapInCLSID();
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::Scget_SnapinCLSID
//
// Synopsis: Get the CLSID for this snapin.
//
// Arguments: [pbstrSnapinCLSID] - out ptr to CLSID.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::Scget_SnapinCLSID( PBSTR pbstrSnapinCLSID)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::Scget_SnapinCLSID"));
sc = ScCheckPointers(pbstrSnapinCLSID);
if (sc)
return sc;
CSnapIn *pSnapin = GetPrimarySnapIn();
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
CCoTaskMemPtr<OLECHAR> szSnapinClsid;
sc = StringFromCLSID(pSnapin->GetSnapInCLSID(), &szSnapinClsid);
if (sc)
return sc.ToHr();
*pbstrSnapinCLSID = SysAllocString(szSnapinClsid);
if (! *pbstrSnapinCLSID)
sc = E_OUTOFMEMORY;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CMTSnapInNode::ScEnableAllExtensions
//
// Synopsis: Enable or not enable all extensions of this snapin.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTSnapInNode::ScEnableAllExtensions (BOOL bEnable)
{
DECLARE_SC(sc, _T("CMTSnapInNode::ScEnableAllExtensions"));
CSnapIn *pSnapin = GetPrimarySnapIn();
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
sc = ::ScEnableAllExtensions(pSnapin->GetSnapInCLSID(), bEnable);
if (sc)
return sc;
return (sc);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::Scget_Properties
*
* Returns a pointer to the snap-in's Properties object
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::Scget_Properties( PPPROPERTIES ppProperties)
{
DECLARE_SC (sc, _T("CMTSnapInNode::Scget_Properties"));
/*
* validate parameters
*/
sc = ScCheckPointers (ppProperties);
if (sc)
return (sc);
*ppProperties = m_spProps;
/*
* If the snap-in doesn't support ISnapinProperties, don't return
* a Properties interface. This is not an error, but rather a valid
* unsuccessful return, so we return E_NOINTERFACE directly instead
* of assigning to sc first.
*/
if (m_spProps == NULL)
return (E_NOINTERFACE);
/*
* put a ref on for the client
*/
(*ppProperties)->AddRef();
return (sc);
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::ScGetSnapIn
*
* PURPOSE: Returns a pointer to the SnapIn object.
*
* PARAMETERS:
* PPSNAPIN ppSnapIn :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CMTSnapInNode::ScGetSnapIn(PPSNAPIN ppSnapIn)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScGetSnapIn"));
sc = ScCheckPointers(ppSnapIn);
if(sc)
return sc;
// initialize out parameter
*ppSnapIn = NULL;
// create a CMMCView if needed.
sc = CTiedComObjectCreator<CMMCSnapIn>::ScCreateAndConnect(*this, m_spSnapIn);
if(sc)
return sc;
if(m_spSnapIn == NULL)
{
sc = E_UNEXPECTED;
return sc;
}
// addref the pointer for the client.
m_spSnapIn->AddRef();
*ppSnapIn = m_spSnapIn;
return sc;
}
HRESULT CMTNode::OpenStorageForNode()
{
if (m_spNodeStorage != NULL)
return S_OK;
ASSERT(m_spPersistData != NULL);
if (m_spPersistData == NULL)
return E_POINTER;
// Get the storage for all of the nodes
IStorage* const pAllNodes = m_spPersistData->GetNodeStorage();
ASSERT(pAllNodes != NULL);
if (pAllNodes == NULL)
return E_POINTER;
// Create the outer storage for this node
WCHAR name[MAX_PATH];
HRESULT hr = OpenDebugStorage(pAllNodes, GetStorageName(name),
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, L"\\node\\#", &m_spNodeStorage);
return hr == S_OK ? S_OK : E_FAIL;
}
HRESULT CMTNode::OpenStorageForView()
{
if (m_spViewStorage != NULL)
return S_OK;
// Get the storage for all of the nodes
IStorage* const pNodeStorage = GetNodeStorage();
ASSERT(pNodeStorage != NULL);
if (pNodeStorage == NULL)
return E_FAIL;
// Create the outer storage for this node
WCHAR name[MAX_PATH];
HRESULT hr = OpenDebugStorage(pNodeStorage, L"view",
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, L"\\node\\#\\view",
&m_spViewStorage);
return hr == S_OK ? S_OK : E_FAIL;
}
HRESULT CMTNode::OpenStorageForCD()
{
if (m_spCDStorage != NULL)
return S_OK;
// Get the storage for all of the nodes
IStorage* const pNodeStorage = GetNodeStorage();
ASSERT(pNodeStorage != NULL);
if (pNodeStorage == NULL)
return E_FAIL;
// Create the outer storage for this node
WCHAR name[MAX_PATH];
HRESULT hr = OpenDebugStorage(pNodeStorage, L"data",
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, L"\\node\\#\\data",
&m_spCDStorage);
return hr == S_OK ? S_OK : E_FAIL;
}
HRESULT CMTNode::OpenTreeStream()
{
if (m_spTreeStream != NULL)
{
const LARGE_INTEGER loc = {0,0};
ULARGE_INTEGER newLoc;
HRESULT hr = m_spTreeStream->Seek(loc, STREAM_SEEK_SET, &newLoc);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
return S_OK;
}
HRESULT hr = OpenStorageForNode();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
hr = OpenStorageForView();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
hr = OpenStorageForCD();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
IStorage* const pTreeNodes = GetNodeStorage();
ASSERT(pTreeNodes != NULL);
if (pTreeNodes == NULL)
return E_POINTER;
hr = OpenDebugStream(pTreeNodes, L"tree",
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, L"\\node\\#\\tree", &m_spTreeStream);
ASSERT(SUCCEEDED(hr) && m_spTreeStream != NULL);
return SUCCEEDED(hr) ? S_OK : E_FAIL;
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::NextStaticNode
*
* PURPOSE:
*
* PARAMETERS:
*
* RETURNS: NULL if not found, else the next CMTSnapInNode.
* inline
*
* NOTE: This performance is poor! Improve by indexing all CMTSnapInNodes
* separately.
*+-------------------------------------------------------------------------*/
CMTNode*
CMTNode::NextStaticNode()
{
CMTNode *pNext = this;
while (pNext)
{
if (pNext->IsStaticNode())
return pNext;
pNext = pNext->Next();
}
return NULL;
}
HRESULT CMTNode::IsDirty()
{
if (GetDirty())
{
TraceDirtyFlag(TEXT("CMTNode"), true);
return S_OK;
}
HRESULT hr;
CMTNode* const pChild = m_pChild->NextStaticNode();
if (pChild)
{
hr = pChild->IsDirty();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CMTNode"), true);
return hr;
}
}
CMTNode* const pNext = m_pNext->NextStaticNode();
if (pNext)
{
hr = pNext->IsDirty();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CMTNode"), true);
return hr;
}
}
TraceDirtyFlag(TEXT("CMTNode"), false);
return S_FALSE;
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::InitNew
*
* PURPOSE:
*
* PARAMETERS:
* PersistData* d :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT
CMTNode::InitNew(PersistData* d)
{
SC sc;
CStream treeStream;
if ( (m_spPersistData != NULL) || (d==NULL) || !IsStaticNode())
goto FailedError;
m_spPersistData = d;
if (m_spPersistData == NULL)
goto ArgumentError;
sc = InitNew();
if(sc)
goto Error;
// Get the stream for persistence of the tree
treeStream.Attach( m_spPersistData->GetTreeStream());
// recurse thru children
{
CMTNode* const pChild = m_pChild->NextStaticNode();
if (pChild)
{
sc = pChild->InitNew(d);
if(sc)
goto Error;
}
else
{
sc = ScWriteEmptyNode(treeStream);
if(sc)
goto Error;
}
}
// chain to next node.
{
CMTNode* const pNext = m_pNext->NextStaticNode();
if (pNext)
{
sc = pNext->InitNew(d);
if(sc)
goto Error;
}
else
{
sc = ScWriteEmptyNode(treeStream);
if(sc)
goto Error;
}
}
Cleanup:
return HrFromSc(sc);
FailedError:
sc = E_FAIL;
goto Error;
ArgumentError:
sc = E_INVALIDARG;
Error:
TraceError(TEXT("CMTNode::InitNew"), sc);
goto Cleanup;
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::Persist
*
* PURPOSE: Persists the CMTNode to the specified persistor.
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CMTNode::Persist(CPersistor& persistor)
{
MTNODEID id = GetID(); // persist the node id
persistor.PersistAttribute(XML_ATTR_MT_NODE_ID, id);
SetID(id);
// Save the children
CPersistor persistorSubNode(persistor, XML_TAG_SCOPE_TREE_NODES);
if (persistor.IsStoring())
{
CMTNode* pChild = m_pChild->NextStaticNode();
while (pChild)
{
persistorSubNode.Persist(*pChild);
// get next node
pChild = pChild->Next();
// advance if it is not a static node
pChild = (pChild ? pChild->NextStaticNode() : NULL);
}
ClearDirty();
}
else
{
XMLListCollectionBase::Persist(persistorSubNode);
}
UINT nImage = m_nImage;
if (nImage > eStockImage_Max) // if SnapIn changed icon dynamically, then
nImage = eStockImage_Folder; // this value will be bogus next time:
// replace w/ 0 (closed folder)
persistor.PersistAttribute(XML_ATTR_MT_NODE_IMAGE, nImage);
persistor.PersistString(XML_ATTR_MT_NODE_NAME, m_strName);
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::OnNewElement
*
* PURPOSE: called for each new child node found in XML doc
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CMTNode::OnNewElement(CPersistor& persistor)
{
DECLARE_SC(sc, TEXT("CMTNode::OnNewElement"));
// load the child
CMTNode* pChild;
// attach to the list
PersistNewNode(persistor, &pChild);
if (pChild)
{
// Insert after m_pLastChild (at the last position).
// If m_pLastChild is NULL, insert as the first and only child.
sc = ScInsertChild(pChild, m_pLastChild);
}
}
//+-------------------------------------------------------------------
//
// Member: CMTNode::ScLoad
//
// Synopsis: Loads the MTNode from the specified stream.
// COMPATIBILITY issues: MMC1.0 through MMC1.2 used special built-in
// node types to represent Folder, Web Link, and ActiveX control
// nodes. MMC2.0 and higher use snap-ins instead. The only special
// node is Console Root, which is still saved and loaded as a Folder
// node with ID = 1.
//
// Arguments: d [IN]: Data Stream to load the node from.
// ppNode [OUT]: Non-Null pointer to the pointer to the loaded
// node.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTNode::ScLoad(PersistData* d, CMTNode** ppNode)
{
// Call helper method with NULL parent (for Root node) and
// NULL prev (Insert at first position).
return ScLoad(d, ppNode, NULL, NULL);
}
//+-------------------------------------------------------------------
//
// Member: CMTNode::ScLoad
//
// Synopsis: Helper for ScLoad(PersistData*, CMTNode**). Uses Recusrion
//
// Arguments: d [IN]: Data Stream to load the node from
// ppNode [OUT]: Non-Null pointer to the pointer to the loaded
// node.
// pParent [IN]: Pointer to the node under which the node is to be
// loaded.
// pPrev [IN]: Pointer to the node after which the node is to be
// loaded.
//
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTNode::ScLoad(PersistData* d, CMTNode** ppNode, CMTNode* pParent, CMTNode *pPrev)
{
DECLARE_SC(sc, TEXT("CMTNode::ScLoad"));
CMTSnapInNode* pmtSnapInNode = NULL;
CStream treeStream;
// check parameters
sc = ScCheckPointers(d, ppNode);
if(sc)
return sc;
*ppNode = NULL;
// Read the type of node from the stream.
treeStream.Attach(d->GetTreeStream());
int nt;
sc = treeStream.ScRead(&nt, sizeof(nt));
if(sc)
return sc;
if (!nt)
return sc;
if (!(nt == NODE_CODE_SNAPIN || nt == NODE_CODE_FOLDER ||
nt == NODE_CODE_HTML || nt == NODE_CODE_OCX))
return (sc = E_FAIL); // invalid node type.
// Read the storage key
MTNODEID id;
sc = treeStream.ScRead(&id, sizeof(id));
if(sc)
return sc;
// Create a node of the appropriate type. Everything, including Console Root
// uses CMTSnapInNode.
if( nt == NODE_CODE_FOLDER || nt == NODE_CODE_SNAPIN || nt == NODE_CODE_HTML || nt == NODE_CODE_OCX )
{
pmtSnapInNode = new CMTSnapInNode (NULL);
ASSERT(pmtSnapInNode != NULL);
if (pmtSnapInNode == NULL)
return E_POINTER;
*ppNode = pmtSnapInNode;
}
else
return (sc = E_UNEXPECTED); // should never happen
(*ppNode)->m_bLoaded = true;
ASSERT((*ppNode)->m_spPersistData == NULL);
ASSERT(d != NULL);
(*ppNode)->m_spPersistData = d;
ASSERT((*ppNode)->m_spPersistData != NULL);
if ((*ppNode)->m_spPersistData == NULL)
return E_INVALIDARG;
(*ppNode)->SetID(id);
if (id >= m_NextID)
m_NextID = id+1;
// Open the stream for the nodes data
sc = (*ppNode)->OpenTreeStream();
if (sc)
{
(*ppNode)->Release();
*ppNode = NULL;
return sc;
}
// Load the node
// If old style node, then convert to snap-in type node
switch (nt)
{
case NODE_CODE_SNAPIN:
sc = (*ppNode)->ScLoad();
break;
// All folder nodes, INCLUDING old-style console root nodes, are upgraded to snap-ins.
case NODE_CODE_FOLDER:
if(pmtSnapInNode == NULL)
return (sc = E_UNEXPECTED);
sc = pmtSnapInNode->ScConvertLegacyNode(CLSID_FolderSnapin);
break;
case NODE_CODE_HTML:
sc = pmtSnapInNode->ScConvertLegacyNode(CLSID_HTMLSnapin);
break;
case NODE_CODE_OCX:
sc = pmtSnapInNode->ScConvertLegacyNode(CLSID_OCXSnapin);
break;
default:
ASSERT(0 && "Invalid node type");
sc = E_FAIL;
}
if (sc)
{
(*ppNode)->Release();
*ppNode = NULL;
return sc;
}
// Set the parent pointer before loading the children or the siblings
if(pParent) // Do not insert if pParent is NULL (as for the root node)
{
// Insert after pPrev. If pPrev is NULL, insert as the first child.
sc = pParent->ScInsertChild(*ppNode, pPrev);
if (sc)
{
(*ppNode)->Release();
*ppNode = NULL;
return sc;
}
}
// load the children
CMTNode* pChild;
sc = ScLoad(d, &pChild, *ppNode, NULL); // NULL ==> Insert at First Position
if (sc)
{
(*ppNode)->Release();
*ppNode = NULL;
return sc;
}
// Load siblings
CMTNode* pNext;
CMTNode * pTemp = NULL;
// IMPORTANT - why are we passing pTemp instead of & (*ppNode->Next()) ? This is because
// the latter automatically gets set owing to the fourth parameter. This caused a bug when the second
// parameter also caused the Next() pointer to get set - in effect, the node was being set as its own
// sibling.
sc = ScLoad(d, &pTemp, pParent, *ppNode);
if (sc)
{
(*ppNode)->Release();
*ppNode = NULL;
return sc;
}
(*ppNode)->SetDirty(false);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::PersistNewNode
*
* PURPOSE: Loads the MTNode from the persistor.
*
*+-------------------------------------------------------------------------*/
void CMTNode::PersistNewNode(CPersistor &persistor, CMTNode** ppNode)
{
DECLARE_SC(sc, TEXT("CMTNode::PersistNewNode"));
CMTSnapInNode* pmtSnapInNode = NULL;
const int CONSOLE_ROOT_ID = 1;
// check parameters
sc = ScCheckPointers(ppNode);
if (sc)
sc.Throw();
*ppNode = NULL;
// Create a node of the snapin type. Everything uses CMTSnapInNode.
pmtSnapInNode = new CMTSnapInNode(NULL);
sc = ScCheckPointers(pmtSnapInNode,E_OUTOFMEMORY);
if (sc)
sc.Throw();
*ppNode = pmtSnapInNode;
(*ppNode)->m_bLoaded = true;
ASSERT((*ppNode)->m_spPersistData == NULL);
try
{
persistor.Persist(**ppNode);
}
catch(...)
{
// ensure cleanup here
(*ppNode)->Release();
*ppNode = NULL;
throw;
}
// update index for new nodes
MTNODEID id = (*ppNode)->GetID();
if (id >= m_NextID)
m_NextID = id+1;
(*ppNode)->SetDirty(false);
}
HRESULT CMTNode::DestroyElements()
{
if (!IsStaticNode())
return S_OK;
HRESULT hr;
if (m_pChild != NULL)
{
hr = m_pChild->DestroyElements();
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
}
return DoDestroyElements();
}
HRESULT CMTNode::DoDestroyElements()
{
if (m_spPersistData == NULL)
return S_OK;
IStorage* const pNodeStorage = m_spPersistData->GetNodeStorage();
ASSERT(pNodeStorage != NULL);
if (pNodeStorage == NULL)
return S_OK;
WCHAR name[MAX_PATH];
HRESULT hr = pNodeStorage->DestroyElement(GetStorageName(name));
SetDirty();
CMTNode* const psParent = m_pParent != NULL ? m_pParent->GetStaticParent() : NULL;
if (psParent != NULL)
psParent->SetDirty();
return S_OK;
}
void CMTNode::SetParent(CMTNode* pParent)
{
m_pParent = pParent;
if (m_pNext)
m_pNext->SetParent(pParent);
}
HRESULT CMTNode::CloseView(int idView)
{
if (!IsStaticNode())
return S_OK;
HRESULT hr;
CMTNode* const pChild = m_pChild->NextStaticNode();
if (pChild)
{
hr = pChild->CloseView(idView);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
}
CMTNode* const pNext = m_pNext->NextStaticNode();
if (pNext)
{
hr = pNext->CloseView(idView);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
}
return S_OK;
}
HRESULT CMTNode::DeleteView(int idView)
{
if (!IsStaticNode())
return S_OK;
HRESULT hr;
CMTNode* const pChild = m_pChild->NextStaticNode();
if (pChild)
{
hr = pChild->DeleteView(idView);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
}
CMTNode* const pNext = m_pNext->NextStaticNode();
if (pNext)
{
hr = pNext->DeleteView(idView);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
}
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: GetBookmark
//
// Synopsis: Get bookmark for this MTNode.
//
// Arguments: None.
//
// Returns: auto pointer to CBookmark.
//
// History: 04-23-1999 AnandhaG Created
//
//--------------------------------------------------------------------
CBookmark* CMTNode::GetBookmark()
{
DECLARE_SC(sc, TEXT("CMTNode::GetBookmark"));
// If the bookmark is not created, create one.
if (NULL == m_bookmark.get())
{
m_bookmark = std::auto_ptr<CBookmarkEx>(new CBookmarkEx);
if (NULL == m_bookmark.get())
return NULL;
m_bookmark->Reset();
SC sc = m_bookmark->ScInitialize(this, GetStaticParent(), false /*bFastRetrievalOnly*/);
if(sc)
sc.TraceAndClear(); // change
}
return m_bookmark.get();
}
void
CMTNode::SetCachedDisplayName(LPCTSTR pszName)
{
if (m_strName.str() != pszName)
{
m_strName = pszName;
SetDirty();
if (Parent())
Parent()->OnChildrenChanged();
}
}
UINT
CMTNode::GetState(void)
{
UINT nState = 0;
if (WasExpandedAtLeastOnce())
{
nState |= MMC_SCOPE_ITEM_STATE_EXPANDEDONCE;
}
return nState;
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::ScLoad
*
* PURPOSE: Loads the node from the tree stream
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CMTNode::ScLoad()
{
ASSERT (IsStaticNode());
SC sc;
CStream stream;
stream.Attach(GetTreeStream());
HRESULT hr;
IStringTablePrivate* pStringTable = CScopeTree::GetStringTable();
ASSERT (pStringTable != NULL);
/*
* read the "versioned stream" marker
*/
StreamVersionIndicator nVersionMarker;
sc = stream.ScRead(&nVersionMarker, sizeof(nVersionMarker));
if(sc)
goto Error;
/*
* Determine the stream version number. If this is a versioned
* stream, the version is the next DWORD in the stream, otherwise
* it must be it's a version 1 stream
*/
StreamVersionIndicator nVersion;
if (nVersionMarker == VersionedStreamMarker)
{
sc = stream.ScRead(&nVersion, sizeof(nVersion));
if(sc)
goto Error;
}
else
nVersion = Stream_V0100;
switch (nVersion)
{
/*
* MMC 1.0 stream
*/
case Stream_V0100:
{
/*
* Version 1 streams didn't have a version marker; they began with
* the image index as the first DWORD. The first DWORD has
* already been read (version marker), so we can recycle that
* value for the image index.
*/
m_nImage = nVersionMarker;
/*
* Continue reading with the display name (length then characters)
*/
unsigned int stringLength = 0;
sc = stream.ScRead(&stringLength, sizeof(stringLength));
if(sc)
goto Error;
if (stringLength)
{
wchar_t* str = reinterpret_cast<wchar_t*>(alloca((stringLength+1)*2));
ASSERT(str != NULL);
if (str == NULL)
return E_POINTER;
sc = stream.ScRead(str, stringLength*2);
if(sc)
goto Error;
str[stringLength] = 0;
USES_CONVERSION;
m_strName = W2T (str);
}
break;
}
/*
* MMC 1.1 stream
*/
case Stream_V0110:
{
/*
* read the image index
*/
sc = stream.ScRead(&m_nImage, sizeof(m_nImage));
if(sc)
goto Error;
/*
* read the name (stream insertion operators will throw
* _com_error's, so we need an exception block here)
*/
try
{
IStream *pStream = stream.Get();
if(!pStream)
goto PointerError;
*pStream >> m_strName;
}
catch (_com_error& err)
{
hr = err.Error();
ASSERT (false && "Caught _com_error");
return (hr);
}
break;
}
default:
#ifdef DBG
TCHAR szTraceMsg[80];
StringCchPrintf (szTraceMsg, countof(szTraceMsg), _T("Unexpected stream version 0x08x\n"), nVersion);
TRACE (szTraceMsg);
ASSERT (FALSE);
#endif
return (E_FAIL);
break;
}
Cleanup:
return sc;
PointerError:
sc = E_POINTER;
Error:
TraceError(TEXT("CMTNode::Load"), sc);
goto Cleanup;
}
HRESULT CMTNode::Init(void)
{
DECLARE_SC(sc, TEXT("CMTNode::Init"));
if (m_bInit == TRUE)
return S_FALSE;
ASSERT(WasExpandedAtLeastOnce() == FALSE);
if (!m_pPrimaryComponentData)
return E_FAIL;
CMTSnapInNode* pMTSnapIn = GetStaticParent();
HMTNODE hMTNode = CMTNode::ToHandle(pMTSnapIn);
if (!m_pPrimaryComponentData->IsInitialized())
{
sc = m_pPrimaryComponentData->Init(hMTNode);
if(sc)
return sc.ToHr();
sc = pMTSnapIn->ScInitIComponentData(m_pPrimaryComponentData);
if (sc)
return sc.ToHr();
}
// Init the extensions
m_bInit = TRUE;
BOOL fProblem = FALSE;
// Get node's node-type
GUID guidNodeType;
sc = GetNodeType(&guidNodeType);
if (sc)
return sc.ToHr();
CExtensionsIterator it;
// TODO: try to use the easier form of it.ScInitialize()
sc = it.ScInitialize(m_pPrimaryComponentData->GetSnapIn(), guidNodeType, g_szNameSpace,
m_arrayDynExtCLSID.GetData(), m_arrayDynExtCLSID.GetSize());
if(sc)
return sc.ToHr();
else
{
CComponentData* pCCD = NULL;
for (; it.IsEnd() == FALSE; it.Advance())
{
pCCD = pMTSnapIn->GetComponentData(it.GetCLSID());
if (pCCD == NULL)
{
CSnapInPtr spSnapIn;
// If a dynamic extension, we have to get the snap-in ourselves
// otherwise the iterator has it
if (it.IsDynamic())
{
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
ASSERT(pCache != NULL);
SC sc = pCache->ScGetSnapIn(it.GetCLSID(), &spSnapIn);
ASSERT(!sc.IsError());
// On failure, continue with other extensions
if (sc)
continue;
}
else
{
spSnapIn = it.GetSnapIn();
}
ASSERT(spSnapIn != NULL);
pCCD = new CComponentData(spSnapIn);
pMTSnapIn->AddComponentDataToArray(pCCD);
}
ASSERT(pCCD != NULL);
if (pCCD != NULL && pCCD->IsInitialized() == FALSE)
{
sc = pCCD->Init(hMTNode);
if ( !sc.IsError() )
sc = pMTSnapIn->ScInitIComponentData(pCCD);
if ( sc )
{
sc.TraceAndClear();
fProblem = TRUE;
}
}
}
pMTSnapIn->CompressComponentDataArray();
}
if (fProblem == TRUE)
{
Dbg(DEB_TRACE, _T("Failed to load some extensions"));
}
return S_OK;
}
HRESULT CMTNode::Expand(void)
{
DECLARE_SC(sc, TEXT("CMTNode::Expand"));
CComponentData* pCCD = m_pPrimaryComponentData;
if (WasExpandedAtLeastOnce() == FALSE)
Init();
SetExpandedAtLeastOnce();
ASSERT(pCCD != NULL);
if (pCCD == NULL)
return E_FAIL;
// Get the data object for the cookie from the owner snap-in
IDataObjectPtr spDataObject;
HRESULT hr = pCCD->QueryDataObject(GetUserParam(), CCT_SCOPE, &spDataObject);
CHECK_HRESULT(hr);
if (FAILED(hr))
return hr;
// hr = pCCD->Notify (spDataObject, MMCN_EXPAND, TRUE,
// reinterpret_cast<LPARAM>(this));
hr = Expand (pCCD, spDataObject, TRUE);
CHECK_HRESULT(hr);
if (FAILED(hr))
return hr;
// Mark the folder for the master tree item as expanded
CMTSnapInNode* pSIMTNode = GetStaticParent();
//
// Deal with extension snap-ins
//
m_bExtensionsExpanded = TRUE;
// Get node's node-type
GUID guidNodeType;
hr = GetNodeType(&guidNodeType);
if (FAILED(hr))
return hr;
CExtensionsIterator it;
// TODO: try to use the easier form of it.ScInitialize()
sc = it.ScInitialize(GetPrimarySnapIn(), guidNodeType, g_szNameSpace,
m_arrayDynExtCLSID.GetData(), m_arrayDynExtCLSID.GetSize());
if (sc)
return S_FALSE; // The snapin is not loaded on the m/c.
if (it.IsEnd()) // No extensions.
return S_OK;
BOOL fProblem = FALSE;
for (; it.IsEnd() == FALSE; it.Advance())
{
CComponentData* pCCD = pSIMTNode->GetComponentData(it.GetCLSID());
if (pCCD == NULL)
continue;
// hr = pCCD->Notify (spDataObject, MMCN_EXPAND, TRUE,
// reinterpret_cast<LPARAM>(this));
hr = Expand (pCCD, spDataObject, TRUE);
CHECK_HRESULT(hr);
// continue even if an error occurs with extension snapins
if (FAILED(hr))
fProblem = TRUE;
}
return (fProblem == TRUE) ? S_FALSE : S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CMTNode::ScInsertChild
//
// Synopsis: Inserts a child node after the designated node.
//
// Arguments: pmtn: Non-Null pointer to the node to be inserted.
// pmtnInsertAfter: Pointer to the node to insert after.
// If NULL, pmtn is inserted as the first child.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTNode::ScInsertChild(CMTNode* pmtn, CMTNode* pmtnInsertAfter)
{
DECLARE_SC(sc, TEXT("CMTNode::ScInsertChild"));
sc = ScCheckPointers(pmtn);
if (sc)
return sc;
pmtn->AttachNext(NULL);
pmtn->AttachPrev(NULL);
if(pmtnInsertAfter)
{
if (pmtnInsertAfter->Parent() != this)
return (sc = E_INVALIDARG);
CMTNode* pmtnNext = pmtnInsertAfter->Next();
if(pmtnNext)
{
pmtnNext->AttachPrev(pmtn);
pmtn->AttachNext(pmtnNext);
}
else
{
if (LastChild() != pmtnInsertAfter)
return (sc = E_UNEXPECTED);
AttachLastChild(pmtn);
}
pmtnInsertAfter->AttachNext(pmtn);
pmtn->AttachPrev(pmtnInsertAfter);
}
else
{
CMTNode* pmtnNext = Child();
if(pmtnNext)
{
pmtnNext->AttachPrev(pmtn);
pmtn->AttachNext(pmtnNext);
}
else
{
AttachLastChild(pmtn);
}
AttachChild(pmtn);
}
pmtn->AttachParent(this);
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CMTNode::ScDeleteChild
//
// Synopsis: Deletes a child node.
//
// Arguments: pmtn: Non-Null pointer to the node to be deleted.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTNode::ScDeleteChild(CMTNode *pmtn)
{
DECLARE_SC(sc, TEXT("CMTNode::ScDeleteChild"));
sc = ScCheckPointers(pmtn);
if (sc)
return sc;
if (pmtn->Parent() != this)
return (sc = E_INVALIDARG);
CMTNode* pmtnNext = pmtn->Next();
CMTNode* pmtnPrev = pmtn->Prev();
if (pmtnPrev)
{
pmtnPrev->AttachNext(pmtnNext);
}
else
{
/* pmtn is the first child */
if(pmtn != Child())
return (sc = E_UNEXPECTED);
AttachChild(pmtnNext);
}
if(pmtnNext)
{
pmtnNext->AttachPrev(pmtnPrev);
}
else
{
/* pmtn is the last child */
AttachLastChild(pmtnPrev);
}
pmtn->AttachNext(NULL);
pmtn->AttachPrev(NULL);
pmtn->AttachParent(NULL);
pmtn->Release();
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CMTNode::ScDeleteTrailingChildren
//
// Synopsis: Deletes the designated child node and all subsequent ones.
//
// Arguments: pmtn: Non-Null pointer to the first node to be deleted.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CMTNode::ScDeleteTrailingChildren(CMTNode* pmtn)
{
DECLARE_SC(sc, TEXT("CMTNode::ScDeleteTrailingChildren"));
sc = ScCheckPointers(pmtn);
if (sc)
return sc;
if (pmtn->Parent() != this)
return (sc = E_INVALIDARG);
if (Child() == pmtn) /* First child */
AttachChild(NULL);
AttachLastChild(pmtn->Prev());
CMTNode* pmtnTmp = NULL;
while(pmtn)
{
pmtnTmp = pmtn;
pmtn = pmtnTmp->Next();
pmtnTmp->AttachNext(NULL);
pmtnTmp->AttachPrev(NULL);
pmtnTmp->AttachParent(NULL);
pmtnTmp->Release();
}
return sc;
}
CNode* CMTNode::GetNode(CViewData* pViewData, BOOL fRootNode)
{
CMTSnapInNode* pMTSnapInNode = GetStaticParent();
if (pMTSnapInNode == NULL)
return (NULL);
if (fRootNode)
{
/*
* create a static parent node for this non-static
* root node (it will be deleted in the CNode dtor)
*/
CNode* pNodeTemp = pMTSnapInNode->GetNode(pViewData, FALSE);
if (pNodeTemp == NULL)
return NULL;
}
CNode* pNode = new CNode(this, pViewData, fRootNode);
if (pNode != NULL)
{
CComponent* pCC = pMTSnapInNode->GetComponent(pViewData->GetViewID(),
GetPrimaryComponentID(), GetPrimarySnapIn());
if (pCC==NULL)
{
delete pNode;
return NULL;
}
else
pNode->SetPrimaryComponent(pCC);
}
return pNode;
}
HRESULT CMTNode::AddExtension(LPCLSID lpclsid)
{
DECLARE_SC(sc, TEXT("CMTNode::AddExtension"));
sc = ScCheckPointers(lpclsid);
if (sc)
return sc.ToHr();
CMTSnapInNode* pMTSnapIn = GetStaticParent();
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
sc = ScCheckPointers(pMTSnapIn, pCache, E_UNEXPECTED);
if (sc)
return sc.ToHr();
do // not a loop
{
// Get node's node-type
GUID guidNodeType;
sc = GetNodeType(&guidNodeType);
if (sc)
return sc.ToHr();
// Must be a namespace extension
if (!ExtendsNodeNameSpace(guidNodeType, lpclsid))
return (sc = E_INVALIDARG).ToHr();
// Check if extension is already enabled
CExtensionsIterator it;
// TODO: try to use the easier form of it.ScInitialize()
sc = it.ScInitialize(GetPrimarySnapIn(), guidNodeType, g_szNameSpace,
m_arrayDynExtCLSID.GetData(), m_arrayDynExtCLSID.GetSize());
for (; it.IsEnd() == FALSE; it.Advance())
{
if (IsEqualCLSID(*lpclsid, it.GetCLSID()))
return (sc = S_FALSE).ToHr();
}
// Add extension to dynamic list
m_arrayDynExtCLSID.Add(*lpclsid);
// No errors returned if node is not initialized in MMC1.2.
if (!m_bInit)
break;
HMTNODE hMTNode = CMTNode::ToHandle(pMTSnapIn);
CSnapInPtr spSI;
CComponentData* pCCD = pMTSnapIn->GetComponentData(*lpclsid);
if (pCCD == NULL)
{
sc = pCache->ScGetSnapIn(*lpclsid, &spSI);
if (sc)
return sc.ToHr();
pCCD = new CComponentData(spSI);
sc = ScCheckPointers(pCCD, E_OUTOFMEMORY);
if (sc)
return sc.ToHr();
pMTSnapIn->AddComponentDataToArray(pCCD);
}
sc = ScCheckPointers(pCCD, E_UNEXPECTED);
if (sc)
return sc.ToHr();
if (pCCD->IsInitialized() == FALSE)
{
sc = pCCD->Init(hMTNode);
if (sc)
{
// Init failed.
pMTSnapIn->CompressComponentDataArray();
return sc.ToHr();
}
else
{
// Above Init is successful.
sc = pMTSnapIn->ScInitIComponentData(pCCD);
sc.TraceAndClear(); // to maintain compatibility
}
}
// Create and initialize a CComponent for all initialized nodes
CNodeList& nodes = pMTSnapIn->GetNodeList();
POSITION pos = nodes.GetHeadPosition();
CNode* pNode = NULL;
while (pos)
{
pNode = nodes.GetNext(pos);
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
sc = ScCheckPointers(pSINode, E_UNEXPECTED);
if (sc)
{
sc.TraceAndClear();
continue;
}
// Create component if hasn't been done yet
CComponent* pCC = pSINode->GetComponent(pCCD->GetComponentID());
if (pCC == NULL)
{
// Create and initialize one
pCC = new CComponent(pCCD->GetSnapIn());
sc = ScCheckPointers(pCC, E_OUTOFMEMORY);
if (sc)
return sc.ToHr();
pCC->SetComponentID(pCCD->GetComponentID());
pSINode->AddComponentToArray(pCC);
sc = pCC->Init(pCCD->GetIComponentData(), hMTNode, CNode::ToHandle(pNode),
pCCD->GetComponentID(), pNode->GetViewID());
sc.Trace_(); // Just trace for MMC1.2 compatibility.
}
}
// if extensions are already expanded, expand the new one now
if (AreExtensionsExpanded())
{
// Get the data object for the cookie from the owner snap-in
IDataObjectPtr spDataObject;
sc = GetPrimaryComponentData()->QueryDataObject(GetUserParam(), CCT_SCOPE, &spDataObject);
if (sc)
return sc.ToHr();
// hr = pCCD->Notify (spDataObject, MMCN_EXPAND, TRUE,
// reinterpret_cast<LPARAM>(this));
sc = Expand (pCCD, spDataObject, TRUE);
if (sc)
sc.Trace_(); // Just trace for MMC1.2 compatibility.
}
}
while(0);
return sc.ToHr();
}
HRESULT CMTNode::IsExpandable()
{
DECLARE_SC(sc, TEXT("CMTNode::IsExpandable"));
// if already expanded, we know if there are children
if (WasExpandedAtLeastOnce())
return (Child() != NULL) ? S_OK : S_FALSE;
// Even if not expanded there might be static children
if (Child() != NULL)
return S_OK;
// if primary snap-in can add children, return TRUE
// Note: When primary declares no children, it is also declaring
// there will be no dynamic namespace extensions
if (!(m_usExpandFlags & FLAG_NO_CHILDREN_FROM_PRIMARY))
return S_OK;
// Check enabled static extensions if haven't already
if (!(m_usExpandFlags & FLAG_NAMESPACE_EXTNS_CHECKED))
{
m_usExpandFlags |= FLAG_NAMESPACE_EXTNS_CHECKED;
do
{
// Do quick check for no extensions first
if (GetPrimarySnapIn()->GetExtensionSnapIn() == NULL)
{
m_usExpandFlags |= FLAG_NO_NAMESPACE_EXTNS;
break;
}
// Use iterator to find statically enabled namespace extens
GUID guidNodeType;
HRESULT hr = GetNodeType(&guidNodeType);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
break;
CExtensionsIterator it;
// TODO: try to use the easier form of it.ScInitialize()
sc = it.ScInitialize(GetPrimarySnapIn(), guidNodeType, g_szNameSpace, NULL, 0);
// if no extensions found, set the flag
if (sc.IsError() || it.IsEnd())
m_usExpandFlags |= FLAG_NO_NAMESPACE_EXTNS;
}
while (FALSE);
}
// if no namespace extensions, there will be no children
if (m_usExpandFlags & FLAG_NO_NAMESPACE_EXTNS)
return S_FALSE;
return S_OK;
}
HRESULT CMTNode::Expand (
CComponentData* pComponentData,
IDataObject* pDataObject,
BOOL bExpanding)
{
HRESULT hr = E_FAIL;
bool fSendExpand = true;
if (CScopeTree::_IsSynchronousExpansionRequired())
{
MMC_EXPANDSYNC_STRUCT ess;
ess.bHandled = FALSE;
ess.bExpanding = bExpanding;
ess.hItem = reinterpret_cast<HSCOPEITEM>(this);
hr = pComponentData->Notify (pDataObject, MMCN_EXPANDSYNC, 0,
reinterpret_cast<LPARAM>(&ess));
fSendExpand = !ess.bHandled;
}
if (fSendExpand)
{
hr = pComponentData->Notify (pDataObject, MMCN_EXPAND, bExpanding,
reinterpret_cast<LPARAM>(this));
}
return (hr);
}
SC CMTNode::ScQueryDispatch(DATA_OBJECT_TYPES type,
PPDISPATCH ppScopeNodeObject)
{
DECLARE_SC(sc, _T("CMTNode::QueryDispatch"));
sc = ScCheckPointers(ppScopeNodeObject);
if (sc)
return sc;
*ppScopeNodeObject = NULL;
CMTSnapInNode* pMTSINode = GetStaticParent();
sc = ScCheckPointers(pMTSINode, E_UNEXPECTED);
if (sc)
return sc;
CComponentData* pCCD = pMTSINode->GetComponentData(GetPrimarySnapInCLSID());
sc = ScCheckPointers(pCCD, E_UNEXPECTED);
if (sc)
return sc;
sc = pCCD->ScQueryDispatch(GetUserParam(), type, ppScopeNodeObject);
return sc;
}
/*+-------------------------------------------------------------------------*
* CMTNode::SetDisplayName
*
*
*--------------------------------------------------------------------------*/
void CMTNode::SetDisplayName (LPCTSTR pszName)
{
// This function should never be called as it does nothing. Display names
DECLARE_SC(sc, TEXT("CMTNode::SetDisplayName"));
if (pszName != (LPCTSTR) MMC_TEXTCALLBACK)
{
sc = E_INVALIDARG;
TraceError(TEXT("The string should be MMC_TEXTCALLBACK"), sc);
sc.Clear();
}
}
/*+-------------------------------------------------------------------------*
*
* CMTNode::GetDisplayName
*
* PURPOSE: Returns the display name of the node.
*
* RETURNS:
* LPCTSTR
*
*+-------------------------------------------------------------------------*/
tstring
CMTNode::GetDisplayName()
{
CComponentData* pCCD = GetPrimaryComponentData();
if (pCCD)
{
SCOPEDATAITEM ScopeDataItem;
ZeroMemory(&ScopeDataItem, sizeof(ScopeDataItem));
ScopeDataItem.mask = SDI_STR;
ScopeDataItem.lParam = GetUserParam();
HRESULT hr = pCCD->GetDisplayInfo(&ScopeDataItem);
CHECK_HRESULT(hr);
/*
* if we succeeded, cache the name returned to us for
* persistence
*/
if (SUCCEEDED(hr))
{
USES_CONVERSION;
if (ScopeDataItem.displayname)
SetCachedDisplayName(OLE2T(ScopeDataItem.displayname));
else
SetCachedDisplayName(_T(""));
}
}
return GetCachedDisplayName();
}
/***************************************************************************\
*
* METHOD: CMTNode::ScGetPropertyFromINodeProperties
*
* PURPOSE: gets SnapIn property thru INodeProperties interface
*
* PARAMETERS:
* LPDATAOBJECT pDataObject [in] - data object
* BSTR bstrPropertyName [in] - property name
* PBSTR pbstrPropertyValue [out] - property value
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTNode::ScGetPropertyFromINodeProperties(LPDATAOBJECT pDataObject, BSTR bstrPropertyName, PBSTR pbstrPropertyValue)
{
DECLARE_SC(sc, TEXT("CMTNode::ScGetPropertyFromINodeProperties"));
SC sc_no_trace; // for 'valid' error - not to be traced
// parameter check
sc = ScCheckPointers(pDataObject, bstrPropertyName, pbstrPropertyValue);
if(sc)
return sc;
// get the CComponentData
CComponentData *pComponentData = GetPrimaryComponentData();
sc = ScCheckPointers(pComponentData, E_UNEXPECTED);
if(sc)
return sc;
// QI for INodeProperties from IComponentData
INodePropertiesPtr spNodeProperties = pComponentData->GetIComponentData();
// at this point we should have a valid interface if it is supported
sc_no_trace = ScCheckPointers(spNodeProperties, E_NOINTERFACE);
if(sc_no_trace)
return sc_no_trace;
// get the property
sc_no_trace = spNodeProperties->GetProperty(pDataObject, bstrPropertyName, pbstrPropertyValue);
return sc_no_trace;
}
//############################################################################
//############################################################################
//
// Implementation of class CComponentData
//
//############################################################################
//############################################################################
//____________________________________________________________________________
//
// Class: CComponentData Inlines
//____________________________________________________________________________
//
DEBUG_DECLARE_INSTANCE_COUNTER(CComponentData);
CComponentData::CComponentData(CSnapIn * pSnapIn)
: m_spSnapIn(pSnapIn), m_ComponentID(-1), m_bIComponentDataInitialized(false)
{
TRACE_CONSTRUCTOR(CComponentData);
DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentData);
ASSERT(m_spSnapIn != NULL);
}
CComponentData::~CComponentData()
{
TRACE_DESTRUCTOR(CComponentData);
DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentData);
if (m_spIComponentData != NULL)
m_spIComponentData->Destroy();
}
HRESULT CComponentData::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
{
ASSERT(m_spIComponentData != NULL);
if (m_spIComponentData == NULL)
return E_FAIL;
HRESULT hr = S_OK;
__try
{
hr = m_spIComponentData->Notify(lpDataObject, event, arg, param);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
hr = E_FAIL;
if (m_spSnapIn)
TraceSnapinException(m_spSnapIn->GetSnapInCLSID(), TEXT("IComponentData::Notify"), event);
}
return hr;
}
SC CComponentData::ScQueryDispatch(MMC_COOKIE cookie,
DATA_OBJECT_TYPES type,
PPDISPATCH ppScopeNodeObject)
{
DECLARE_SC(sc, _T("CComponentData::ScQueryDispatch"));
sc = ScCheckPointers(m_spIComponentData, E_UNEXPECTED);
if (sc)
return sc;
IComponentData2Ptr spCompData2 = m_spIComponentData;
sc = ScCheckPointers(spCompData2.GetInterfacePtr(), E_NOINTERFACE);
if (sc)
return sc;
ASSERT(type != CCT_RESULT); // Cant Ask Disp for resultpane objects.
sc = spCompData2->QueryDispatch(cookie, type, ppScopeNodeObject);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CreateSnapIn
*
* PURPOSE: Create a name space snapin (standalone or extension).
*
* PARAMETERS:
* clsid - class id of the snapin to be created.
* ppICD - IComponentData ptr of created snapin.
* fCreateDummyOnFailure - Create dummy snapin if Create snapin fails.
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT CreateSnapIn (const CLSID& clsid, IComponentData** ppICD,
bool fCreateDummyOnFailure /* =true */)
{
DECLARE_SC(sc, TEXT("CreateSnapIn"));
EDummyCreateReason eReason = eSnapCreateFailed;
IComponentDataPtr spICD;
sc = ScCheckPointers(ppICD);
if(sc)
return sc.ToHr();
// initialize the out parameter
*ppICD = NULL;
CPolicy policy;
sc = policy.ScInit();
if (sc)
{
eReason = eSnapPolicyFailed;
}
else if (policy.IsPermittedSnapIn(clsid))
{
/*
* Bug 258270: creating the snap-in might result in MSI running to
* install it. The MSI status window is modeless, but may spawn a
* modal dialog. If we don't manually disable MMC's main window,
* the user might start clicking around in the scope tree while that
* modal dialog is up, leading to reentrancy and all of the resulting
* calamity that one would expect.
*/
bool fReenableMMC = false;
CScopeTree* pScopeTree = CScopeTree::GetScopeTree();
HWND hwndMain = (pScopeTree) ? pScopeTree->GetMainWindow() : NULL;
if (IsWindow (hwndMain))
{
fReenableMMC = IsWindowEnabled (hwndMain);
if (fReenableMMC)
EnableWindow (hwndMain, false);
}
//create the snapin
sc = spICD.CreateInstance(clsid, NULL,MMC_CLSCTX_INPROC);
if(!sc.IsError() && (spICD==NULL))
sc = E_NOINTERFACE;
/*
* re-enable the main window if we disabled it
*/
if (fReenableMMC)
EnableWindow (hwndMain, true);
if (sc)
{
ReportSnapinInitFailure(clsid);
// Create a dummy snapin with snapin
// creation failed message.
eReason = eSnapCreateFailed;
}
else // creation succeeded. return
{
*ppICD = spICD.Detach();
return sc.ToHr();
}
}
else
{
// Display a message that policies does not
// allow this snapin to be created.
DisplayPolicyErrorMessage(clsid, FALSE);
// Create a dummy snapin with policy
// restriction message.
sc = E_FAIL;
eReason = eSnapPolicyFailed;
}
// If we've reached here, an error occurred
// create dummy snap-in that only displays error message
if (fCreateDummyOnFailure)
{
sc = ScCreateDummySnapin (&spICD, eReason, clsid);
if(sc)
return sc.ToHr();
sc = ScCheckPointers(spICD, E_UNEXPECTED);
if(sc)
return sc.ToHr();
*ppICD = spICD.Detach();
}
return sc.ToHr();
}
CExtSI* AddExtension(CSnapIn* pSnapIn, CLSID& rclsid, CSnapInsCache* pCache)
{
ASSERT(pSnapIn != NULL);
// See if extension is already present
CExtSI* pExt = pSnapIn->FindExtension(rclsid);
// if not, create one
if (pExt == NULL)
{
// Create cache entry for extension snapin
if (pCache == NULL)
pCache = theApp.GetSnapInsCache();
ASSERT(pCache != NULL);
CSnapInPtr spExtSnapIn;
SC sc = pCache->ScGetSnapIn(rclsid, &spExtSnapIn);
ASSERT(!sc.IsError() && spExtSnapIn != NULL);
// Attach extension to snap-in
if (!sc.IsError())
pExt = pSnapIn->AddExtension(spExtSnapIn);
}
else
{
// Clear deletion flag
pExt->MarkDeleted(FALSE);
}
return pExt;
}
HRESULT LoadRequiredExtensions (
CSnapIn* pSnapIn,
IComponentData* pICD,
CSnapInsCache* pCache /*=NULL*/)
{
SC sc;
ASSERT(pSnapIn != NULL);
// if already loaded, just return
if (pSnapIn->RequiredExtensionsLoaded())
goto Cleanup;
do
{
// Set extensions loaded, so we don't try again
pSnapIn->SetRequiredExtensionsLoaded();
// if snapin was enabling all extensions
// clear the flags before asking again
if (pSnapIn->DoesSnapInEnableAll())
{
pSnapIn->SetSnapInEnablesAll(FALSE);
pSnapIn->SetAllExtensionsEnabled(FALSE);
}
// Mark all required extensions for deletion
CExtSI* pExt = pSnapIn->GetExtensionSnapIn();
while (pExt != NULL)
{
if (pExt->IsRequired())
pExt->MarkDeleted(TRUE);
pExt = pExt->Next();
}
// Check for interface
IRequiredExtensionsPtr spReqExtn = pICD;
// if snap-in wants all extensions enabled
if (spReqExtn != NULL && spReqExtn->EnableAllExtensions() == S_OK)
{
// Set the "enable all" flags
pSnapIn->SetSnapInEnablesAll(TRUE);
pSnapIn->SetAllExtensionsEnabled(TRUE);
}
// if either user or snap-in wants all extensions
if (pSnapIn->AreAllExtensionsEnabled())
{
// Get list of all extensions
CExtensionsCache ExtCache;
sc = MMCGetExtensionsForSnapIn(pSnapIn->GetSnapInCLSID(), ExtCache);
if (sc)
goto Cleanup;
// Add each extension to snap-in's extension list
CExtensionsCacheIterator ExtIter(ExtCache);
for (; ExtIter.IsEnd() == FALSE; ExtIter.Advance())
{
// Only add extensions that can be statically enabled
if ((ExtIter.GetValue() & CExtSI::EXT_TYPE_STATIC) == 0)
continue;
GUID clsid = ExtIter.GetKey();
CExtSI* pExt = AddExtension(pSnapIn, clsid, pCache);
// Mark required if enabled by the snap-in
if (pExt != NULL && pSnapIn->DoesSnapInEnableAll())
pExt->SetRequired();
}
}
CPolicy policy;
sc = policy.ScInit();
if (sc)
goto Error;
// if snap-in supports the interface and didn't enable all
// ask for specific required extensions
// Note: this is done even if the user has enabled all because
// we need to know which ones the snap-in requires
if (spReqExtn != NULL && !pSnapIn->DoesSnapInEnableAll())
{
CLSID clsid;
sc = spReqExtn->GetFirstExtension(&clsid);
// Do while snap-in provides extension CLSIDs
while (HrFromSc(sc) == S_OK)
{
// See if the extension is restricted by policy.
// If so display a message.
if (! policy.IsPermittedSnapIn(clsid))
DisplayPolicyErrorMessage(clsid, TRUE);
// Add as required extension
CExtSI* pExt = AddExtension(pSnapIn, clsid, pCache);
if (pExt != NULL)
pExt->SetRequired();
sc = spReqExtn->GetNextExtension(&clsid);
}
}
// Delete extensions that are no longer required
// Note: Because required extensions are updated when snap-in is first loaded
// we don't have to worry about adding/deleting any nodes now.
pSnapIn->PurgeExtensions();
} while (FALSE);
Cleanup:
return HrFromSc(sc);
Error:
TraceError(TEXT("LoadRequiredExtensions"), sc);
goto Cleanup;
}
HRESULT CComponentData::Init(HMTNODE hMTNode)
{
ASSERT(hMTNode != 0);
if (IsInitialized() == TRUE)
return S_OK;
ASSERT(m_spSnapIn != NULL);
HRESULT hr = S_OK;
do
{
if (m_spIComponentData == NULL)
{
if (m_spSnapIn == NULL)
{
hr = E_POINTER;
break;
}
IUnknownPtr spUnknown;
hr = CreateSnapIn(m_spSnapIn->GetSnapInCLSID(), &m_spIComponentData);
ASSERT(SUCCEEDED(hr));
ASSERT(m_spIComponentData != NULL);
if (FAILED(hr))
break;
if(m_spIComponentData == NULL)
{
hr = E_FAIL;
break;
}
}
hr = m_spIFramePrivate.CreateInstance(CLSID_NodeInit,
#if _MSC_VER >= 1100
NULL,
#endif
MMC_CLSCTX_INPROC);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
Debug_SetNodeInitSnapinName(m_spSnapIn, m_spIFramePrivate.GetInterfacePtr());
// Init frame.
ASSERT(m_ComponentID != -1);
ASSERT(m_spIFramePrivate != NULL);
ASSERT(m_spSnapIn != NULL);
if ((m_spIFramePrivate == NULL) || (m_spSnapIn == NULL))
{
hr = E_UNEXPECTED;
CHECK_HRESULT(hr);
break;
}
m_spIFramePrivate->SetComponentID(m_ComponentID);
m_spIFramePrivate->CreateScopeImageList(m_spSnapIn->GetSnapInCLSID());
m_spIFramePrivate->SetNode(hMTNode, NULL);
// Load extensions requested by snap-in and proceed regardless of outcome
LoadRequiredExtensions(m_spSnapIn, m_spIComponentData);
hr = m_spIComponentData->Initialize(m_spIFramePrivate);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
} while (0);
if (FAILED(hr))
{
m_spIComponentData = NULL;
m_spIFramePrivate = NULL;
}
return hr;
}
//############################################################################
//############################################################################
//
// Implementation of class CMTSnapInNode
//
//############################################################################
//############################################################################
DEBUG_DECLARE_INSTANCE_COUNTER(CMTSnapInNode);
CMTSnapInNode::CMTSnapInNode(Properties* pProps)
: m_spProps (pProps),
m_fCallbackForDisplayName(false)
{
DEBUG_INCREMENT_INSTANCE_COUNTER(CMTSnapInNode);
// Open and Closed images
SetImage(eStockImage_Folder);
SetOpenImage(eStockImage_OpenFolder);
m_ePreloadState = ePreload_Unknown;
m_bHasBitmaps = FALSE;
m_resultImage = CMTNode::GetImage();
/*
* attach this node to it's properties collection
*/
if (m_spProps != NULL)
{
CSnapinProperties* pSIProps = CSnapinProperties::FromInterface (m_spProps);
if (pSIProps != NULL)
pSIProps->ScSetSnapInNode (this);
}
}
CMTSnapInNode::~CMTSnapInNode() throw()
{
DEBUG_DECREMENT_INSTANCE_COUNTER(CMTSnapInNode);
for (int i=0; i < m_ComponentDataArray.size(); i++)
delete m_ComponentDataArray[i];
// DON'T CHANGE THIS ORDER!!!!!
m_ComponentStorage.Clear();
/*
* detach this node from it's properties collection
*/
if (m_spProps != NULL)
{
CSnapinProperties* pSIProps = CSnapinProperties::FromInterface (m_spProps);
if (pSIProps != NULL)
pSIProps->ScSetSnapInNode (NULL);
}
/*
* clean up the image lists (they aren't self-cleaning!)
*/
m_imlSmall.Destroy();
m_imlLarge.Destroy();
}
HRESULT CMTSnapInNode::Init(void)
{
DECLARE_SC (sc, _T("CMTSnapInNode::Init"));
if (IsInitialized() == TRUE)
return S_FALSE;
HRESULT hr = CMTNode::Init();
if (FAILED(hr))
return hr;
/*
* initialize the snap-in with its properties interface
*/
sc = ScInitProperties ();
if (sc)
return (sc.ToHr());
if (IsPreloadRequired())
{
CComponentData* pCCD = GetPrimaryComponentData();
ASSERT(pCCD != NULL);
IDataObjectPtr spDataObject;
hr = pCCD->QueryDataObject(GetUserParam(), CCT_SCOPE, &spDataObject);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
HSCOPEITEM hsi = reinterpret_cast<HSCOPEITEM>(this);
pCCD->Notify(spDataObject, MMCN_PRELOAD, hsi, 0);
}
return S_OK;
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScInitProperties
*
* Initializes the snap-in with its properties interface, if it supports
* ISnapinProperties.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScInitProperties ()
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScInitProperties"));
/*
* get the snap-in's IComponentData
*/
CComponentData* pCCD = GetPrimaryComponentData();
if (pCCD == NULL)
return (sc = E_UNEXPECTED);
IComponentDataPtr spComponentData = pCCD->GetIComponentData();
if (spComponentData == NULL)
return (sc = E_UNEXPECTED);
/*
* If the snap-in supports ISnapinProperties, give it its Properties
* interface.
*/
ISnapinPropertiesPtr spISP = spComponentData;
if (spISP != NULL)
{
/*
* If we didn't persist properties for this snap-in we won't have
* a CSnapinProperties object yet; create one now.
*/
CSnapinProperties* pSIProps = NULL;
sc = ScCreateSnapinProperties (&pSIProps);
if (sc)
return (sc);
if (pSIProps == NULL)
return (sc = E_UNEXPECTED);
/*
* Initialize the snap-in with the initial properties.
*/
sc = pSIProps->ScInitialize (spISP, pSIProps, this);
if (sc)
return (sc);
}
return (sc);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScCreateSnapinProperties
*
* Creates the CSnapinProperties object for this node. It is safe to call
* this method multiple times; subsequent invocations will short out.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScCreateSnapinProperties (
CSnapinProperties** ppSIProps) /* O:pointer to the CSnapinProperties object (optional) */
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScCreateSnapinProperties"));
/*
* create a CSnapinProperties if we don't already have one
*/
if (m_spProps == NULL)
{
/*
* create the properties object
*/
CComObject<CSnapinProperties>* pSIProps;
sc = CComObject<CSnapinProperties>::CreateInstance (&pSIProps);
if (sc)
return (sc);
if (pSIProps == NULL)
return (sc = E_UNEXPECTED);
/*
* keep a reference to the object
*/
m_spProps = pSIProps;
}
/*
* return a pointer to the implementing object, if desired
*/
if (ppSIProps != NULL)
*ppSIProps = CSnapinProperties::FromInterface (m_spProps);
return (sc);
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::SetDisplayName
*
* PURPOSE: Sets the display name of the node.
*
* PARAMETERS:
* LPCTSTR pszName :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void
CMTSnapInNode::SetDisplayName(LPCTSTR pszName)
{
bool fDisplayCallback = (pszName == (LPCTSTR)MMC_TEXTCALLBACK);
/*
* if our callback setting has changed, we're dirty
*/
if (m_fCallbackForDisplayName != fDisplayCallback)
{
m_fCallbackForDisplayName = fDisplayCallback;
SetDirty();
}
/*
* if we're not now callback, cache the name (if we're callback,
* the name will be cached the next time GetDisplayName is called)
*/
if (!m_fCallbackForDisplayName)
SetCachedDisplayName(pszName);
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::GetDisplayName
*
* PURPOSE: Returns the display name of the node.
*
* RETURNS:
* LPCTSTR
*
*+-------------------------------------------------------------------------*/
tstring
CMTSnapInNode::GetDisplayName()
{
if (m_fCallbackForDisplayName)
return (CMTNode::GetDisplayName());
return GetCachedDisplayName();
}
HRESULT CMTSnapInNode::IsExpandable()
{
// if haven't intiailized the snap-in we have to assume that
// there could be children
if (!IsInitialized())
return S_OK;
return CMTNode::IsExpandable();
}
void CMTSnapInNode::CompressComponentDataArray()
{
int nSize = m_ComponentDataArray.size();
int nSkipped = 0;
for (int i=0; i<nSize; ++i)
{
ASSERT(m_ComponentDataArray[i] != NULL);
if (m_ComponentDataArray[i]->IsInitialized() == FALSE)
{
// if component failed to intialize, delete it
// and skip over it
delete m_ComponentDataArray[i];
++nSkipped;
}
else
{
// if components have been skiped, move the good component to the
// first vacant slot and adjust the component's ID
if (nSkipped)
{
m_ComponentDataArray[i-nSkipped] = m_ComponentDataArray[i];
m_ComponentDataArray[i-nSkipped]->ResetComponentID(i-nSkipped);
}
}
}
// reduce array size by number skipped
if (nSkipped)
m_ComponentDataArray.resize(nSize - nSkipped);
}
void CMTSnapInNode::AddNode(CNode * pNode)
{
#ifdef DBG
{
POSITION pos = m_NodeList.Find(pNode);
ASSERT(pos == NULL);
}
#endif
if (!FindNode(pNode->GetViewID()))
m_NodeList.AddHead(pNode);
}
void CMTSnapInNode::RemoveNode(CNode * pNode)
{
POSITION pos = m_NodeList.Find(pNode);
if (pos != NULL)
m_NodeList.RemoveAt(pos);
}
CSnapInNode* CMTSnapInNode::FindNode(int nViewID)
{
POSITION pos = m_NodeList.GetHeadPosition();
while (pos)
{
CSnapInNode* pSINode =
dynamic_cast<CSnapInNode*>(m_NodeList.GetNext(pos));
ASSERT(pSINode != NULL);
if (pSINode->GetViewID() == nViewID)
{
return pSINode;
}
}
return NULL;
}
UINT CMTSnapInNode::GetResultImage(CNode* pNode, IImageListPrivate* pResultImageList)
{
if (pResultImageList == NULL)
return GetImage();
if ((m_bHasBitmaps == FALSE) && (m_resultImage != MMC_IMAGECALLBACK))
return GetImage();
int ret = 0;
IFramePrivate* pFramePrivate = dynamic_cast<IFramePrivate*>(pResultImageList);
COMPONENTID id = 0;
pFramePrivate->GetComponentID (&id);
COMPONENTID tempID = (COMPONENTID)-GetID(); // use Ravi's negative of ID scheme
pFramePrivate->SetComponentID (tempID);
if (m_bHasBitmaps)
{
const int nResultImageIndex = 0;
/*
* if we haven't added this node's images to the result image list,
* add it now
*/
if (FAILED (pResultImageList->MapRsltImage (tempID, nResultImageIndex, &ret)))
{
/*
* Extract icons from the imagelist dynamically for device independence.
* (There ought to be a way to copy images from one imagelist to
* another, but there's not. ImageList_Copy looks like it should
* work, but it only supports copying images within the same image
* list.)
*/
HRESULT hr;
CSmartIcon icon;
/*
* Set our icon from the small imagelist. ImageListSetIcon
* will also set the large icon by stretching the small, but
* we'll fix that below.
*/
icon.Attach (m_imlSmall.GetIcon (0));
hr = pResultImageList->ImageListSetIcon (
reinterpret_cast<PLONG_PTR>((HICON)icon),
nResultImageIndex);
if (hr == S_OK)
{
/*
* Replace the large icon that ImageListSetIcon generated
* by stretching the small icon above, with the large icon
* that was created with the correct dimensions.
*/
icon.Attach (m_imlLarge.GetIcon (0));
hr = pResultImageList->ImageListSetIcon (
reinterpret_cast<PLONG_PTR>((HICON)icon),
ILSI_LARGE_ICON (nResultImageIndex));
}
if (hr == S_OK)
pResultImageList->MapRsltImage (tempID, nResultImageIndex, &ret);
}
}
else if (m_resultImage == MMC_IMAGECALLBACK)
{
// ask snapin
// first call IComponent::Notify w/ MMCN_ADD_IMAGES;
CComponent* pComponent = pNode->GetPrimaryComponent ();
if (pComponent) {
IDataObjectPtr spDataObject;
HRESULT hr = pComponent->QueryDataObject (GetUserParam(), CCT_RESULT, &spDataObject);
if (spDataObject) {
hr = pComponent->Notify (spDataObject, MMCN_ADD_IMAGES,
(LPARAM)pResultImageList, (LPARAM)this);
if (hr == S_OK) {
RESULTDATAITEM rdi;
ZeroMemory (&rdi, sizeof(rdi));
rdi.mask = SDI_IMAGE;
rdi.lParam = GetUserParam();
rdi.nImage = 0;
hr = pComponent->GetDisplayInfo (&rdi);
// map user's number to our number
pResultImageList->MapRsltImage (tempID, rdi.nImage, &ret);
}
}
}
}
pFramePrivate->SetComponentID (id); // change back
return (UINT)ret;
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScHandleCustomImages
*
* Retrieves images from a snap-in's About object and delegates to the
* overload of this function to assemble the images into their appropriate
* internal state.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScHandleCustomImages (const CLSID& clsidSnapin)
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScHandleCustomImages"));
m_bHasBitmaps = false;
/*
* open the SnapIns key
*/
MMC_ATL::CRegKey keySnapins;
sc.FromWin32 (keySnapins.Open (HKEY_LOCAL_MACHINE, SNAPINS_KEY, KEY_READ));
if (sc)
return (sc);
OLECHAR szSnapinCLSID[40];
if (StringFromGUID2 (clsidSnapin, szSnapinCLSID, countof(szSnapinCLSID)) == 0)
return (sc = E_UNEXPECTED);
/*
* open the key for the requested snap-in
*/
USES_CONVERSION;
MMC_ATL::CRegKey keySnapin;
sc.FromWin32 (keySnapin.Open (keySnapins, OLE2T(szSnapinCLSID), KEY_READ));
if (sc)
return (sc);
// from snapin clsid, get "about" clsid, if any.
TCHAR szAboutCLSID[40] = {0};
DWORD dwCnt = sizeof(szAboutCLSID);
sc.FromWin32 (keySnapin.QueryValue (szAboutCLSID, _T("About"), &dwCnt));
if (sc)
return (sc);
if (szAboutCLSID[0] == 0)
return (sc = E_FAIL);
// create an instance of the About object
ISnapinAboutPtr spISA;
sc = spISA.CreateInstance (T2OLE (szAboutCLSID), NULL, MMC_CLSCTX_INPROC);
if (sc)
return (sc);
sc = ScCheckPointers (spISA, E_UNEXPECTED);
if (sc)
return (sc);
// get the images
// Documentation explicitly states these images are NOT owned by
// MMC, despite the are out parameters. So we cannot release them,
// even though most snapins will leak them anyway.
// see bugs #139613 & #140637
HBITMAP hbmpSmallImage = NULL;
HBITMAP hbmpSmallImageOpen = NULL;
HBITMAP hbmpLargeImage = NULL;
COLORREF crMask;
sc = spISA->GetStaticFolderImage (&hbmpSmallImage,
&hbmpSmallImageOpen,
&hbmpLargeImage,
&crMask);
if (sc)
return (sc);
/*
* if the snap-in didn't give us a complete set of bitmaps,
* use default images but don't fail
*/
if (hbmpSmallImage == NULL || hbmpSmallImageOpen == NULL || hbmpLargeImage == NULL)
return (sc);
sc = ScHandleCustomImages (hbmpSmallImage, hbmpSmallImageOpen, hbmpLargeImage, crMask);
if (sc)
return (sc);
return (sc);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScHandleCustomImages
*
* Takes custom images for this snap-in and adds them to an imagelist for
* device-independence.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScHandleCustomImages (
HBITMAP hbmSmall, // I:small image
HBITMAP hbmSmallOpen, // I:small open image
HBITMAP hbmLarge, // I:large image
COLORREF crMask) // I:mask color, common between all bitmaps
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScHandleCustomImages"));
/*
* validate input
*/
sc = ScCheckPointers (hbmSmall, hbmSmallOpen, hbmLarge);
if (sc)
return (sc);
/*
* we need to make copies of the input bitmaps because the calls to
* ImageList_AddMasked (below) messes up the background color
*/
WTL::CBitmap bmpSmallCopy = CopyBitmap (hbmSmall);
if (bmpSmallCopy.IsNull())
return (sc.FromLastError());
WTL::CBitmap bmpSmallOpenCopy = CopyBitmap (hbmSmallOpen);
if (bmpSmallOpenCopy.IsNull())
return (sc.FromLastError());
WTL::CBitmap bmpLargeCopy = CopyBitmap (hbmLarge);
if (bmpLargeCopy.IsNull())
return (sc.FromLastError());
/*
* preserve the images in imagelists for device independence
*/
ASSERT (m_imlSmall.IsNull());
if (!m_imlSmall.Create (16, 16, ILC_COLOR8 | ILC_MASK, 2, 1) ||
(m_imlSmall.Add (bmpSmallCopy, crMask) == -1) ||
(m_imlSmall.Add (bmpSmallOpenCopy, crMask) == -1))
{
return (sc.FromLastError());
}
ASSERT (m_imlLarge.IsNull());
if (!m_imlLarge.Create (32, 32, ILC_COLOR8 | ILC_MASK, 1, 1) ||
(m_imlLarge.Add (bmpLargeCopy, crMask) == -1))
{
return (sc.FromLastError());
}
m_bHasBitmaps = TRUE;
sc = ScAddImagesToImageList ();
if (sc)
return (sc);
return (sc);
}
void CMTSnapInNode::SetPrimarySnapIn(CSnapIn * pSI)
{
DECLARE_SC (sc, _T("CMTSnapInNode::SetPrimarySnapIn"));
ASSERT(m_ComponentDataArray.size() == 0);
CComponentData* pCCD = new CComponentData(pSI);
int nID = AddComponentDataToArray(pCCD);
ASSERT(nID == 0);
SetPrimaryComponentData(pCCD);
if (m_bHasBitmaps == FALSE) {
sc = ScHandleCustomImages (pSI->GetSnapInCLSID());
if (sc)
sc.TraceAndClear();
if (m_bHasBitmaps)
SetDirty();
}
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScInitIComponent
*
* PURPOSE: Either loads component (if has a stream/storage)
* or initializes with a fresh stream/storage
*
* PARAMETERS:
* CComponent* pCComponent [in] component to initialize
* int viewID [in] view id of the component
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScInitIComponent(CComponent* pCComponent, int viewID)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScInitIComponent"));
// parameter chack
sc = ScCheckPointers( pCComponent );
if (sc)
return sc;
IComponent* pComponent = pCComponent->GetIComponent();
sc = ScCheckPointers( pComponent, E_UNEXPECTED );
if (sc)
return sc;
CLSID clsid = pCComponent->GetCLSID();
// initialize the snapin object
sc = ScInitComponentOrComponentData(pComponent, &m_ComponentPersistor, viewID, clsid );
if (sc)
return sc;
pCComponent->SetIComponentInitialized();
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScInitIComponentData
*
* PURPOSE: Either loads component data (if has a stream/storage)
* or initializes with a fresh stream/storage
*
* PARAMETERS:
* CComponentData* pCComponentData
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScInitIComponentData(CComponentData* pCComponentData)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScInitIComponentData"));
// parameter check
sc = ScCheckPointers( pCComponentData );
if (sc)
return sc;
// Get the IComponentData to later obtain IPersist* from
IComponentData* const pIComponentData = pCComponentData->GetIComponentData();
sc = ScCheckPointers( pIComponentData, E_UNEXPECTED );
if (sc)
return sc;
const CLSID& clsid = pCComponentData->GetCLSID();
// initialize the snapin object
sc = ScInitComponentOrComponentData(pIComponentData, &m_CDPersistor, CDPersistor::VIEW_ID_DOCUMENT, clsid );
if (sc)
return sc;
pCComponentData->SetIComponentDataInitialized();
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScInitComponentOrComponentData
*
* PURPOSE: Either loads snapin object (component or component data)
* or initializes with a fresh stream/storage
*
* PARAMETERS:
* IUnknown *pSnapin [in] - snapin to initialize
* CMTSnapinNodeStreamsAndStorages *pStreamsAndStorages
* [in] - collection of streams/storages
* int idView [in] - view id of component
* const CLSID& clsid [in] class is of the snapin
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScInitComponentOrComponentData(IUnknown *pSnapin, CMTSnapinNodeStreamsAndStorages *pStreamsAndStorages, int idView, const CLSID& clsid )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScInitComponentOrComponentData"));
// parameter check
sc = ScCheckPointers( pSnapin, pStreamsAndStorages );
if (sc)
return sc;
IPersistStreamPtr spIPersistStream;
IPersistStreamInitPtr spIPersistStreamInit;
IPersistStoragePtr spIPersistStorage;
// determine the interface supported and load/init
if ( (spIPersistStream = pSnapin) != NULL) // QI first for an IPersistStream
{
if ( pStreamsAndStorages->HasStream( idView, clsid ) )
{
// load
IStreamPtr spStream;
sc = pStreamsAndStorages->ScGetIStream( idView, clsid, &spStream);
if (sc)
return sc;
sc = spIPersistStream->Load( spStream );
if(sc)
return sc;
}
// for this interface there in no initialization if we have nothing to load from
}
else if ( (spIPersistStreamInit = pSnapin) != NULL) // QI for an IPersistStreamInit
{
if ( pStreamsAndStorages->HasStream( idView, clsid ) )
{
// load
IStreamPtr spStream;
sc = pStreamsAndStorages->ScGetIStream( idView, clsid, &spStream);
if (sc)
return sc;
sc = spIPersistStreamInit->Load( spStream );
if(sc)
return sc;
}
else
{
// init new
sc = spIPersistStreamInit->InitNew();
if (sc)
return sc;
}
}
else if ( (spIPersistStorage = pSnapin) != NULL) // QI for an IPersistStorage
{
bool bHasStorage = pStreamsAndStorages->HasStorage( idView, clsid );
IStoragePtr spStorage;
sc = pStreamsAndStorages->ScGetIStorage( idView, clsid, &spStorage);
if (sc)
return sc;
if ( bHasStorage )
{
sc = spIPersistStorage->Load( spStorage );
if (sc)
return sc;
}
else
{
sc = spIPersistStorage->InitNew( spStorage );
if (sc)
return sc;
}
}
return sc;
}
/**************************************************************************
// CMTSnapinNode::CloseView
//
// This method does any clean-up that is required before deleting
// a view. For now all we do is close any OCXs assocoiated with the view.
// This is done so the OCX can close before the view is hidden.
***************************************************************************/
HRESULT CMTSnapInNode::CloseView(int idView)
{
// Locate associated node in specified view
CNodeList& nodes = GetNodeList();
ASSERT(&nodes != NULL);
if (&nodes == NULL)
return E_FAIL;
POSITION pos = nodes.GetHeadPosition();
while (pos)
{
CNode* pNode = nodes.GetNext(pos);
ASSERT(pNode != NULL);
if (pNode == NULL)
continue;
// if match found, tell node to close its controls
if (pNode->GetViewID() == idView)
{
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
ASSERT(pSINode != NULL);
pSINode->CloseControls();
break;
}
}
HRESULT hr = CMTNode::CloseView(idView);
ASSERT(hr == S_OK);
return hr == S_OK ? S_OK : E_FAIL;
}
HRESULT CMTSnapInNode::DeleteView(int idView)
{
HRESULT hr;
m_ComponentPersistor.RemoveView(idView);
hr = CMTNode::DeleteView(idView);
ASSERT(hr == S_OK);
return hr == S_OK ? S_OK : E_FAIL;
}
SC CMTSnapInNode::ScLoad()
{
SC sc;
CStream stream;
CLSID clsid;
sc = CMTNode::ScLoad();
if(sc)
goto Error;
stream.Attach(GetTreeStream());
sc = stream.ScRead(&clsid, sizeof(clsid));
if(sc)
goto Error;
// read bitmaps, if any
// we are ignoring error here, because we had gaps in the save code
// in the past and now we have console files to deal with
// see bug 96402 "Private: AV in FrontPage Server Extensions & HP ManageX"
ASSERT (sizeof(m_bHasBitmaps) == sizeof(BOOL));
sc = stream.ScRead(&m_bHasBitmaps, sizeof(BOOL), true /*bIgnoreErrors*/);
if(sc)
goto Error;
if (m_bHasBitmaps == TRUE)
{
WTL::CBitmap bmpSmall;
sc = ScLoadBitmap (stream, &bmpSmall.m_hBitmap);
if(sc)
goto Error;
WTL::CBitmap bmpSmallOpen;
sc = ScLoadBitmap (stream, &bmpSmallOpen.m_hBitmap);
if(sc)
goto Error;
WTL::CBitmap bmpLarge;
sc = ScLoadBitmap (stream, &bmpLarge.m_hBitmap);
if(sc)
goto Error;
COLORREF crMask;
sc = stream.ScRead(&crMask, sizeof(COLORREF));
if(sc)
goto Error;
sc = ScHandleCustomImages (bmpSmall, bmpSmallOpen, bmpLarge, crMask);
if (sc)
goto Error;
}
{
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
ASSERT(pCache != NULL);
if (pCache == NULL)
return E_FAIL;
CSnapInPtr spSI;
sc = pCache->ScGetSnapIn(clsid, &spSI);
if (sc)
goto Error;
sc = ScCheckPointers(spSI, E_UNEXPECTED);
if (sc)
goto Error;
SetPrimarySnapIn(spSI);
pCache->SetDirty(FALSE);
}
// see if we have to do the preload thing
{
BOOL bPreload = FALSE;
sc = stream.ScRead(&bPreload, sizeof(BOOL), true /*bIgnoreErrors*/); // the preload bit is optional, do no error out.
if(sc)
goto Error;
SetPreloadRequired (bPreload);
}
// read all the streams and storages for this node
sc = ScReadStreamsAndStoragesFromConsole();
if(sc)
goto Error;
Cleanup:
return sc == S_OK ? S_OK : E_FAIL;
Error:
TraceError(TEXT("CMTSnapInNode::Load"), sc);
goto Cleanup;
}
HRESULT CMTSnapInNode::IsDirty()
{
DECLARE_SC (sc, _T("CMTSnapInNode::IsDirty"));
HRESULT hr = CMTNode::IsDirty();
ASSERT(SUCCEEDED(hr));
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return hr;
}
hr = AreIComponentDatasDirty();
ASSERT(hr == S_OK || hr == S_FALSE);
if (hr == S_OK)
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return S_OK;
}
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return E_FAIL;
}
hr = AreIComponentsDirty();
ASSERT(hr == S_OK || hr == S_FALSE);
if (hr == S_OK)
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return S_OK;
}
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return E_FAIL;
}
/*
* See if "preload" bit changed. If an error occurred while querying
* the snap-in, we'll assume that the preload bit hasn't changed.
*/
PreloadState ePreloadState = m_ePreloadState;
SC scNoTrace = ScQueryPreloadRequired (ePreloadState);
if (scNoTrace.IsError() || (ePreloadState == m_ePreloadState))
{
TraceDirtyFlag(TEXT("CMTSnapinNode"), false);
return S_FALSE;
}
TraceDirtyFlag(TEXT("CMTSnapinNode"), true);
return S_OK;
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::AreIComponentDatasDirty
*
* Returns S_OK if any of the IComponentDatas attached to this snap-in node
* (i.e. those of this snap-in and its extensions) is dirty, S_FALSE otherwise.
*--------------------------------------------------------------------------*/
HRESULT CMTSnapInNode::AreIComponentDatasDirty()
{
CComponentData* const pCCD = GetPrimaryComponentData();
#if 1
/*
* we used to check the primary component data explicitly, but that
* (if it exists) is always the first element in the IComponentData
* array. The loop below will handle it in a more generic manner.
*/
ASSERT ((pCCD == NULL) || (pCCD == m_ComponentDataArray[0]));
#else
IComponentData* const pICCD = pCCD != NULL ?
pCCD->GetIComponentData() : NULL;
if ((pICCD != NULL) && (IsIUnknownDirty (pICCD) == S_OK))
return (S_OK);
#endif
/*
* check all of the IComponentDatas attached to this snap-in node
* to see if any one is dirty
*/
UINT cComponentDatas = m_ComponentDataArray.size();
for (UINT i = 0; i < cComponentDatas; i++)
{
IComponentData* pICCD = (m_ComponentDataArray[i] != NULL)
? m_ComponentDataArray[i]->GetIComponentData()
: NULL;
if ((pICCD != NULL) && (IsIUnknownDirty (pICCD) == S_OK))
return (S_OK);
}
return (S_FALSE);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::AreIComponentsDirty
*
* Returns S_OK if any of the IComponents attached to this snap-in node
* (in any view) is dirty, S_FALSE otherwise.
*--------------------------------------------------------------------------*/
HRESULT CMTSnapInNode::AreIComponentsDirty()
{
CNodeList& nodes = GetNodeList();
ASSERT(&nodes != NULL);
if (&nodes == NULL)
return E_FAIL;
POSITION pos = nodes.GetHeadPosition();
while (pos)
{
CNode* pNode = nodes.GetNext(pos);
ASSERT(pNode != NULL);
if (pNode == NULL)
return E_FAIL;
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
ASSERT(pSINode != NULL);
if (pSINode == NULL)
return E_FAIL;
const CComponentArray& components = pSINode->GetComponentArray();
const int end = components.size();
for (int i = 0; i < end; i++)
{
CComponent* pCC = components[i];
if ((NULL == pCC) || (pCC->IsInitialized() == FALSE) )
continue;
IComponent* pComponent = pCC->GetIComponent();
if (NULL == pComponent)
continue;
HRESULT hr = IsIUnknownDirty(pComponent);
ASSERT(hr == S_OK || hr == S_FALSE);
if (hr == S_OK)
return S_OK;
if (hr != S_FALSE)
return E_FAIL;
}
}
return S_FALSE;
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::IsIUnknownDirty
*
* Checks an IUnknown* for any of the three persistence interfaces
* (IPersistStream, IPersistStreamInit, and IPersistStorage, in that order)
* and if any of them is supported, returns the result of that interface's
* IsDirty method.
*--------------------------------------------------------------------------*/
HRESULT CMTSnapInNode::IsIUnknownDirty(IUnknown* pUnk)
{
ASSERT(pUnk != NULL);
if (pUnk == NULL)
return E_POINTER;
// 1. Check for IPersistStream
IPersistStreamPtr spIPS = pUnk;
if (spIPS != NULL)
return spIPS->IsDirty();
// 2. Check for IPersistStreamInit
IPersistStreamInitPtr spIPSI = pUnk;
if (spIPSI != NULL)
return spIPSI->IsDirty();
// 3. Check for IPersistStorage
IPersistStoragePtr spIPStg = pUnk;
if (spIPStg != NULL)
return spIPStg->IsDirty();
return S_FALSE;
}
// local functions
inline long LongScanBytes (long bits)
{
bits += 31;
bits /= 8;
bits &= ~3;
return bits;
}
SC ScLoadBitmap (CStream &stream, HBITMAP* pBitmap)
{
DECLARE_SC(sc, TEXT("ScLoadBitmap"));
// parameter check
sc = ScCheckPointers(pBitmap);
if (sc)
return sc;
/*
* The bitmap we're going to CreateDIBitmap into should be empty.
* If it's not, it may indicate a bitmap leak. If you've investigated
* an instance where this assert fails and determined that *pBitmap
* isn't being leaked (be very sure!), set *pBitmap to NULL before
* calling ScLoadBitmap. DO NOT remove this assert because you
* think it's hyperactive.
*/
ASSERT (*pBitmap == NULL);
// initialization
*pBitmap = NULL;
DWORD dwSize;
sc = stream.ScRead(&dwSize, sizeof(DWORD));
if(sc)
return sc;
CAutoArrayPtr<BYTE> spDib(new BYTE[dwSize]);
sc = ScCheckPointers(spDib, E_OUTOFMEMORY);
if (sc)
return sc;
// have a typed pointer for member access
typedef const BITMAPINFOHEADER * const LPCBITMAPINFOHEADER;
LPCBITMAPINFOHEADER pDib = reinterpret_cast<LPCBITMAPINFOHEADER>(&spDib[0]);
sc = stream.ScRead(spDib, dwSize);
if(sc)
return sc;
BYTE * bits = (BYTE*) (pDib+1);
int depth = pDib->biBitCount*pDib->biPlanes;
if (depth <= 8)
bits += (1<<depth)*sizeof(RGBQUAD);
// get a screen dc
WTL::CClientDC dc(NULL);
if (dc == NULL)
return sc.FromLastError(), sc;
HBITMAP hbitmap = CreateDIBitmap (dc, pDib, CBM_INIT, bits, (BITMAPINFO*)pDib, DIB_RGB_COLORS);
if (hbitmap == NULL)
return sc.FromLastError(), sc;
// return the bitmap
*pBitmap = hbitmap;
return sc;
}
/*+-------------------------------------------------------------------------*
*
* PersistBitmap
*
* PURPOSE: Saves Bitmap to / loads from XML doc.
*
* PARAMETERS:
* CPersistor &persistor :
* LPCTSTR name : name attribute of instance in XML
* HBITMAP hBitmap :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void PersistBitmap(CPersistor &persistor, LPCTSTR name, HBITMAP& hBitmap)
{
DECLARE_SC(sc, TEXT("PersistBitmap"));
// combined from ScSaveBitmap & ScLoadBitmap
// get a screen dc
WTL::CClientDC dc(NULL);
if (dc == NULL)
sc.FromLastError(), sc.Throw();
CXMLAutoBinary binBlock;
if (persistor.IsStoring())
{
// check pointers
sc = ScCheckPointers(hBitmap);
if (sc)
sc.Throw();
// create memory dc
WTL::CDC memdc;
memdc.CreateCompatibleDC(dc);
if (memdc == NULL)
sc.FromLastError(), sc.Throw();
// get bitmap info
BITMAP bm;
if (0 == GetObject (hBitmap, sizeof(BITMAP), (LPSTR)&bm))
sc.FromLastError(), sc.Throw();
// TODO: lousy palette stuff
int depth;
switch(bm.bmPlanes*bm.bmBitsPixel)
{
case 1:
depth = 1;
break;
case 2:
case 3:
case 4:
depth = 4;
break;
case 5:
case 6:
case 7:
case 8:
depth = 8;
break;
default:
depth = 24;
break;
}
DWORD dwSize = sizeof(BITMAPINFOHEADER) + bm.bmHeight*LongScanBytes(depth*bm.bmWidth);
DWORD colors = 0;
if(depth <= 8)
{
colors = 1<<depth;
dwSize += colors*sizeof(RGBQUAD);
}
sc = binBlock.ScAlloc(dwSize);
if (sc)
sc.Throw();
CXMLBinaryLock sLock(binBlock); // will unlock in destructor
BITMAPINFOHEADER* dib = NULL;
sc = sLock.ScLock(&dib);
if (sc)
sc.Throw();
sc = ScCheckPointers(dib, E_UNEXPECTED);
if (sc)
sc.Throw();
BYTE * bits = colors*sizeof(RGBQUAD) + (BYTE *)&dib[1];
dib->biSize = sizeof(BITMAPINFOHEADER);
dib->biWidth = bm.bmWidth;
dib->biHeight = bm.bmHeight;
dib->biPlanes = 1;
dib->biBitCount = (WORD)depth;
dib->biCompression = 0;
dib->biSizeImage = dwSize; // includes palette and bih ??
dib->biXPelsPerMeter = 0;
dib->biYPelsPerMeter = 0;
dib->biClrUsed = colors;
dib->biClrImportant = colors;
HBITMAP hold = memdc.SelectBitmap (hBitmap);
if (hold == NULL)
sc.FromLastError(), sc.Throw();
int lines = GetDIBits (memdc, hBitmap, 0, bm.bmHeight, (LPVOID)bits, (BITMAPINFO*)dib, DIB_RGB_COLORS);
// see if we were successful
if (!lines)
sc.FromLastError();
else if(lines != bm.bmHeight)
sc = E_UNEXPECTED; // should not happen
// clean up gdi resources.
memdc.SelectBitmap(hold);
if(sc)
sc.Throw();
}
persistor.Persist(binBlock, name);
if (persistor.IsLoading())
{
/*
* The bitmap we're going to CreateDIBitmap into should be empty.
* If it's not, it may indicate a bitmap leak. If you've investigated
* an instance where this assert fails and determined that hBitmap
* isn't being leaked (be very sure!), set hBitmap to NULL before
* calling PersistBitmap. DO NOT remove this assert because you
* think it's hyperactive.
*/
ASSERT (hBitmap == NULL);
hBitmap = NULL;
CXMLBinaryLock sLock(binBlock); // will unlock in destructor
BITMAPINFOHEADER* dib = NULL;
sc = sLock.ScLock(&dib);
if (sc)
sc.Throw();
sc = ScCheckPointers(dib, E_UNEXPECTED);
if (sc)
sc.Throw();
BYTE * bits = (BYTE *)&dib[1];
int depth = dib->biBitCount*dib->biPlanes;
if (depth <= 8)
bits += (1<<depth)*sizeof(RGBQUAD);
HBITMAP hbitmap = CreateDIBitmap (dc,
dib, CBM_INIT,
bits,
(BITMAPINFO*)dib,
DIB_RGB_COLORS);
if (hbitmap == NULL)
sc.FromLastError(), sc.Throw();
hBitmap = hbitmap;
}
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::Persist
*
* PURPOSE: Persist snapin node
*
* PARAMETERS:
* CPersistor &persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CMTSnapInNode::Persist(CPersistor& persistor)
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::Persist"));
// save the base class.
CMTNode::Persist(persistor);
CLSID clsid;
ZeroMemory(&clsid,sizeof(clsid));
if (persistor.IsLoading())
{
// check if bitmaps are here
m_bHasBitmaps = persistor.HasElement(XML_TAG_NODE_BITMAPS, NULL);
/*
* load persisted properties, if present
*/
if (persistor.HasElement (CSnapinProperties::_GetXMLType(), NULL))
{
/*
* create a properties object, since we don't have one yet
*/
ASSERT (m_spProps == NULL);
CSnapinProperties* pSIProps = NULL;
sc = ScCreateSnapinProperties (&pSIProps);
if (sc)
sc.Throw();
if (pSIProps == NULL)
(sc = E_UNEXPECTED).Throw();
/*
* load the properties
*/
persistor.Persist (*pSIProps);
}
}
else
{
clsid = GetPrimarySnapInCLSID();
/*
* persist properties, if present
*/
if (m_spProps != NULL)
{
CSnapinProperties* pSIProps = CSnapinProperties::FromInterface(m_spProps);
if (pSIProps != NULL)
persistor.Persist (*pSIProps);
}
}
persistor.PersistAttribute(XML_ATTR_MT_NODE_SNAPIN_CLSID, clsid);
if (m_bHasBitmaps)
{
CPersistor persistorBitmaps(persistor, XML_TAG_NODE_BITMAPS);
/*
* Early versions of XML persistence saved device-dependent
* bitmaps. If there's a BinaryData element named "SmallOpen",
* this is a console saved by early XML persistence -- read it
* in a special manner.
*/
if (persistor.IsLoading() &&
persistorBitmaps.HasElement (XML_TAG_VALUE_BIN_DATA,
XML_NAME_NODE_BITMAP_SMALL_OPEN))
{
WTL::CBitmap bmpSmall, bmpSmallOpen, bmpLarge;
std::wstring strMask;
PersistBitmap(persistorBitmaps, XML_NAME_NODE_BITMAP_SMALL, bmpSmall.m_hBitmap);
PersistBitmap(persistorBitmaps, XML_NAME_NODE_BITMAP_SMALL_OPEN, bmpSmallOpen.m_hBitmap);
PersistBitmap(persistorBitmaps, XML_NAME_NODE_BITMAP_LARGE, bmpLarge.m_hBitmap);
persistorBitmaps.PersistAttribute(XML_ATTR_NODE_BITMAPS_MASK, strMask);
COLORREF crMask = wcstoul(strMask.c_str(), NULL, 16);
sc = ScHandleCustomImages (bmpSmall, bmpSmallOpen, bmpLarge, crMask);
if (sc)
sc.Throw();
}
/*
* We either writing or reading a modern XML file that has persisted
* the images in device-independent imagelist. Read/write them that way.
*/
else
{
persistorBitmaps.Persist (m_imlSmall, XML_NAME_NODE_BITMAP_SMALL);
persistorBitmaps.Persist (m_imlLarge, XML_NAME_NODE_BITMAP_LARGE);
if (persistor.IsLoading())
{
sc = ScAddImagesToImageList();
if (sc)
sc.Throw();
}
}
}
// setup snapins CD
if (persistor.IsLoading())
{
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
if (pCache == NULL)
sc.Throw(E_FAIL);
CSnapInPtr spSI;
sc = pCache->ScGetSnapIn(clsid, &spSI);
if (sc)
sc.Throw();
if (spSI != NULL)
SetPrimarySnapIn(spSI);
else
sc.Throw(E_UNEXPECTED);
pCache->SetDirty(FALSE);
}
// when storing, ask snapins to save their data first
if ( persistor.IsStoring() )
{
sc = ScSaveIComponentDatas();
if (sc)
sc.Throw();
sc = ScSaveIComponents();
if (sc)
sc.Throw();
}
persistor.Persist(m_CDPersistor);
persistor.Persist(m_ComponentPersistor);
/*
* Save/load the preload bit. Do this last to avoid busting old .msc files.
*/
BOOL bPreload = false;
if (persistor.IsStoring() && IsInitialized())
bPreload = IsPreloadRequired ();
persistor.PersistAttribute(XML_ATTR_MT_NODE_PRELOAD, CXMLBoolean(bPreload));
if (persistor.IsLoading())
SetPreloadRequired (bPreload);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScAddImagesToImageList
*
* Adds the small and small(open) bitmaps for the snap-in to the scope
* tree's imagelist.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScAddImagesToImageList()
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScAddImagesToImageList"));
/*
* get the scope tree's imagelist
*/
CScopeTree* pScopeTree = CScopeTree::GetScopeTree();
sc = ScCheckPointers (pScopeTree, E_UNEXPECTED);
if (sc)
return (sc);
WTL::CImageList imlScopeTree = pScopeTree->GetImageList();
if (imlScopeTree.IsNull())
return (sc = E_UNEXPECTED);
/*
* add images to scope tree's imagelist, first closed...
*/
CSmartIcon icon;
icon.Attach (m_imlSmall.GetIcon (0));
if (icon == NULL)
return (sc.FromLastError());
SetImage (imlScopeTree.AddIcon (icon));
/*
* ...then open
*/
icon.Attach (m_imlSmall.GetIcon (1));
if (icon == NULL)
return (sc.FromLastError());
SetOpenImage (imlScopeTree.AddIcon (icon));
return (sc);
}
CComponent* CMTSnapInNode::GetComponent(UINT nViewID, COMPONENTID nID,
CSnapIn* pSnapIn)
{
CNodeList& nodes = GetNodeList();
POSITION pos = nodes.GetHeadPosition();
CNode* pNode = NULL;
while (pos)
{
pNode = nodes.GetNext(pos);
if (pNode != NULL && pNode->GetViewID() == (int)nViewID)
break;
}
if(pNode == NULL)
return NULL;
ASSERT(pNode != NULL);
ASSERT(pNode->GetViewID() == (int)nViewID);
if (pNode->GetViewID() != (int)nViewID)
return NULL;
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
CComponent* pCC = pSINode->GetComponent(nID);
if (pCC == NULL)
pCC = pSINode->CreateComponent(pSnapIn, nID);
return pCC;
}
CNode* CMTSnapInNode::GetNode(CViewData* pViewData, BOOL fRootNode)
{
/*
* check for another CSnapInNode that already exists in this view
*/
CSnapInNode* pExistingNode = FindNode (pViewData->GetViewID());
CSnapInNode* pNewNode;
/*
* if this is the first CSnapInNode for this view, create a unique one
*/
if (fRootNode || (pExistingNode == NULL))
pNewNode = new CSnapInNode (this, pViewData, fRootNode);
/*
* otherwise, copy the node that's here
*/
else
pNewNode = new CSnapInNode (*pExistingNode);
return (pNewNode);
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::Reset
*
* PURPOSE: Resets the node in order to reload extensions. basically it forces
* save-load-init sequence to refresh the snapin node
*
* PARAMETERS:
*
* RETURNS:
* void
*
\***************************************************************************/
void CMTSnapInNode::Reset()
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::Reset"));
CSnapIn * pSnapIn = GetPrimarySnapIn();
ASSERT(pSnapIn != NULL);
// we will perform resetting of components and component datas
// by storing / loading them "the XML way"
// following that there is nothing what makes this node different
// from one loaded from XML, so we will change it's type
sc = ScSaveIComponentDatas();
if (sc)
sc.TraceAndClear(); // continue even on error
sc = ScSaveIComponents();
if (sc)
sc.TraceAndClear(); // continue even on error
// need to reset component XML streams/storage
sc = m_CDPersistor.ScReset();
if (sc)
sc.TraceAndClear(); // continue even on error
sc = m_ComponentPersistor.ScReset();
if (sc)
sc.TraceAndClear(); // continue even on error
// First Reset all the nodes
POSITION pos = m_NodeList.GetHeadPosition();
while (pos)
{
CSnapInNode* pSINode =
dynamic_cast<CSnapInNode*>(m_NodeList.GetNext(pos));
ASSERT(pSINode != NULL);
pSINode->Reset();
}
for (int i=0; i < m_ComponentDataArray.size(); i++)
delete m_ComponentDataArray[i];
m_ComponentDataArray.clear();
CMTNode::Reset();
ResetExpandedAtLeastOnce();
SetPrimarySnapIn(pSnapIn);
pos = m_NodeList.GetHeadPosition();
while (pos)
{
CSnapInNode* pSINode =
dynamic_cast<CSnapInNode*>(m_NodeList.GetNext(pos));
ASSERT(pSINode != NULL);
CComponent* pCC = new CComponent(pSnapIn);
pCC->SetComponentID(GetPrimaryComponentID());
pSINode->AddComponentToArray(pCC);
pSINode->SetPrimaryComponent(pCC);
}
Init();
pos = m_NodeList.GetHeadPosition();
while (pos)
{
CSnapInNode* pSINode =
dynamic_cast<CSnapInNode*>(m_NodeList.GetNext(pos));
ASSERT(pSINode != NULL);
pSINode->InitComponents();
}
}
/*+-------------------------------------------------------------------------*
* class CLegacyNodeConverter
*
*
* PURPOSE: Used to emulate the legacy node snapins' Save routines.
*
*+-------------------------------------------------------------------------*/
class CLegacyNodeConverter : public CSerialObjectRW
{
public:
CLegacyNodeConverter(LPCTSTR szName, LPCTSTR szView)
: m_strName(szName), m_strView(szView)
{
}
~CLegacyNodeConverter()
{
// must call detach or the strings will be removed from the string table.
m_strName.Detach();
m_strView.Detach();
}
public:
// CSerialObject methods
virtual UINT GetVersion() {return 1;}
virtual HRESULT ReadSerialObject (IStream &stm, UINT nVersion) {ASSERT(0 && "Should not come here."); return E_UNEXPECTED;}
virtual HRESULT WriteSerialObject(IStream &stm);
private: // attributes - persisted
CStringTableString m_strName; // the name of the root node, which is the only node created by the snapin
CStringTableString m_strView; // the view displayed by the node.
};
/*+-------------------------------------------------------------------------*
*
* CLegacyNodeConverter::WriteSerialObject
*
* PURPOSE: Writes out the name and view strings using the format expected
* by the built in snapins.
*
* PARAMETERS:
* IStream & stm :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT
CLegacyNodeConverter::WriteSerialObject(IStream &stm)
{
stm << m_strName;
stm << m_strView;
return S_OK;
}
/*+-------------------------------------------------------------------------*
*
* CMTSnapInNode::ScConvertLegacyNode
*
* PURPOSE: Reads in an legacy node and converts it to a built-in snapin node.
* 1) The original tree stream is read and the target URL or OCX is read.
* 2) The new Data stream with the munged CLSID name is created
* and the data required by the snapin is placed there. Because
* the bitmap etc is already loaded, and because the original
* stream is thrown away, we don't need to emulate the "tree"
* stream. Also, because this snapin has no view specific information,
* the views storage is not used.
*
* PARAMETERS: clsid: The CLSID of the built in snapin.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CMTSnapInNode::ScConvertLegacyNode(const CLSID &clsid)
{
USES_CONVERSION;
SC sc;
std::wstring strView;
CStream stream;
CStream nodeStream = NULL;
int iStorageOrStream=0;
IStreamPtr spCDStream;
bool bIsHTMLNode = (&clsid == &CLSID_HTMLSnapin);
bool bIsOCXNode = (&clsid == &CLSID_OCXSnapin);
// 1. load the base class
sc = CMTNode::ScLoad();
if(sc)
goto Error;
// get the tree stream.
stream.Attach(GetTreeStream());
// 2. read the URL or OCX string as needed.
if(bIsHTMLNode)
{
WCHAR* szView = NULL;
// get the string length of the label, and read the string.
unsigned int stringLength;
sc = stream.ScRead(&stringLength, sizeof(stringLength));
if(sc)
goto Error;
szView = reinterpret_cast<wchar_t*>(alloca((stringLength+1)*sizeof(WCHAR))); // allocates on stack, don't free.
if (szView == NULL)
goto PointerError;
sc = stream.ScRead(szView, stringLength*2);
if(sc)
goto Error;
szView[stringLength] = TEXT('\0'); // null terminate the string.
strView = szView;
}
else if(bIsOCXNode)
{
CLSID clsidOCX;
// Read OCX clsid
sc = stream.ScRead(&clsidOCX, sizeof(clsidOCX));
if(sc)
goto Error;
{
WCHAR szCLSID[40];
if (0 == StringFromGUID2 (clsidOCX, szCLSID, countof(szCLSID)))
{
sc = E_UNEXPECTED;
goto Error;
}
strView = szCLSID;
}
}
// at this point, strView contains either the URL or OCX CLSID.
// 3. Write node name
sc = m_CDPersistor.ScGetIStream( clsid, &spCDStream );
if (sc)
goto Error;
nodeStream.Attach( spCDStream );
if(NULL == nodeStream.Get())
goto PointerError;
// 4. Write out the Data stream.
{
tstring strName = GetDisplayName();
CLegacyNodeConverter converter(strName.data(), OLE2CT(strView.data()));
// call the converter to write out the stream.
sc = converter.Write(nodeStream);
if(sc)
goto Error;
}
// at this point, the "data" stream should be correctly written out.
// 5. For OCX nodes, convert the view streams and storages
/* OLD NEW
2 (node storage) 2 (node storage)
data data
tree tree
view view
1 <--- streams and storages --------- 1
2 <--- written by OCX, 1 per view -- \ 1jvmv2n4y1k471h9ujk86lite7 (OCX snap-in)
\ --------> ocx_stream (or ocx_storage)
\
------> 2 1jvmv2n4y1k471h9ujk86lite7 (OCX snap-in)
ocx_stream (or ocx_storage)
*/
if(bIsOCXNode)
{
for(iStorageOrStream = 1 /*NOT zero*/; ; iStorageOrStream++)
{
// create the name of the storage
CStr strStorageOrStream;
strStorageOrStream.Format(TEXT("%d"), iStorageOrStream);
// at this point strStorageOrStream should contain a number like "1"
CStorage storageView(GetViewStorage());
// rename the storage or stream labelled "1" to "temp" under the same parent.
sc = storageView.ScMoveElementTo(T2COLE(strStorageOrStream), storageView, L"temp", STGMOVE_MOVE);
if(sc == SC(STG_E_FILENOTFOUND)) // loop end condition - no more streams or storages
{
sc.Clear();
break;
}
if(sc)
goto Error;
// now we create the storage with the same name, eg "1"
{
WCHAR name[MAX_PATH];
sc = ScGetComponentStorageName(name, countof(name), clsid); // the name of the snapin component
if(sc)
goto Error;
CStorage storageNewView, storageSnapIn;
sc = storageNewView.ScCreate(storageView, T2COLE(strStorageOrStream),
STGM_WRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
L"\\node\\#\\view\\#\\storage" /*CHANGE*/);
if(sc)
goto Error;
// create the snapin's storage underneath the view's storage
sc = storageSnapIn.ScCreate(storageNewView, name,
STGM_WRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
L"\\node\\#\\view\\#\\storage\\#\\snapinStorage");
if(sc)
goto Error;
// move the "temp" stream or storage to the storage called L"ocx_streamorstorage"
// (which is what the OCX snapin expects.)
sc = storageView.ScMoveElementTo(L"temp", storageSnapIn, L"ocx_streamorstorage", STGMOVE_MOVE);
if(sc)
goto Error;
}
}
}
// 6. now do the same thing that CMTSnapInNode::ScLoad would do.
{
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
ASSERT(pCache != NULL);
if (pCache == NULL)
goto FailedError;
CSnapInPtr spSI;
sc = pCache->ScGetSnapIn(clsid, &spSI);
ASSERT(!sc.IsError() && spSI != NULL);
if (!sc.IsError() && spSI != NULL)
SetPrimarySnapIn(spSI);
pCache->SetDirty(FALSE);
if(sc)
goto Error;
}
// always set the preload bit.
SetPreloadRequired (true);
// Some actions (loading bitmaps for example) performed here invalidate the node
// and set the dirty flag. Since coverting legacy node may be done any time again
// the converted node should not be assumed as changed.
ClearDirty();
// read all the streams and storages for this node
sc = ScReadStreamsAndStoragesFromConsole();
if(sc)
goto Error;
Cleanup:
return sc;
FailedError:
sc = E_FAIL;
goto Error;
PointerError:
sc = E_POINTER;
Error:
TraceError(TEXT("CMTSnapInNode::ScConvertLegacyNode"), sc);
goto Cleanup;
}
HRESULT copyStream(IStream* dest, IStream* src)
{
ASSERT(dest != NULL);
ASSERT(src != NULL);
if (dest == NULL || src == NULL)
return E_POINTER;
const LARGE_INTEGER loc = {0,0};
ULARGE_INTEGER newLoc;
HRESULT hr = src->Seek(loc, STREAM_SEEK_SET, &newLoc);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
hr = dest->Seek(loc, STREAM_SEEK_SET, &newLoc);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return E_FAIL;
const ULARGE_INTEGER size = {0,0};
hr = dest->SetSize(size);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
STATSTG statstg;
hr = src->Stat(&statstg, STATFLAG_NONAME);
ASSERT(hr == S_OK);
if (hr != S_OK)
return E_FAIL;
ULARGE_INTEGER cr;
ULARGE_INTEGER cw;
hr = src->CopyTo(dest, statstg.cbSize, &cr, &cw);
#if 0 // for debugging...
for (long i = 0; true; i++)
{
BYTE b;
long bytesRead;
hr = src->Read(&b, sizeof(b), &bytesRead);
if (hr != S_OK)
return S_OK;
long bytesWritten;
hr = dest->Write(&b, bytesRead, &bytesWritten);
ASSERT(hr == S_OK);
ASSERT(bytesWritten == bytesRead);
if (hr != S_OK || bytesWritten != bytesRead)
return E_FAIL;
}
#endif
return S_OK;
}
//############################################################################
//############################################################################
//
// Helper functions
//
//############################################################################
//############################################################################
void DisplayPolicyErrorMessage(const CLSID& clsid, bool bExtension)
{
CStr strMessage;
if (bExtension)
strMessage.LoadString(GetStringModule(), IDS_EXTENSION_NOTALLOWED);
else
strMessage.LoadString(GetStringModule(), IDS_SNAPIN_NOTALLOWED);
// Get the snapin name for the error message.
CSnapInsCache* pSnapInsCache = theApp.GetSnapInsCache();
ASSERT(pSnapInsCache != NULL);
CSnapInPtr spSnapIn;
SC sc = pSnapInsCache->ScFindSnapIn(clsid, &spSnapIn);
if (!sc.IsError() && (NULL != spSnapIn))
{
WTL::CString strName;
sc = spSnapIn->ScGetSnapInName (strName);
if (!sc.IsError())
{
strMessage += _T("\n");
strMessage += strName;
strMessage += _T(".");
}
}
::MessageBox(NULL, strMessage, _T("MMC"), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
/***************************************************************************\
*
* METHOD: CMMCSnapIn::get_Vendor
*
* PURPOSE: returns vendor info for snapin. Implements OM property SnapIn.Vendor
*
* PARAMETERS:
* PBSTR pbstrVendor [out] - vendor info
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
STDMETHODIMP CMMCSnapIn::get_Vendor( PBSTR pbstrVendor )
{
DECLARE_SC(sc, TEXT("CMMCSnapIn::get_Vendor"));
sc = ScCheckPointers(pbstrVendor);
if (sc)
return sc.ToHr();
// init out parameter
*pbstrVendor = NULL;
// get the snapin about
CSnapinAbout *pSnapinAbout = NULL;
sc = ScGetSnapinAbout(pSnapinAbout);
if (sc)
return sc.ToHr();
// recheck the pointer
sc = ScCheckPointers(pSnapinAbout, E_UNEXPECTED);
if (sc)
return sc.ToHr();
*pbstrVendor = ::SysAllocString( pSnapinAbout->GetCompanyName() );
return sc.ToHr();
}
/***************************************************************************\
*
* METHOD: CMMCSnapIn::get_Version
*
* PURPOSE: returns version info for snapin. Implements OM property SnapIn.Version
*
* PARAMETERS:
* PBSTR pbstrVersion [out] - version info
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
STDMETHODIMP CMMCSnapIn::get_Version( PBSTR pbstrVersion )
{
DECLARE_SC(sc, TEXT("CMMCSnapIn::get_Version"));
sc = ScCheckPointers(pbstrVersion);
if (sc)
return sc.ToHr();
// init out parameter
*pbstrVersion = NULL;
// get the snapin about
CSnapinAbout *pSnapinAbout = NULL;
sc = ScGetSnapinAbout(pSnapinAbout);
if (sc)
return sc.ToHr();
// recheck the pointer
sc = ScCheckPointers(pSnapinAbout, E_UNEXPECTED);
if (sc)
return sc.ToHr();
*pbstrVersion = ::SysAllocString( pSnapinAbout->GetVersion() );
return sc.ToHr();
}
/***************************************************************************\
*
* METHOD: CMMCSnapIn::GetMTSnapInNode
*
* PURPOSE: helper. returns mtnode for the snapin
*
* PARAMETERS:
*
* RETURNS:
* CMTSnapInNode * - node
*
\***************************************************************************/
CMTSnapInNode * CMMCSnapIn::GetMTSnapInNode()
{
CMTSnapInNode *pMTSnapInNode = NULL;
SC sc = ScGetTiedObject(pMTSnapInNode);
if (sc)
return NULL;
return pMTSnapInNode;
}
/***************************************************************************\
*
* METHOD: CMMCSnapIn::ScGetSnapinAbout
*
* PURPOSE: helper. returns snapins about object
*
* PARAMETERS:
* CSnapinAbout*& pAbout [out] - snapins about object
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMMCSnapIn::ScGetSnapinAbout(CSnapinAbout*& pAbout)
{
DECLARE_SC(sc, TEXT("CMMCSnapIn::ScGetSnapinAbout"));
// init out param
pAbout = NULL;
// If the snapin object is already created just return it.
if (NULL != (pAbout = m_spSnapinAbout.get()))
return sc;
// get snapins clsid
CLSID clsidSnapin = GUID_NULL;
sc = GetSnapinClsid(clsidSnapin);
if (sc)
return sc;
CLSID clsidAbout; // get the about class-id.
sc = ScGetAboutFromSnapinCLSID(clsidSnapin, clsidAbout);
if (sc)
return sc;
if (clsidSnapin == GUID_NULL)
return sc = E_FAIL;
// Create about object
m_spSnapinAbout = SnapinAboutPtr (new CSnapinAbout);
if (! m_spSnapinAbout.get())
return sc = E_OUTOFMEMORY;
// and initialize it.
if (!m_spSnapinAbout->GetSnapinInformation(clsidAbout))
return sc = E_FAIL;
pAbout = m_spSnapinAbout.get();
return sc;
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::IsPreloadRequired
*
* Returns true if the snap-in wants MMCN_PRELOAD notifications, false
* otherwise.
*--------------------------------------------------------------------------*/
BOOL CMTSnapInNode::IsPreloadRequired () const
{
DECLARE_SC (sc, _T("CMTSnapInNode::IsPreloadRequired"));
/*
* if we don't know whether the snap-in wants MMCN_PRELOAD (because
* we haven't asked it yet), ask now
*/
if (m_ePreloadState == ePreload_Unknown)
{
/*
* assume preload isn't required
*/
m_ePreloadState = ePreload_False;
sc = ScQueryPreloadRequired (m_ePreloadState);
if (sc)
sc.TraceAndClear();
}
return (m_ePreloadState == ePreload_True);
}
/*+-------------------------------------------------------------------------*
* CMTSnapInNode::ScQueryPreloadRequired
*
* Asks the snap-in whether it requires preload notification by asking its
* data object for the CCF_SNAPIN_PRELOADS format.
*
* Returns in ePreload:
*
* ePreload_True snap-in requires MMCN_PRELOAD
* ePreload_False snap-in doesn't require MMCN_PRELOAD
*
* If anything fails during the process of asking the snap-in for
* CCF_SNAPIN_PRELOADS, the value of ePreload is unchanged.
*--------------------------------------------------------------------------*/
SC CMTSnapInNode::ScQueryPreloadRequired (
PreloadState& ePreload) const /* O:preload state for snap-in */
{
DECLARE_SC (sc, _T("CMTSnapInNode::ScQueryPreloadRequired"));
/*
* make sure we have a primary ComponentData
*/
CComponentData* pCCD = GetPrimaryComponentData();
sc = ScCheckPointers (pCCD, E_UNEXPECTED);
if (sc)
return (sc);
/*
* get the data object for this node
*/
IDataObjectPtr spDataObject;
sc = pCCD->QueryDataObject(GetUserParam(), CCT_SCOPE, &spDataObject);
if (sc)
return (sc);
sc = ScCheckPointers (spDataObject, E_UNEXPECTED);
if (sc)
return (sc);
/*
* CCF_SNAPIN_PRELOADS is an optional clipboard format, so it's not
* an error if ExtractData fails.
*/
BOOL bPreload = (ePreload == ePreload_True) ? TRUE : FALSE;
if (SUCCEEDED (ExtractData (spDataObject, GetPreLoadFormat(),
(BYTE*)&bPreload, sizeof(BOOL))))
{
ePreload = (bPreload) ? ePreload_True : ePreload_False;
}
return (sc);
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScReadStreamsAndStoragesFromConsole
*
* PURPOSE: Enumerates old (structured storage based) console.
* Enumerates the streams and storages under the snapin node.
* For each stream/storage found adds a copy to m_CDPpersistor
* or m_ComponentPersistor, indexed by a hash value (name in storage).
* These entries will be recognized and stored by a CLSID when
* CLSID is known ( when request by CLSID is made )
*
* PARAMETERS:
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScReadStreamsAndStoragesFromConsole()
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScReadStreamsAndStoragesFromConsole"));
IStorage* pNodeCDStorage = GetStorageForCD();
sc = ScCheckPointers( pNodeCDStorage, E_POINTER );
if (sc)
return sc;
IEnumSTATSTGPtr spEnum;
sc = pNodeCDStorage->EnumElements( 0, NULL, 0, &spEnum );
if (sc)
return sc;
// recheck pointer
sc = ScCheckPointers( spEnum, E_POINTER );
if (sc)
return sc;
// reset enumeration
sc = spEnum->Reset();
if (sc)
return sc;
// enumerate the items ( each entry is for separate component data )
while (1)
{
STATSTG statstg;
ZeroMemory( &statstg, sizeof(statstg) );
ULONG cbFetched = 0;
sc = spEnum->Next( 1, &statstg, &cbFetched );
if (sc)
return sc;
if ( sc != S_OK ) // - done
{
sc.Clear();
break;
}
// attach to the out param
CCoTaskMemPtr<WCHAR> spName( statstg.pwcsName );
// make a copy of streams and storages
if ( statstg.type == STGTY_STREAM )
{
IStreamPtr spStream;
sc = OpenDebugStream(pNodeCDStorage, spName, STGM_READ | STGM_SHARE_EXCLUSIVE,
L"\\node\\#\\data\\clsid", &spStream);
if (sc)
return sc;
sc = m_CDPersistor.ScInitIStream( spName, spStream );
if (sc)
return sc;
}
else if ( statstg.type == STGTY_STORAGE )
{
IStoragePtr spStorage;
sc = OpenDebugStorage(pNodeCDStorage, spName, STGM_READ | STGM_SHARE_EXCLUSIVE,
L"\\node\\#\\data\\clsid", &spStorage);
if (sc)
return sc;
sc = m_CDPersistor.ScInitIStorage( spName, spStorage );
if (sc)
return sc;
}
}
// view streams/storages
IStorage *pNodeComponentStorage = GetViewStorage();
sc = ScCheckPointers( pNodeComponentStorage, E_POINTER );
if (sc)
return sc;
spEnum = NULL;
sc = pNodeComponentStorage->EnumElements( 0, NULL, 0, &spEnum );
if (sc)
return sc;
// recheck pointer
sc = ScCheckPointers( spEnum, E_POINTER );
if (sc)
return sc;
// reset enumeration
sc = spEnum->Reset();
if (sc)
return sc;
// enumerate the items ( each entry is for separate view )
while (1)
{
STATSTG statstg;
ZeroMemory( &statstg, sizeof(statstg) );
ULONG cbFetched = 0;
sc = spEnum->Next( 1, &statstg, &cbFetched );
if (sc)
return sc;
if ( sc != S_OK ) // done
{
sc.Clear();
break;
}
// attach to the out param
CCoTaskMemPtr<WCHAR> spName( statstg.pwcsName );
// read the view storage
if ( statstg.type == STGTY_STORAGE )
{
int idView = CMTNode::GetViewIdFromStorageName(spName);
IStoragePtr spViewStorage;
sc = OpenDebugStorage(pNodeComponentStorage, spName, STGM_READ | STGM_SHARE_EXCLUSIVE,
L"\\node\\#\\view\\#", &spViewStorage);
if (sc)
return sc;
// enumerate what's inside a view storage
IEnumSTATSTGPtr spViewEnum;
sc = spViewStorage->EnumElements( 0, NULL, 0, &spViewEnum );
if (sc)
return sc;
// recheck pointer
sc = ScCheckPointers( spViewEnum, E_POINTER );
if (sc)
return sc;
// reset enumeration
sc = spViewEnum->Reset();
if (sc)
return sc;
// enumerate the items ( each entry is for separate component in a view )
while (1)
{
STATSTG statstg;
ZeroMemory( &statstg, sizeof(statstg) );
ULONG cbFetched = 0;
sc = spViewEnum->Next( 1, &statstg, &cbFetched );
if (sc)
return sc;
if ( sc != S_OK ) // - done
{
sc.Clear();
break;
}
// attach to the out param
CCoTaskMemPtr<WCHAR> spName( statstg.pwcsName );
// make a copy of streams and storages
if ( statstg.type == STGTY_STREAM )
{
IStreamPtr spStream;
sc = OpenDebugStream(spViewStorage, spName, STGM_READ | STGM_SHARE_EXCLUSIVE,
L"\\node\\#\\view\\#\\clsid", &spStream);
if (sc)
return sc;
sc = m_ComponentPersistor.ScInitIStream( idView, spName, spStream );
if (sc)
return sc;
}
else if ( statstg.type == STGTY_STORAGE )
{
IStoragePtr spStorage;
sc = OpenDebugStorage(spViewStorage, spName, STGM_READ | STGM_SHARE_EXCLUSIVE,
L"\\node\\#\\view\\#\\clsid", &spStorage);
if (sc)
return sc;
sc = m_ComponentPersistor.ScInitIStorage( idView, spName, spStorage );
if (sc)
return sc;
}
}
}
}
// by now we should have loaded everything from the console file
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScSaveIComponentDatas
*
* PURPOSE: Saves IComponentDatass for all snapins under this static scope node
*
* PARAMETERS:
*
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScSaveIComponentDatas( )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScSaveIComponentDatas"));
// if node is not initialized ( not expanded ) - nothing to save
// old data will be persisted.
if ( !IsInitialized() )
return sc;
// go for every component data we have
for( int i = 0; i< GetNumberOfComponentDatas(); i++ )
{
CComponentData* pCD = GetComponentData(i);
sc = ScCheckPointers(pCD, E_UNEXPECTED);
if (sc)
return sc;
sc = ScSaveIComponentData( pCD );
if (sc)
return sc;
}
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScSaveIComponentData
*
* PURPOSE: Determines snapin's IComponentData persistence capabilities (QI for IPersistXXXX)
* And asks it to save giving maintained stream/storage as a media.
*
* PARAMETERS:
* CComponentData* pCD [in] component data
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScSaveIComponentData( CComponentData* pCD )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScSaveIComponentData"));
sc = ScCheckPointers(pCD);
if (sc)
return sc;
// check if the component is initialized
if ( !pCD->IsIComponentDataInitialized() )
{
// compatibility with mmc1.2 - give another chance.
sc = ScInitIComponentData(pCD);
if (sc)
return sc;
}
// Check first for an IComponentData
IComponentData* const pICCD = pCD->GetIComponentData();
sc = ScCheckPointers( pICCD, E_UNEXPECTED );
if (sc)
return sc;
// Get the snapin name for the error message.
CSnapInPtr spSnapin = pCD->GetSnapIn();
// now ask the snapin to save the data
sc = ScAskSnapinToSaveData( pICCD, &m_CDPersistor, CDPersistor::VIEW_ID_DOCUMENT, pCD->GetCLSID(), spSnapin );
if (sc)
return sc;
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScSaveIComponents
*
* PURPOSE: Saves IComponents for all snapins under this static scope node
*
* PARAMETERS:
*
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScSaveIComponents( )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScSaveIComponents"));
// if node is not initialized ( not expanded ) - nothing to save
// old data will be persisted.
if ( !IsInitialized() )
return sc;
// go for every CNode in every view
CNodeList& nodes = GetNodeList();
POSITION pos = nodes.GetHeadPosition();
while (pos)
{
CNode* pNode = nodes.GetNext( pos );
sc = ScCheckPointers( pNode, E_UNEXPECTED );
if (sc)
return sc;
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
sc = ScCheckPointers(pSINode, E_UNEXPECTED);
if (sc)
return sc;
const int viewID = pNode->GetViewID();
const CComponentArray& components = pSINode->GetComponentArray();
const int size = components.size();
for (int i = 0; i < size; i++)
{
CComponent* pCC = components[i];
if ( pCC != NULL )
{
sc = ScSaveIComponent( pCC, viewID);
if (sc)
return sc;
}
}
}
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScSaveIComponent
*
* PURPOSE: Determines snapin's IComponent persistence capabilities (QI for IPersistXXXX)
* And asks it to save giving maintained stream/storage as a media.
*
* PARAMETERS:
* CComponent* pCComponent [in] component
* int viewID [in] view id for which the component is created
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScSaveIComponent( CComponent* pCComponent, int viewID )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScSaveIComponent"));
// parameter check
sc = ScCheckPointers( pCComponent );
if (sc)
return sc;
const CLSID& clsid = pCComponent->GetCLSID();
// check if the component is initialized (compatibility with mmc 1.2)
// give another chance to load
if ( !pCComponent->IsIComponentInitialized() )
{
sc = ScInitIComponent(pCComponent, viewID);
if (sc)
return sc;
}
// get IComponent
IComponent* pComponent = pCComponent->GetIComponent();
sc = ScCheckPointers(pComponent, E_UNEXPECTED);
if (sc)
return sc;
// Get the snapin to get name for the error message.
CSnapInPtr spSnapin = pCComponent->GetSnapIn();
// now ask the snapin to save the data
sc = ScAskSnapinToSaveData( pComponent, &m_ComponentPersistor, viewID, clsid, spSnapin );
if (sc)
return sc;
return sc;
}
/***************************************************************************\
*
* METHOD: CMTSnapInNode::ScAskSnapinToSaveData
*
* PURPOSE: Determines snapin persistence capabilities (QI for IPersistXXXX)
* And asks it to save giving maintained stream/storage as a media.
* This method is called to save both Components and ComponentDatas
*
* PARAMETERS:
* IUnknown *pSnapin [in] snapin which data needs to be saved
* CMTSnapinNodeStreamsAndStorages *pStreamsAndStorages
* [in] collection of streams/storage where to save
* int idView [in] view id - key for saved data
* const CLSID& clsid [in] class id - key for saved data
* CSnapIn *pCSnapin [in] pointer to CSnapin, used for display name on error
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CMTSnapInNode::ScAskSnapinToSaveData( IUnknown *pSnapin,
CMTSnapinNodeStreamsAndStorages *pStreamsAndStorages,
int idView , const CLSID& clsid, CSnapIn *pCSnapin )
{
DECLARE_SC(sc, TEXT("CMTSnapInNode::ScAskSnapinToSaveData"));
sc = ScCheckPointers( pSnapin, pStreamsAndStorages );
if (sc)
return sc;
IPersistStreamPtr spIPS;
IPersistStoragePtr spIPStg;
IPersistStreamInitPtr spIPSI;
// QI for IPersistStream
if ( (spIPS = pSnapin) != NULL)
{
// get the object for persistence
CXML_IStream *pXMLStream = NULL;
sc = pStreamsAndStorages->ScGetXmlStream( idView, clsid, pXMLStream );
if (sc)
return sc;
// recheck the pointer
sc = ScCheckPointers( pXMLStream, E_UNEXPECTED );
if (sc)
return sc;
// save data to stream
sc = pXMLStream->ScRequestSave( spIPS.GetInterfacePtr() );
if (sc)
goto DisplaySnapinError;
}
else if ( (spIPSI = pSnapin) != NULL) // QI for IPersistStreamInit
{
// get the object for persistence
CXML_IStream *pXMLStream = NULL;
sc = pStreamsAndStorages->ScGetXmlStream( idView, clsid, pXMLStream );
if (sc)
return sc;
// recheck the pointer
sc = ScCheckPointers( pXMLStream, E_UNEXPECTED );
if (sc)
return sc;
// save data to stream
sc = pXMLStream->ScRequestSave( spIPSI.GetInterfacePtr() );
if (sc)
goto DisplaySnapinError;
}
else if ( (spIPStg = pSnapin) != NULL) // QI for IPersistStorage
{
// get the object for persistence
CXML_IStorage *pXMLStorage = NULL;
sc = pStreamsAndStorages->ScGetXmlStorage( idView, clsid, pXMLStorage );
if (sc)
return sc;
// recheck the pointer
sc = ScCheckPointers( pXMLStorage, E_UNEXPECTED );
if (sc)
return sc;
// save data to storage
sc = pXMLStorage->ScRequestSave( spIPStg.GetInterfacePtr() );
if (sc)
goto DisplaySnapinError;
}
return sc;
// display snapin failure
DisplaySnapinError:
// need to inform the world...
CStr strMessage;
strMessage.LoadString(GetStringModule(), IDS_SNAPIN_SAVE_FAILED);
if (pCSnapin != NULL)
{
WTL::CString strName;
if (!pCSnapin->ScGetSnapInName(strName).IsError())
{
strMessage += _T("\n");
strMessage += strName;
strMessage += _T(".");
}
}
::MessageBox(NULL, strMessage, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
return sc;
}