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
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;
|
|
}
|
|
|