552 lines
14 KiB
C++
552 lines
14 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: doccnfg.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "doccnfg.h"
|
|
#include "comdbg.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// external references
|
|
extern const wchar_t* AMCSnapInCacheStreamName;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Class CMMCDocConfig implementation
|
|
|
|
CMMCDocConfig::~CMMCDocConfig()
|
|
{
|
|
if (IsFileOpen())
|
|
CloseFile();
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMMCDocConfig::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
return (InlineIsEqualGUID(IID_IDocConfig, riid)) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMMCDocConfig::OpenFile(BSTR bstrFilePath)
|
|
{
|
|
return ScOpenFile( bstrFilePath ).ToHr();
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMMCDocConfig::CloseFile()
|
|
{
|
|
return ScCloseFile().ToHr();
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMMCDocConfig::SaveFile(BSTR bstrFilePath)
|
|
{
|
|
return ScSaveFile(bstrFilePath).ToHr();
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMMCDocConfig::EnableSnapInExtension(BSTR bstrSnapIn, BSTR bstrExt, VARIANT_BOOL bEnable)
|
|
{
|
|
return ScEnableSnapInExtension(bstrSnapIn, bstrExt, bEnable).ToHr();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CMMCDocConfig::Dump
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CMMCDocConfig::Dump (LPCTSTR pszDumpFilePath)
|
|
{
|
|
return ScDump (pszDumpFilePath).ToHr();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CMMCDocConfig::CheckSnapinAvailability
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
STDMETHODIMP CMMCDocConfig::CheckSnapinAvailability (CAvailableSnapinInfo& asi)
|
|
{
|
|
return ScCheckSnapinAvailability(asi).ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScOpenFile
|
|
*
|
|
* PURPOSE: Opens the specified console file and reads snapin cache from it
|
|
*
|
|
* PARAMETERS:
|
|
* BSTR bstrFilePath [in] file name to read from
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScOpenFile(BSTR bstrFilePath)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScOpenFile"));
|
|
|
|
// Close currently open file
|
|
if (IsFileOpen())
|
|
{
|
|
sc = ScCloseFile();
|
|
if (sc)
|
|
sc.TraceAndClear(); // report the error and ignore
|
|
}
|
|
|
|
// parameter check
|
|
if (bstrFilePath == NULL || SysStringLen(bstrFilePath) == 0)
|
|
return sc = E_INVALIDARG;
|
|
|
|
USES_CONVERSION;
|
|
LPCTSTR lpstrFilePath = OLE2CT(bstrFilePath);
|
|
|
|
// create object to load the snapins
|
|
CAutoPtr<CSnapInsCache> spSnapInsCache( new CSnapInsCache );
|
|
sc = ScCheckPointers( spSnapInsCache, E_OUTOFMEMORY );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// load the data (use bas class method)
|
|
bool bXmlBased = false;
|
|
CXMLDocument xmlDocument;
|
|
IStoragePtr spStorage;
|
|
sc = ScLoadConsole( lpstrFilePath, bXmlBased, xmlDocument, &spStorage );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// examine file type
|
|
if ( !bXmlBased )
|
|
{
|
|
// structured storage - based console
|
|
IStreamPtr spStream;
|
|
sc = OpenDebugStream(spStorage, AMCSnapInCacheStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_READWRITE, L"SnapInCache", &spStream);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = spSnapInsCache->ScLoad(spStream);
|
|
if (sc)
|
|
return sc;
|
|
|
|
m_spStorage = spStorage;
|
|
}
|
|
else
|
|
{
|
|
// xml - based console
|
|
|
|
try // xml implementation throws sc's
|
|
{
|
|
// construct parent document
|
|
CXMLElement elemDoc = xmlDocument;
|
|
CPersistor persistorFile(xmlDocument, elemDoc);
|
|
// init
|
|
persistorFile.SetLoading(true);
|
|
|
|
// navigate to snapin cache
|
|
CPersistor persistorConsole ( persistorFile, XML_TAG_MMC_CONSOLE_FILE );
|
|
CPersistor persistorTree ( persistorConsole, XML_TAG_SCOPE_TREE );
|
|
|
|
// load
|
|
persistorTree.Persist(*spSnapInsCache);
|
|
|
|
// hold onto the persistor info
|
|
m_XMLDocument = persistorConsole.GetDocument();
|
|
m_XMLElemConsole = persistorConsole.GetCurrentElement();
|
|
m_XMLElemTree = persistorTree.GetCurrentElement();
|
|
}
|
|
catch(SC& sc_thrown)
|
|
{
|
|
return (sc = sc_thrown);
|
|
}
|
|
}
|
|
|
|
// keep on the pointer
|
|
m_spCache.Attach( spSnapInsCache.Detach() );
|
|
m_strFilePath = lpstrFilePath;
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScCloseFile
|
|
*
|
|
* PURPOSE: closes open file
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScCloseFile()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScCloseFile"));
|
|
|
|
if (!IsFileOpen())
|
|
return sc = E_UNEXPECTED;
|
|
|
|
// release everything
|
|
m_spStorage = NULL;
|
|
m_strFilePath.erase();
|
|
m_spCache.Delete();
|
|
m_XMLDocument = CXMLDocument();
|
|
m_XMLElemConsole = CXMLElement();
|
|
m_XMLElemTree = CXMLElement();
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: ScFindAndTruncateChild
|
|
*
|
|
* PURPOSE: helper; locates the element by tag and removes all element's contents
|
|
* Doing so instead of deleting and recreating the element preserves all
|
|
* the formating and tag order in xml document
|
|
*
|
|
* PARAMETERS:
|
|
* CPersistor& parent [in] - parent persistor
|
|
* LPCTSTR strTag [in] - child's tag
|
|
* CXMLElement& child [out] - child's element
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC ScFindAndTruncateChild(CPersistor& parent, LPCTSTR strTag, CXMLElement& child)
|
|
{
|
|
DECLARE_SC(sc, TEXT("ScTruncateChild"));
|
|
|
|
try
|
|
{
|
|
// create persistor for the old cache tag
|
|
parent.SetLoading(true); // we want 'loading-alike' navigation
|
|
CPersistor persistorChild( parent, strTag );
|
|
parent.SetLoading(false); // restore saving behavior
|
|
|
|
// get the element
|
|
CXMLElement elChild = persistorChild.GetCurrentElement();
|
|
|
|
// get nodes under the element
|
|
CXMLElementCollection colChildren;
|
|
elChild.get_children( &colChildren );
|
|
|
|
long count = 0;
|
|
colChildren.get_count( &count );
|
|
|
|
// iterate and delete all the nodes
|
|
while (count > 0)
|
|
{
|
|
CXMLElement el;
|
|
colChildren.item( 0, &el);
|
|
|
|
elChild.removeChild(el);
|
|
|
|
--count;
|
|
}
|
|
|
|
// return the element
|
|
child = elChild;
|
|
}
|
|
catch(SC& sc_thrown)
|
|
{
|
|
return (sc = sc_thrown);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScSaveFile
|
|
*
|
|
* PURPOSE: Saves file to specified location
|
|
*
|
|
* PARAMETERS:
|
|
* BSTR bstrFilePath [in] file path to save to. NULL -> same as load
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScSaveFile(BSTR bstrFilePath)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScSaveFile"));
|
|
|
|
if (!IsFileOpen() || m_spCache == NULL)
|
|
return sc = E_UNEXPECTED;
|
|
|
|
USES_CONVERSION;
|
|
|
|
// if new path specified, save local copy as new default
|
|
if ( bstrFilePath && SysStringLen(bstrFilePath) != 0)
|
|
m_strFilePath = OLE2CT(bstrFilePath);
|
|
|
|
// remove extensions marked for deletion
|
|
m_spCache->Purge(TRUE);
|
|
|
|
if ( m_spStorage != NULL ) // not the XML way?
|
|
{
|
|
// replace snapin cache stream with new cache contents
|
|
IStreamPtr spStream;
|
|
sc = CreateDebugStream(m_spStorage, AMCSnapInCacheStreamName,
|
|
STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, L"SnapInCache", &spStream);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// save the cache
|
|
sc = m_spCache->ScSave(spStream, TRUE);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Create storage for the requested file
|
|
IStoragePtr spNewStorage;
|
|
sc = CreateDebugDocfile( T2COLE( m_strFilePath.c_str() ),
|
|
STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE,
|
|
&spNewStorage);
|
|
|
|
if (sc)
|
|
return sc;
|
|
|
|
// copy the working storage to the new file
|
|
sc = m_spStorage->CopyTo(NULL, NULL, NULL, spNewStorage);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// lets hold on the new one
|
|
m_spStorage = spNewStorage;
|
|
}
|
|
else
|
|
{
|
|
try // may throw
|
|
{
|
|
// save the data
|
|
|
|
CPersistor persistorTree( m_XMLDocument, m_XMLElemTree );
|
|
|
|
// this is more tricky than loading - we want to reuse the same tag
|
|
|
|
CXMLElement elCache;
|
|
sc = ScFindAndTruncateChild(persistorTree, m_spCache->GetXMLType(), elCache);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// create persistor for the new cache tag
|
|
CPersistor persistorCache( persistorTree, elCache );
|
|
|
|
// now persist under the new tag
|
|
m_spCache->Persist(persistorCache);
|
|
|
|
// update documents guid to invalidate user data
|
|
|
|
GUID guidConsoleId;
|
|
sc = CoCreateGuid(&guidConsoleId);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// persistor for console
|
|
CPersistor persistorConsole ( m_XMLDocument, m_XMLElemConsole );
|
|
persistorConsole.SetLoading(false);
|
|
|
|
CXMLElement elGuid;
|
|
sc = ScFindAndTruncateChild(persistorConsole, XML_TAG_CONSOLE_FILE_UID, elGuid);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// create persistor for the new guid tag
|
|
CPersistor persistorGuid( persistorConsole, elGuid );
|
|
|
|
// now persist under the new tag
|
|
persistorGuid.PersistContents(guidConsoleId);
|
|
|
|
//save to file
|
|
sc = ScSaveConsole( m_strFilePath.c_str(), true/*bForAuthorMode*/, m_XMLDocument);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
catch(SC& sc_thrown)
|
|
{
|
|
return (sc = sc_thrown);
|
|
}
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScEnableSnapInExtension
|
|
*
|
|
* PURPOSE: Enables extension in snapin cache
|
|
*
|
|
* PARAMETERS:
|
|
* BSTR bstrSnapIn [in] classid of the snapin
|
|
* BSTR bstrExt [in] classid of extension
|
|
* VARIANT_BOOL bEnable [in] enable/disable flag
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScEnableSnapInExtension(BSTR bstrSnapIn, BSTR bstrExt, VARIANT_BOOL bEnable)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScEnableSnapInExtension"));
|
|
|
|
CLSID SnapInCLSID;
|
|
CLSID ExtCLSID;
|
|
CSnapInPtr spBaseSnapIn;
|
|
CSnapInPtr spExtSnapIn;
|
|
|
|
// convert input strings to CLSIDs
|
|
sc = CLSIDFromString(bstrSnapIn, &SnapInCLSID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = CLSIDFromString( bstrExt, &ExtCLSID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Locate base snap-in in cache
|
|
sc = m_spCache->ScFindSnapIn(SnapInCLSID, &spBaseSnapIn);
|
|
if (sc)
|
|
return sc = E_INVALIDARG;
|
|
|
|
// Check if extension is enabled
|
|
CExtSI* pExt = spBaseSnapIn->GetExtensionSnapIn();
|
|
while (pExt != NULL)
|
|
{
|
|
if (pExt->GetSnapIn()->GetSnapInCLSID() == ExtCLSID)
|
|
break;
|
|
|
|
pExt = pExt->Next();
|
|
}
|
|
|
|
// if extension is present and not marked for deletion
|
|
if (pExt != NULL && !pExt->IsMarkedForDeletion())
|
|
{
|
|
// If should be disabled, just mark deleted
|
|
if (!bEnable)
|
|
pExt->MarkDeleted(TRUE);
|
|
}
|
|
else
|
|
{
|
|
// if should be enabled
|
|
if (bEnable)
|
|
{
|
|
// if extension is present, just undelete
|
|
if (pExt != NULL)
|
|
{
|
|
pExt->MarkDeleted(FALSE);
|
|
}
|
|
else
|
|
{
|
|
// Find or create cache entry for extension snapin
|
|
sc = m_spCache->ScGetSnapIn(ExtCLSID, &spExtSnapIn);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Add as extension to base snapin
|
|
spBaseSnapIn->AddExtension(spExtSnapIn);
|
|
}
|
|
}
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScDump
|
|
*
|
|
* PURPOSE: dumps contents of snapin cache
|
|
*
|
|
* PARAMETERS:
|
|
* LPCTSTR pszDumpFilePath [in] file to dump to
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScDump (LPCTSTR pszDumpFilePath)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScDump"));
|
|
|
|
/*
|
|
* validate input
|
|
*/
|
|
sc = ScCheckPointers (pszDumpFilePath);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (pszDumpFilePath[0] == 0)
|
|
return sc = E_INVALIDARG;
|
|
|
|
/*
|
|
* make sure a file is open
|
|
*/
|
|
if (!IsFileOpen())
|
|
return ((sc = E_UNEXPECTED).ToHr());
|
|
|
|
sc = ScCheckPointers (m_spCache, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
return (m_spCache->Dump (pszDumpFilePath));
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMMCDocConfig::ScCheckSnapinAvailability
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* BOOL f32bit [in] // check 32-bit (vs. 64-bit) snap-ins?
|
|
* UINT& cTotalSnapins [out] // total number of snap-ins referenced in the console file
|
|
* UINT& cAvailableSnapins [out] // number of snap-ins available in the requested memory model
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CMMCDocConfig::ScCheckSnapinAvailability (CAvailableSnapinInfo& asi)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMMCDocConfig::ScCheckSnapinAvailability"));
|
|
|
|
/*
|
|
* make sure a file is open
|
|
*/
|
|
if (!IsFileOpen())
|
|
return ((sc = E_UNEXPECTED).ToHr());
|
|
|
|
sc = ScCheckPointers (m_spCache, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_spCache->ScCheckSnapinAvailability (asi);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|