Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1942 lines
54 KiB

//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: SnapIn.cpp
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 9/11/1996 RaviR Created
//
//____________________________________________________________________________
#include "stdafx.h"
#include "util.h"
#include "NodeMgr.h"
#include "regutil.h"
#include "regkeyex.h"
#include "tstring.h"
#include "about.h"
#include "bitmap.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*
* define our own Win64 symbol to make it easy to include 64-bit only
* code in the 32-bit build, so we can exercise some code on 32-bit Windows
* where the debuggers are better
*/
#ifdef _WIN64
#define MMC_WIN64
#endif
#ifdef MMC_WIN64
#include "wow64reg.h" // for REG_OPTION_OPEN_32BITKEY
#endif
#ifdef DBG
#ifdef MMC_WIN64
CTraceTag tagSnapinAnalysis64 (_T("64/32-bit interop"), _T("Snap-in analysis"));
CTraceTag tagVerboseSnapinAnalysis64 (_T("64/32-bit interop"), _T("Snap-in analysis (verbose)"));
#endif // MMC_WIN64
#endif
/*+-------------------------------------------------------------------------*
* tstringFromCLSID
*
* Returns the text representation of a CLSID in a tstring.
*--------------------------------------------------------------------------*/
tstring tstringFromCLSID (REFCLSID clsid)
{
WCHAR wzCLSID[40];
int nChars = StringFromGUID2 (clsid, wzCLSID, countof(wzCLSID));
if (nChars == 0)
return tstring();
USES_CONVERSION;
return (W2T (wzCLSID));
}
/*+-------------------------------------------------------------------------*
* GetModuleVersion
*
* Reads the version resource in a module and returns the version string.
*--------------------------------------------------------------------------*/
DWORD GetModuleVersion (LPCTSTR pszModule, LPTSTR pszBuffer, int cchBuffer)
{
DECLARE_SC(sc, TEXT("GetModuleVersion"));
// check parameters
sc = ScCheckPointers(pszModule, pszBuffer);
if(sc)
return 0;
// validate the buffer
BufferCchValidate(pszBuffer, cchBuffer);
static bool fAttemptedVersionDllLoad = false;
static DWORD (APIENTRY* pfnGetFileVersionInfoSize)(LPCTSTR, LPDWORD) = NULL;
static BOOL (APIENTRY* pfnGetFileVersionInfo)(LPCTSTR, DWORD, DWORD, LPVOID) = NULL;
static BOOL (APIENTRY* pfnVerQueryValue)(LPBYTE, LPCTSTR, LPVOID*, PUINT) = NULL;
if (!fAttemptedVersionDllLoad)
{
/*
* only try once
*/
fAttemptedVersionDllLoad = true;
HINSTANCE hinst = LoadLibrary (_T("version.dll"));
if (hinst != NULL)
{
#ifdef UNICODE
(FARPROC&)pfnGetFileVersionInfoSize = GetProcAddress (hinst, "GetFileVersionInfoSizeW");
(FARPROC&)pfnGetFileVersionInfo = GetProcAddress (hinst, "GetFileVersionInfoW");
(FARPROC&)pfnVerQueryValue = GetProcAddress (hinst, "VerQueryValueW");
#else
(FARPROC&)pfnGetFileVersionInfoSize = GetProcAddress (hinst, "GetFileVersionInfoSizeA");
(FARPROC&)pfnGetFileVersionInfo = GetProcAddress (hinst, "GetFileVersionInfoA");
(FARPROC&)pfnVerQueryValue = GetProcAddress (hinst, "VerQueryValueA");
#endif
}
}
*pszBuffer = 0;
if (pfnGetFileVersionInfoSize != NULL)
{
ASSERT (pfnGetFileVersionInfo != NULL);
ASSERT (pfnVerQueryValue != NULL);
ULONG lUnused;
DWORD cbVerInfo = pfnGetFileVersionInfoSize (pszModule, &lUnused);
if (cbVerInfo > 0)
{
LPBYTE pbVerInfo = new BYTE[cbVerInfo];
VS_FIXEDFILEINFO* pffi;
if (pfnGetFileVersionInfo != NULL && pfnVerQueryValue != NULL &&
pfnGetFileVersionInfo (pszModule, NULL, cbVerInfo, pbVerInfo) &&
pfnVerQueryValue (pbVerInfo, _T("\\"), (void**) &pffi, (UINT*)&lUnused))
{
SC sc = StringCchPrintf (pszBuffer, cchBuffer, _T("%d.%d.%d.%d"),
HIWORD (pffi->dwFileVersionMS),
LOWORD (pffi->dwFileVersionMS),
HIWORD (pffi->dwFileVersionLS),
LOWORD (pffi->dwFileVersionLS));
if(sc)
return 0;
}
delete[] pbVerInfo;
}
}
return (lstrlen (pszBuffer));
}
/*+-------------------------------------------------------------------------*
* SafeWriteProfileString
*
*
*--------------------------------------------------------------------------*/
inline void SafeWritePrivateProfileString (
LPCTSTR pszSection,
LPCTSTR pszKey,
LPCTSTR psz,
LPCTSTR pszFile)
{
if (!WritePrivateProfileString (pszSection, pszKey, psz, pszFile))
THROW_ON_FAIL (HRESULT_FROM_WIN32 (GetLastError()));
}
//____________________________________________________________________________
//
// Member: CSnapIn::CSnapIn, Constructor
//
// History: 9/19/1996 RaviR Created
//____________________________________________________________________________
//
// {E6DFFF74-6FE7-11d0-B509-00C04FD9080A}
const GUID IID_CSnapIn =
{ 0xe6dfff74, 0x6fe7, 0x11d0, { 0xb5, 0x9, 0x0, 0xc0, 0x4f, 0xd9, 0x8, 0xa } };
// {7A85B79C-BDED-11d1-A4FA-00C04FB6DD2C}
static const GUID GUID_EnableAllExtensions =
{ 0x7a85b79c, 0xbded, 0x11d1, { 0xa4, 0xfa, 0x0, 0xc0, 0x4f, 0xb6, 0xdd, 0x2c } };
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapIn);
CSnapIn::CSnapIn()
:m_pExtSI(NULL), m_dwFlags(SNAPIN_ENABLE_ALL_EXTS), m_ExtPersistor(*this)
{
TRACE_CONSTRUCTOR(CSnapIn);
#ifdef DBG
dbg_cRef = 0;
#endif
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapIn);
}
CSnapIn::~CSnapIn()
{
DECLARE_SC(sc, TEXT("CSnapIn::~CSnapIn"));
Dbg(DEB_USER1, _T("CSnapIn::~CSnapIn\n"));
sc = ScDestroyExtensionList();
if (sc)
{
}
#ifdef DBG
ASSERT(dbg_cRef <= 0);
#endif
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapIn);
}
DEBUG_DECLARE_INSTANCE_COUNTER(CExtSI);
CExtSI::CExtSI(CSnapIn* pSnapIn)
: m_pSnapIn(pSnapIn), m_pNext(NULL), m_dwFlags(0)
{
ASSERT(pSnapIn != NULL);
m_pSnapIn->AddRef();
DEBUG_INCREMENT_INSTANCE_COUNTER(CExtSI);
}
CExtSI::~CExtSI(void)
{
SAFE_RELEASE(m_pSnapIn);
delete m_pNext;
DEBUG_DECREMENT_INSTANCE_COUNTER(CExtSI);
}
CSnapInsCache::CSnapInsCache()
: m_bIsDirty(FALSE), m_bUpdateHelpColl(false)
{
}
CSnapInsCache::~CSnapInsCache()
{
DECLARE_SC(sc, TEXT("CSnapInsCache::~CSnapInsCache"));
// destruction will remove all snapins, but ask them to release extensions first,
// this will break all circular references (else such snapins objects will be leaked).
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
// get pointer to the snapin
CSnapIn* pSnapIn = it->second;
sc = ScCheckPointers( pSnapIn, E_UNEXPECTED );
if (sc)
{
sc.TraceAndClear();
continue;
}
// ask snapin to destroy extension list
sc = pSnapIn->ScDestroyExtensionList();
if (sc)
sc.TraceAndClear();
}
}
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScIsDirty
*
* PURPOSE: returns dirty status of Snapin Cache
*
* PARAMETERS:
*
* RETURNS:
* SC - result code [SC(S_OK) - if dirty, SC(S_FALSE) else]
*
\***************************************************************************/
SC CSnapInsCache::ScIsDirty()
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScIsDirty"));
TraceDirtyFlag(TEXT("CSnapInsCache"), m_bIsDirty);
sc = m_bIsDirty ? SC(S_OK) : SC(S_FALSE);
return sc;
}
void CSnapInsCache::SetDirty(BOOL bIsDirty)
{
m_bIsDirty = bIsDirty;
}
/***************************************************************************\
*
* METHOD: CSnapInsCache::Purge
*
* PURPOSE: Cleanup Snapin Cache by usage information
* Uses sphisticated algorithm to find out which snapins are not used
* see ScMarkExternallyReferencedSnapins() for description
* removes snapins which are not referenced externally
*
* PARAMETERS:
* BOOL bExtensionsOnly
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
void CSnapInsCache::Purge(BOOL bExtensionsOnly)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::Purge"));
int iSnapIn;
// Delete all extensions marked as deleted
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
CSnapIn* pSnapIn = it->second;
ASSERT(pSnapIn != NULL);
if (it->second != NULL)
it->second->PurgeExtensions();
}
if (bExtensionsOnly)
return;
// Delete all snapins that have no external references
sc = ScMarkExternallyReferencedSnapins();
if (sc)
return; // error occured - do not remove anything
// remove not referenced
for ( it = m_snapins.begin(); it != m_snapins.end(); )
{
CSnapIn *pSnapin = it->second;
sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
if (sc)
return;
bool bExternallyReferenced;
sc = pSnapin->ScTempState_IsExternallyReferenced( bExternallyReferenced );
if (sc)
return;
if ( !bExternallyReferenced )
{
// destory extension list - it will break all circular references if such exist
// (note- extension list is not needed anymore - snapin is not used anyway)
sc = pSnapin->ScDestroyExtensionList();
if (sc)
return;
// remove snapin from the cache;
// in combination with the call above this will delete the object.
it = m_snapins.erase( it );
}
else
{
++it; // go to the next snapin
}
}
}
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScMarkExternallyReferencedSnapins
*
* PURPOSE: Marks all snapins in cache according to presence of external references
* This is done by following algorithm:
* 1) For each snapin in the cache, all extensions have a temporary reference
* count incremented. Thus, at the end of this step, each snapin's temp
* ref count is equal to the number of snapins it extends.
2) Each snapin compares the temp reference count to the total number of
references to it, taking into account the fact that the snapin cache
itself holds a reference to each snapin. If the total references exceed
the temp references, this indicates that the snapin has one or more
external references to it.
* Such a snapin is marked as "Externally referenced" as well as all its
* extensions.
*
* At the end of the process each snapin has a boolean flag indicating if
* the snapin is externally referenced. This flag is used in subsequential cache cleanup,
* or help topic building operation.
*
* PARAMETERS:
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapInsCache::ScMarkExternallyReferencedSnapins()
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScMarkExternallyReferencedSnapins"));
// 1. reset the reference calculation data
for ( map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it )
{
CSnapIn *pSnapin = it->second;
sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
if (sc)
return sc;
sc = pSnapin->ScTempState_ResetReferenceCalculationData();
if (sc)
return sc;
}
// 2. update internal reference counts
for ( it = m_snapins.begin(); it != m_snapins.end(); ++it )
{
CSnapIn *pSnapin = it->second;
sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
if (sc)
return sc;
sc = pSnapin->ScTempState_UpdateInternalReferenceCounts();
if (sc)
return sc;
}
// now the snapins which have more references than internal ones do clearly
// have direct external references
// we can mark them and their extensions as "referenced"
// 3. mark snapins with external references
// Note: this step must occur after step 2 completes for ALL snapins.
for ( it = m_snapins.begin(); it != m_snapins.end(); ++it )
{
CSnapIn *pSnapin = it->second;
sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
if (sc)
return sc;
sc = pSnapin->ScTempState_MarkIfExternallyReferenced();
if (sc)
return sc;
}
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScGetSnapIn
*
* PURPOSE: either finds the snapin in cache , either creates the new one
*
* PARAMETERS:
* REFCLSID rclsid - class id of snapin
* CSnapIn** ppSnapIn - result
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapInsCache::ScGetSnapIn(REFCLSID rclsid, CSnapIn** ppSnapIn)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScGetSnapIn"));
// first - parameter check
sc = ScCheckPointers(ppSnapIn);
if (sc)
return sc;
// second - initialization
*ppSnapIn = NULL;
//
// See if it already exists.
//
sc = ScFindSnapIn(rclsid, ppSnapIn);
if (!sc.IsError())
return sc; // jus return OK if we have it
//
// Create a new one & cache it
//
try
{
// Allocate the object
CComObject<CSnapIn> *pSnapin = NULL;
sc = CComObject<CSnapIn>::CreateInstance(&pSnapin);
if (sc)
return sc;
// be sure we didn't get the NULL
sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
if (sc)
return sc;
CSnapInPtr spSnapin = pSnapin;
// Copy the object impl clsid
spSnapin->SetSnapInCLSID(rclsid);
//
// Cache the object.
//
// note - this insertion also AddRef's the pointer
m_snapins[rclsid] = spSnapin;
*ppSnapIn = spSnapin.Detach(); // transfer reference to caller
}
catch( std::bad_alloc )
{
sc = E_OUTOFMEMORY;
}
return sc;
}
#ifdef DBG
void CSnapInsCache::DebugDump(void)
{
TRACE(_T("===========Dump of SnapinsCache ===============\n"));
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
OLECHAR strGUID[64];
CSnapIn* pSnapIn = it->second;
StringFromGUID2(pSnapIn->GetSnapInCLSID(), strGUID, countof(strGUID));
#ifdef DBG
TRACE(_T("%s: RefCnt = %d, %s\n"), strGUID, pSnapIn->m_dwRef,
pSnapIn->HasNameSpaceChanged() ? _T("NameSpace changed") : _T("No change"));
#endif
CExtSI* pExt = pSnapIn->GetExtensionSnapIn();
while (pExt != NULL)
{
StringFromGUID2(pExt->GetSnapIn()->GetSnapInCLSID(), strGUID, countof(strGUID));
#ifdef DBG
// TODO: go to registry to see the type of extension:
// these flags are not updated consistently
TRACE(_T(" %s: %s%s Extends(%s%s%s%s)\n"), strGUID,
pExt->IsNew() ? _T("New ") : _T(""),
pExt->IsMarkedForDeletion() ? _T("Deleted ") : _T(""),
pExt->ExtendsNameSpace() ? _T("NameSpace ") : _T(""),
pExt->ExtendsContextMenu() ? _T("Menu ") : _T(""),
pExt->ExtendsToolBar() ? _T("ToolBar ") : _T(""),
pExt->ExtendsPropertySheet() ? _T("Properties") : _T(""),
pExt->ExtendsView() ? _T("View") : _T(""),
pExt->ExtendsTask() ? _T("Task") : _T("")
);
#endif
pExt = pExt->Next();
}
}
}
#endif // DBG
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScFindSnapIn
*
* PURPOSE: finds the snapin by class id and returns AddRef'ed pointer
*
* PARAMETERS:
* REFCLSID rclsid - class id of the snapin
* CSnapIn** ppSnapIn - resulting pointer
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapInsCache::ScFindSnapIn(REFCLSID rclsid, CSnapIn** ppSnapIn)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScFindSnapIn"));
// first - parameter check
sc = ScCheckPointers(ppSnapIn);
if (sc)
return sc;
// second - initialization
*ppSnapIn = NULL;
// and now wee will se if we have one
map_t::iterator it = m_snapins.find(rclsid);
if (it == m_snapins.end())
return E_FAIL; // not assigning to sc, since it's not really an error condition
// be sure we do not return the NULL
sc = ScCheckPointers(it->second, E_UNEXPECTED);
if (sc)
return sc;
*ppSnapIn = it->second;
(*ppSnapIn)->AddRef();
return sc;
}
#ifdef TEMP_SNAPIN_MGRS_WORK
// Get all extensions.
void CSnapInsCache::GetAllExtensions(CSnapIn* pSI)
{
if (!pSI)
return;
CExtensionsCache extnsCache;
HRESULT hr = MMCGetExtensionsForSnapIn(pSI->GetSnapInCLSID(), extnsCache);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return;
CExtensionsCacheIterator it(extnsCache);
for (; it.IsEnd() == FALSE; it.Advance())
{
CSnapInPtr spSITemp;
hr = GetSnapIn(it.GetKey(), &spSITemp);
ASSERT(SUCCEEDED(hr));
pSI->AddExtension(spSITemp);
}
}
#endif // TEMP_SNAPIN_MGRS_WORK
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScSave
*
* PURPOSE: saves contents of Snapin Cache to IStream
*
* PARAMETERS:
* IStream* pStream - save to this stream
* BOOL bClearDirty - reset dirty flag after save
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapInsCache::ScSave(IStream* pStream, BOOL bClearDirty)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScSave"));
// check the params
sc = ScCheckPointers(pStream);
if (sc)
return sc;
// iterate ans save all snapins
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
CSnapIn* pSnapIn = it->second;
ASSERT(pSnapIn != NULL);
if (pSnapIn != NULL)
{
sc = pSnapIn->Save(pStream, bClearDirty);
if (sc)
return sc;
}
}
// terminating marker
ULONG bytesWritten;
sc = pStream->Write(&GUID_NULL, sizeof(GUID_NULL), &bytesWritten);
if (sc)
return sc;
ASSERT(bytesWritten == sizeof(GUID_NULL));
if (bClearDirty)
SetDirty(FALSE);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CSnapInsCache::Persist
*
* PURPOSE: Persists the CSnapInsCache to the specified persistor.
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapInsCache::Persist(CPersistor& persistor)
{
if (persistor.IsStoring())
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
CSnapIn* pSnapIn = it->second;
ASSERT(pSnapIn != NULL);
if (pSnapIn != NULL)
persistor.Persist(*pSnapIn);
}
else
{
XMLListCollectionBase::Persist(persistor);
SetDirty(FALSE);
}
}
/*+-------------------------------------------------------------------------*
*
* CSnapInsCache::OnNewElement
*
* PURPOSE: called for each saved instance found in XML file.
* creates and uploads new snapin entry
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapInsCache::OnNewElement(CPersistor& persistor)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::OnNewElement"));
ASSERT(persistor.IsLoading());
CLSID clsid;
CPersistor persistorSnapin(persistor, XML_TAG_SNAPIN);
persistor.PersistAttribute(XML_ATTR_SNAPIN_CLSID, clsid);
// create and upload snapin
CSnapInPtr spSnapIn;
sc = ScGetSnapIn(clsid, &spSnapIn);
if (sc) // failed to creatre
sc.Throw();
if (spSnapIn != NULL)
spSnapIn->PersistLoad(persistor,this);
else // OK reported, pointer still NULL
sc.Throw(E_POINTER);
}
/***************************************************************************\
*
* METHOD: CSnapInsCache::ScLoad
*
* PURPOSE: loads snapin cache from IStream
*
* PARAMETERS:
* IStream* pStream - stream to load from
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapInsCache::ScLoad(IStream* pStream)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::ScLoad"));
// parameter check
sc = ScCheckPointers(pStream);
if (sc)
return sc;
// loop thru saved snapins...
do
{
CLSID clsid;
ULONG bytesRead;
sc = pStream->Read(&clsid, sizeof(clsid), &bytesRead);
if (sc)
return sc;
ASSERT(bytesRead == sizeof(clsid));
// ... until special marker is found
if (clsid == GUID_NULL)
{
SetDirty(FALSE);
return S_OK;
}
// creale new snapin
CSnapInPtr spSnapIn;
sc = ScGetSnapIn(clsid, &spSnapIn);
if (sc)
return sc;
// recheck the pointer
sc = ScCheckPointers(spSnapIn, E_UNEXPECTED);
if (sc)
return sc;
// load the contents of snapin
sc = spSnapIn->Load(this, pStream);
if (sc)
return sc;
} while (true);
return E_FAIL; // shouldl never get here.
}
static void WriteSnapInCLSID (
CSnapIn* pSnapIn,
LPCTSTR pszSection,
LPCTSTR pszKeyPrefix,
LPCTSTR pszFilename)
{
tstring strKey = _T("CLSID");
if (pszKeyPrefix != NULL)
strKey = pszKeyPrefix + strKey;
tstring strCLSID = tstringFromCLSID (pSnapIn->GetSnapInCLSID());
SafeWritePrivateProfileString (pszSection, strKey.data(), strCLSID.data(), pszFilename);
}
static void WriteSnapInName (
CSnapIn* pSnapIn,
LPCTSTR pszSection,
LPCTSTR pszKeyPrefix,
LPCTSTR pszFilename)
{
tstring strKey = _T("Name");
if (pszKeyPrefix != NULL)
strKey = pszKeyPrefix + strKey;
WTL::CString strName;
SC sc = pSnapIn->ScGetSnapInName (strName);
if (sc.IsError() || strName.IsEmpty())
strName = _T("<unknown>");
SafeWritePrivateProfileString (pszSection, strKey.data(), strName, pszFilename);
}
static void AppendString (tstring& str, LPCTSTR pszToAppend)
{
if (!str.empty())
str += _T(", ");
str += pszToAppend;
}
static void WriteExtensionType (
DWORD dwExtensionFlags,
LPCTSTR pszSection,
LPCTSTR pszKeyPrefix,
LPCTSTR pszFilename)
{
tstring strKey = _T("Type");
if (pszKeyPrefix != NULL)
strKey = pszKeyPrefix + strKey;
struct {
CExtSI::EXTSI_FLAGS flag;
LPCTSTR pszDescription;
} FlagMap[] = {
{ CExtSI::EXT_TYPE_REQUIRED, _T("required") },
{ CExtSI::EXT_TYPE_STATIC, _T("static") },
{ CExtSI::EXT_TYPE_DYNAMIC, _T("dynamic") },
{ CExtSI::EXT_TYPE_NAMESPACE, _T("namespace") },
{ CExtSI::EXT_TYPE_CONTEXTMENU, _T("context menu") },
{ CExtSI::EXT_TYPE_TOOLBAR, _T("toolbar") },
{ CExtSI::EXT_TYPE_PROPERTYSHEET, _T("property sheet") },
{ CExtSI::EXT_TYPE_TASK, _T("taskpad") },
{ CExtSI::EXT_TYPE_VIEW, _T("view") },
};
tstring strType;
for (int i = 0; i < countof (FlagMap); i++)
{
if (dwExtensionFlags & FlagMap[i].flag)
AppendString (strType, FlagMap[i].pszDescription);
}
SafeWritePrivateProfileString (pszSection, strKey.data(), strType.data(), pszFilename);
}
HRESULT CSnapInsCache::Dump (LPCTSTR pszDumpFile)
{
DECLARE_SC(sc, TEXT("CSnapInsCache::Dump"));
static const TCHAR szStandaloneSection[] = _T("Standalone Snap-ins");
static const TCHAR szStandaloneCountKey[] = _T("StandaloneCount");
int cStandalones = 0;
try
{
/*
* no stand-alone snap-ins found yet (write it now so it's at the
* beginning of the section, for human readability)
*/
SafeWritePrivateProfileString (szStandaloneSection, szStandaloneCountKey, _T("0"), pszDumpFile);
/*
* dump each snap-in to the file
*/
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
CSnapIn* pSnapIn = it->second;
sc = ScCheckPointers(pSnapIn);
if(sc)
{
sc.TraceAndClear();
continue;
}
pSnapIn->Dump (pszDumpFile, this);
/*
* if this is a stand-alone, update the "Standalone Snap-ins" section
*/
if (pSnapIn->IsStandAlone())
{
TCHAR szKeyPrefix[20];
sc = StringCchPrintf(szKeyPrefix, countof(szKeyPrefix), _T("Standalone%d."), ++cStandalones);
if(sc)
return sc.ToHr();
WriteSnapInCLSID (pSnapIn, szStandaloneSection, szKeyPrefix, pszDumpFile);
WriteSnapInName (pSnapIn, szStandaloneSection, szKeyPrefix, pszDumpFile);
}
}
/*
* if we found stand-alones, update the count
*/
if (cStandalones > 0)
{
TCHAR szStandaloneCount[6];
_itot (cStandalones, szStandaloneCount, 10);
SafeWritePrivateProfileString (szStandaloneSection, szStandaloneCountKey,
szStandaloneCount, pszDumpFile);
}
}
catch (_com_error& err)
{
sc = err.Error();
ASSERT (false && "Caught _com_error");
}
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
* CSnapInsCache::ScCheckSnapinAvailability
*
*
*--------------------------------------------------------------------------*/
SC CSnapInsCache::ScCheckSnapinAvailability (CAvailableSnapinInfo& asi)
{
DECLARE_SC (sc, _T("CSnapInsCache::ScCheckSnapinAvailability"));
#ifdef MMC_WIN64
asi.m_cTotalSnapins = m_snapins.size();
asi.m_vAvailableSnapins.clear();
/*
* destroy any existing imagelist
*/
if (asi.m_himl)
ImageList_Destroy (asi.m_himl);
/*
* if we're interested in 32-bit snap-ins, make sure the registry APIs
* go to the 32-bit registry hive.
*/
const REGSAM samDesired = (asi.m_f32Bit) ? KEY_READ | REG_OPTION_OPEN_32BITKEY
: KEY_READ;
CRegKey keyClsid;
sc = ScFromWin32 (keyClsid.Open (HKEY_CLASSES_ROOT, _T("CLSID"), samDesired));
if (sc)
return (sc);
CStr strUnknownSnapinName;
VERIFY (strUnknownSnapinName.LoadString (GetStringModule(), IDS_UnknownSnapinName));
/*
* create an imagelist, tracing (but not aborting) on failure
*/
const int nImageListFolder = 0;
WTL::CImageList iml;
if (!iml.Create (IDB_FOLDER_16, 16 /*cx*/, 4 /*cGrow*/, RGB(255,0,255) /*crMask*/))
sc.FromLastError().TraceAndClear();
/*
* for each snap-in in the cache...
*/
for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
{
/*
* ...check to see if there's an HKCR\CLSID\{clsid}\InprocServer32
* entry for it. If there is, we'll assume the snap-in is "available".
*/
tstring strSnapinClsid = tstringFromCLSID (it->first);
tstring strInprocServerKey = strSnapinClsid + _T("\\InprocServer32");
CRegKey keyInprocServer;
LONG lResult = keyInprocServer.Open (keyClsid, strInprocServerKey.data(), samDesired);
bool fSnapinAvailable = (lResult == ERROR_SUCCESS);
/*
* if the snap-in's available, get it's name and put it in the
* available snap-ins collection
*/
if (fSnapinAvailable)
{
CBasicSnapinInfo bsi;
bsi.m_clsid = it->first;
CSnapIn*pSnapin = it->second;
/*
* get the snap-in's name
*/
WTL::CString strSnapinName;
if ((pSnapin != NULL) && !pSnapin->ScGetSnapInName(strSnapinName).IsError())
bsi.m_strName = strSnapinName;
else
bsi.m_strName = strUnknownSnapinName; // "<unknown>"
/*
* Get the snap-in's image from its about object
* (failures here aren't fatal and don't need to be traced).
* We'll use a generic folder icon if we can't get an image
* from the snap-in's about object.
*/
CLSID clsidAbout;
CSnapinAbout snapinAbout;
if (!iml.IsNull())
{
if (!ScGetAboutFromSnapinCLSID(bsi.m_clsid, clsidAbout).IsError() &&
snapinAbout.GetBasicInformation (clsidAbout))
{
/*
* the bitmaps returned by GetSmallImages are owned by
* the CSnapinAbout object (don't need to delete here)
*/
HBITMAP hbmSmall;
HBITMAP hbmSmallOpen; // unused here, but required for GetSmallImages
COLORREF crMask;
snapinAbout.GetSmallImages (&hbmSmall, &hbmSmallOpen, &crMask);
/*
* ImageList_AddMasked will mess up the background of
* its input bitmap, but the input bitmap won't be
* reused, so we don't need to make a copy like we
* usually do.
*/
WTL::CBitmap bmpSmall = CopyBitmap (hbmSmall);
if (!bmpSmall.IsNull())
bsi.m_nImageIndex = iml.Add (bmpSmall, crMask);
else
bsi.m_nImageIndex = nImageListFolder;
}
else
bsi.m_nImageIndex = nImageListFolder;
}
/*
* put it in the available snap-ins collection
*/
asi.m_vAvailableSnapins.push_back (bsi);
}
#ifdef DBG
if (fSnapinAvailable)
Trace (tagVerboseSnapinAnalysis64,
_T(" available: %s (image=%d)"),
asi.m_vAvailableSnapins.back().m_strName.data(),
asi.m_vAvailableSnapins.back().m_nImageIndex);
else
Trace (tagVerboseSnapinAnalysis64, _T("unavailable: %s"), strSnapinClsid.data());
#endif
}
Trace (tagSnapinAnalysis64, _T("%d-bit snap-in analysis: %d total, %d available"), asi.m_f32Bit ? 32 : 64, asi.m_cTotalSnapins, asi.m_vAvailableSnapins.size());
/*
* give the imagelist to the CAvailableSnapinInfo
*/
asi.m_himl = iml.Detach();
#else
sc = E_NOTIMPL;
#endif // !MMC_WIN64
return (sc);
}
void CSnapIn::MarkExtensionDeleted(CSnapIn* pSnapIn)
{
ASSERT(pSnapIn != NULL);
CExtSI* pExt = m_pExtSI;
while (pExt != NULL)
{
if (pExt->GetSnapIn() == pSnapIn)
{
pExt->MarkDeleted();
return;
}
pExt = pExt->Next();
}
// wasn't in the list !
ASSERT(FALSE);
}
//
// Delete all extensions marked for deletion
// Also reset any New flags
//
void CSnapIn::PurgeExtensions()
{
CExtSI* pExt = m_pExtSI;
CExtSI* pExtPrev = NULL;
// step through linked list, deleting marked nodes
while (pExt != NULL)
{
if (pExt->IsMarkedForDeletion())
{
CExtSI *pExtNext = pExt->Next();
if (pExtPrev)
pExtPrev->SetNext(pExtNext);
else
m_pExtSI = pExtNext;
// clear next link so extensions doesn't take the whole chain
// with it when it is deleted
pExt->SetNext(NULL);
delete pExt;
pExt = pExtNext;
}
else
{
pExt->SetNew(FALSE);
pExtPrev = pExt;
pExt = pExt->Next();
}
}
}
CExtSI* CSnapIn::FindExtension(const CLSID& rclsid)
{
CExtSI* pExt = m_pExtSI;
while (pExt != NULL && !IsEqualCLSID(rclsid, pExt->GetSnapIn()->GetSnapInCLSID()))
{
pExt = pExt->Next();
}
return pExt;
}
CExtSI* CSnapIn::AddExtension(CSnapIn* pSI)
{
CExtSI* pExtSI = new CExtSI(pSI);
ASSERT(pExtSI != NULL);
if ( pExtSI == NULL )
return NULL;
// insert extension in increasing GUID order
CExtSI* pExtPrev = NULL;
CExtSI* pExtTemp = m_pExtSI;
while (pExtTemp != NULL && pExtTemp->GetCLSID() < pExtSI->GetCLSID())
{
pExtPrev = pExtTemp;
pExtTemp = pExtTemp->Next();
}
if (pExtPrev == NULL)
{
pExtSI->SetNext(m_pExtSI);
m_pExtSI = pExtSI;
}
else
{
pExtSI->SetNext(pExtPrev->Next());
pExtPrev->SetNext(pExtSI);
}
// mark as new
pExtSI->SetNew();
return pExtSI;
}
HRESULT CSnapIn::Save(IStream* pStream, BOOL fClearDirty)
{
ASSERT(pStream != NULL);
if (pStream == NULL)
return E_INVALIDARG;
ULONG bytesWritten;
HRESULT hr = pStream->Write(&GetSnapInCLSID(), sizeof(CLSID), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(CLSID));
if (FAILED(hr))
return hr;
// If all extensions are enabled, then write special guid & flag and return
if (AreAllExtensionsEnabled())
{
hr = pStream->Write(&GUID_EnableAllExtensions, sizeof(GUID), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(GUID));
if (FAILED(hr))
return hr;
int iSnapInEnable = DoesSnapInEnableAll() ? 1 : 0;
hr = pStream->Write(&iSnapInEnable, sizeof(int), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(int));
return hr;
}
if (m_pExtSI)
{
hr = m_pExtSI->Save(pStream, fClearDirty);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
}
// NULL guid to terminate extensions list
hr = pStream->Write(&GUID_NULL, sizeof(GUID_NULL), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(GUID_NULL));
if (FAILED(hr))
return hr;
return S_OK;
}
HKEY CSnapIn::OpenKey (REGSAM samDesired /*=KEY_ALL_ACCESS*/) const
{
MMC_ATL::CRegKey SnapInKey;
MMC_ATL::CRegKey AllSnapInsKey;
if (AllSnapInsKey.Open (HKEY_LOCAL_MACHINE, SNAPINS_KEY, samDesired) == ERROR_SUCCESS)
{
OLECHAR szItemKey[40];
int nChars = StringFromGUID2 (m_clsidSnapIn, szItemKey, countof(szItemKey));
if (nChars == 0)
return NULL;
USES_CONVERSION;
SnapInKey.Open (AllSnapInsKey, OLE2T(szItemKey), samDesired);
}
return (SnapInKey.Detach());
}
/*+-------------------------------------------------------------------------*
*
* CSnapIn::Persist
*
* PURPOSE: Persists the CSnapIn to the specified persistor.
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapIn::Persist(CPersistor& persistor)
{
if (persistor.IsStoring())
persistor.PersistAttribute(XML_ATTR_SNAPIN_CLSID, *const_cast<GUID*>(&GetSnapInCLSID()));
BOOL bAreAllExtensionsEnabled = AreAllExtensionsEnabled();
persistor.PersistAttribute(XML_ATTR_SNAPIN_EXTN_ENABLED, CXMLBoolean(bAreAllExtensionsEnabled));
SetAllExtensionsEnabled(bAreAllExtensionsEnabled);
if(bAreAllExtensionsEnabled) // if all extensions are enabled, don't save anything else.
return;
// save the extension information if it exists
persistor.Persist(m_ExtPersistor);
}
//+-------------------------------------------------------------------
//
// Member: CSnapIn::ScGetSnapInName
//
// Synopsis: Return the name of this snapin.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSnapIn::ScGetSnapInName (WTL::CString& strSnapInName) const
{
DECLARE_SC(sc, _T("CSnapIn::ScGetSnapInName"));
sc = ScGetSnapinNameFromRegistry (m_clsidSnapIn, strSnapInName);
if (sc)
return (sc);
return (sc);
}
DWORD CSnapIn::GetSnapInModule(TCHAR* szBuffer, DWORD cchBuffer) const
{
DECLARE_SC(sc, TEXT("CSnapIn::GetSnapInModule"));
sc = ScCheckPointers(szBuffer);
if(sc)
return 0;
if(!cchBuffer)
{
sc = E_FAIL;
return 0;
}
// validate the buffer
BufferCbValidate(szBuffer, cchBuffer);
tstring strKeyName = g_szCLSID;
strKeyName += _T("\\");
strKeyName += tstringFromCLSID (m_clsidSnapIn);
strKeyName += _T("\\");
strKeyName += _T("InprocServer32");
*szBuffer = 0;
MMC_ATL::CRegKey keyServer;
if (keyServer.Open (HKEY_CLASSES_ROOT, strKeyName.data(), KEY_QUERY_VALUE) == ERROR_SUCCESS)
{
TCHAR szModule[MAX_PATH];
DWORD cchModule = countof(szModule);
if (keyServer.QueryValue (szModule, NULL, &cchModule) == ERROR_SUCCESS)
ExpandEnvironmentStrings (szModule, szBuffer, cchBuffer);
}
return (lstrlen (szBuffer));
}
HRESULT CSnapIn::Load(CSnapInsCache* pCache, IStream* pStream, CExtSI*& pExtSI)
{
ASSERT(pStream != NULL);
if (pStream == NULL)
return E_INVALIDARG;
// Clear default enabling of all extensions. The true state will be
// determined from the persisted data.
SetAllExtensionsEnabled(FALSE);
// Read CLSID
CLSID clsid;
ULONG bytesRead;
HRESULT hr = pStream->Read(&clsid, sizeof(clsid), &bytesRead);
ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(clsid));
if (FAILED(hr))
return hr;
if (bytesRead != sizeof(clsid))
return hr = E_FAIL;
if (clsid == GUID_NULL)
return S_OK;
// If special "Enable all" guid encountered, read flag to see if
// snapin or user enabled all and return
if (clsid == GUID_EnableAllExtensions)
{
SetAllExtensionsEnabled();
int iSnapInEnable;
hr = pStream->Read(&iSnapInEnable, sizeof(int), &bytesRead);
ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(int));
if (iSnapInEnable)
SetSnapInEnablesAll();
return S_OK;
}
// Read extension type flags
DWORD dwExtTypes;
hr = pStream->Read(&dwExtTypes, sizeof(DWORD), &bytesRead);
ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(DWORD));
if (FAILED(hr))
return hr;
if (pExtSI != NULL)
{
hr = Load(pCache, pStream, pExtSI);
ASSERT(hr == S_OK);
return hr == S_OK ? S_OK : E_FAIL;
}
CSnapInPtr spSnapIn;
SC sc = pCache->ScGetSnapIn(clsid, &spSnapIn);
if (sc)
return sc.ToHr();
ASSERT(spSnapIn != NULL);
pExtSI = new CExtSI(spSnapIn);
ASSERT(pExtSI != NULL);
if ( pExtSI == NULL )
return E_OUTOFMEMORY;
pExtSI->SetExtensionTypes(dwExtTypes);
hr = Load(pCache, pStream, pExtSI->Next());
ASSERT(hr == S_OK);
return hr == S_OK ? S_OK : E_FAIL;
}
HRESULT CSnapIn::Load(CSnapInsCache* pCache, IStream* pStream)
{
HRESULT hr = Load(pCache, pStream, m_pExtSI);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
return S_OK;
}
bool CSnapIn::IsStandAlone () const
{
MMC_ATL::CRegKey StandAloneKey;
MMC_ATL::CRegKey ItemKey;
ItemKey.Attach (OpenKey (KEY_READ));
if (ItemKey.m_hKey != NULL)
StandAloneKey.Open (ItemKey, g_szStandAlone, KEY_READ);
return (StandAloneKey.m_hKey != NULL);
}
/*+-------------------------------------------------------------------------*
* CSnapIn::Dump
*
* Dumps the information about this snap-in to a INI-style file. The
* format is:
*
* [{clsid}]
* Name=<NameString from registry>
* Module=<dll name>
* Version=<dll version number>
* Standalone=<1 if standalone, 0 if extension>
* ExtensionCount=<number of extensions>
* Extension1={clsid} (extension name)
* ...
* ExtensionN={clsid} (extension name)
*--------------------------------------------------------------------------*/
HRESULT CSnapIn::Dump (LPCTSTR pszDumpFile, CSnapInsCache* pCache)
{
DECLARE_SC(sc, TEXT("CSnapIn::Dump"));
/*
* use the CLSID as the section name
*/
const tstring strSection = tstringFromCLSID (m_clsidSnapIn);
/*
* write Name
*/
WriteSnapInName (this, strSection.data(), NULL, pszDumpFile);
/*
* write Module
*/
TCHAR szModule[MAX_PATH];
bool fFoundModule = (GetSnapInModule (szModule, countof (szModule)) != 0);
if (!fFoundModule)
{
sc = StringCchCopy (szModule, countof(szModule), _T("<unknown>"));
if(sc)
return sc.ToHr();
}
SafeWritePrivateProfileString (strSection.data(), _T("Module"), szModule, pszDumpFile);
/*
* write Version
*/
TCHAR szVersion[64];
if (!fFoundModule || !GetModuleVersion (szModule, szVersion, countof(szVersion)))
{
sc = StringCchCopy(szVersion, countof(szVersion), _T("<unknown>"));
if(sc)
return sc.ToHr();
}
SafeWritePrivateProfileString (strSection.data(), _T("Version"), szVersion, pszDumpFile);
/*
* write Standalone
*/
SafeWritePrivateProfileString (strSection.data(), _T("Standalone"),
IsStandAlone() ? _T("1") : _T("0"),
pszDumpFile);
/*
* make sure the extension chain has been built
*/
if (AreAllExtensionsEnabled())
{
/*
* Calling LoadRequiredExtensions with SNAPIN_SNAPIN_ENABLES_ALL set
* will result in SNAPIN_ENABLE_ALL_EXTS being cleared, which we don't
* want (rswaney).
*
* This happens because we haven't created the snap-in, so we can't
* pass an IComponentData from which LoadRequiredExtensions can QI
* for IRequiredExtensions. LoadRequiredExtensions uses
* IRequiredExtensions to determine whether SNAPIN_ENABLE_ALL_EXTS
* should be cleared or set. Since there's no IRequiredExtensions,
* SNAPIN_ENABLE_ALL_EXTS would be cleared.
*/
SetSnapInEnablesAll (false);
LoadRequiredExtensions (this, NULL, pCache);
}
/*
* write ExtensionCount
*/
TCHAR szExtCount[8];
CExtSI* pExt;
int cExtensions = 0;
// count the extensions
for (pExt = m_pExtSI; pExt != NULL; pExt = pExt->Next())
cExtensions++;
_itot (cExtensions, szExtCount, 10);
SafeWritePrivateProfileString (strSection.data(), _T("ExtensionCount"), szExtCount, pszDumpFile);
/*
* build up a cache of the extensions for this snap-in
*/
CExtensionsCache ExtCache;
MMCGetExtensionsForSnapIn (m_clsidSnapIn, ExtCache);
/*
* write extensions
*/
int i;
for (i = 0, pExt = m_pExtSI; i < cExtensions; i++, pExt = pExt->Next())
{
TCHAR szKeyPrefix[20];
sc = StringCchPrintf (szKeyPrefix, countof(szKeyPrefix), _T("Extension%d."), i+1);
if(sc)
return sc.ToHr();
DWORD dwExtFlags = ExtCache[pExt->GetSnapIn()->m_clsidSnapIn];
WriteSnapInCLSID (pExt->GetSnapIn(), strSection.data(), szKeyPrefix, pszDumpFile);
WriteSnapInName (pExt->GetSnapIn(), strSection.data(), szKeyPrefix, pszDumpFile);
WriteExtensionType (dwExtFlags, strSection.data(), szKeyPrefix, pszDumpFile);
}
return (S_OK);
}
HRESULT CExtSI::Save(IStream* pStream, BOOL fClearDirty)
{
ASSERT(pStream != NULL);
if (pStream == NULL)
return E_INVALIDARG;
// Save extension CLSID
ULONG bytesWritten;
HRESULT hr = pStream->Write(&GetCLSID(), sizeof(CLSID), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(CLSID));
if (FAILED(hr))
return hr;
// Save extension types
DWORD dwExtTypes = m_dwFlags & EXT_TYPES_MASK;
hr = pStream->Write(&dwExtTypes, sizeof(DWORD), &bytesWritten);
ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(DWORD));
if (FAILED(hr))
return hr;
if (m_pNext == NULL)
return S_OK;
hr = m_pNext->Save(pStream, fClearDirty);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
return S_OK;
}
void CExtSI::Persist(CPersistor& persistor)
{
// create an "Extension" object beneath the "Extensions" object.
CPersistor persistorExtension(persistor, XML_TAG_SNAPIN_EXTENSION);
persistorExtension.PersistAttribute(XML_ATTR_SNAPIN_CLSID, *const_cast<GUID*>(&GetCLSID()));
}
/*+-------------------------------------------------------------------------*
*
* CExtSI::PersistNew
*
* PURPOSE: called to create and persist new extension entry
*
* PARAMETERS:
* CPersistor& persistor :
* CSnapIn& snapParent : parent to whom the extension belongs
* CSnapInsCache& snapCache : cache to put new (extension) snapin to
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CExtSI::PersistNew(CPersistor &persistor, CSnapIn& snapParent, CSnapInsCache& snapCache)
{
DECLARE_SC(sc, TEXT("CExtSI::PersistNew"));
CLSID clsid;
CPersistor persistorExtension(persistor, XML_TAG_SNAPIN_EXTENSION);
persistorExtension.PersistAttribute(XML_ATTR_SNAPIN_CLSID, clsid);
CSnapInPtr spSnapIn;
sc = snapCache.ScGetSnapIn(clsid, &spSnapIn);
if (sc)
sc.Throw();
// create new extension entry
CExtSI *pExtSI = snapParent.AddExtension(spSnapIn);
sc = ScCheckPointers(pExtSI,E_FAIL);
if (sc)
sc.Throw();
// upload new extension entry info
pExtSI->Persist(persistor);
}
const CLSID& CExtSI::GetCLSID()
{
ASSERT(m_pSnapIn != NULL);
return m_pSnapIn ? m_pSnapIn->GetSnapInCLSID() : GUID_NULL;
}
/*+-------------------------------------------------------------------------*
*
* CSnapIn::PersistLoad
*
* PURPOSE: provided instead Persist to maintain reference to cache,
* required for registering new extensions during loading
*
* PARAMETERS:
* CPersistor& persistor :
* CSnapInsCache* pCache : cache to put new (extension) snapin to
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapIn::PersistLoad(CPersistor& persistor,CSnapInsCache* pCache)
{
m_ExtPersistor.SetCache(pCache);
persistor.Persist(*this);
m_ExtPersistor.SetCache(NULL);
}
/*+-------------------------------------------------------------------------*
*
* CSnapIn::CExtPersistor::Persist
*
* PURPOSE: persists collection of extensions for snapin
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapIn::CExtPersistor::Persist(CPersistor& persistor)
{
if (persistor.IsStoring())
{
CExtSI* pExt = GetParent().GetExtensionSnapIn();
while (pExt)
{
pExt->Persist(persistor);
pExt = pExt->Next();
}
}
else
{
XMLListCollectionBase::Persist(persistor);
}
}
/*+-------------------------------------------------------------------------*
*
* CSnapIn::CExtPersistor::OnNewElement
*
* PURPOSE: called for each new entry read from XML doc.
*
* PARAMETERS:
* CPersistor& persistor :
*
* RETURNS:
* void
*
*+-------------------------------------------------------------------------*/
void CSnapIn::CExtPersistor::OnNewElement(CPersistor& persistor)
{
DECLARE_SC(sc, TEXT("CSnapIn::CExtPersistor::OnNewElement"));
sc = (persistor.IsLoading() && m_pCache != NULL) ? S_OK : E_FAIL;
if (sc)
sc.Throw();
CExtSI::PersistNew(persistor, m_Parent, *m_pCache);
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScDestroyExtensionList
*
* PURPOSE: destroys the list of extensions. used to do preliminary snapin cleanup
* to avoid circular references held by the extension sanpin
* locking the objects in the memory.
*
* PARAMETERS:
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScDestroyExtensionList()
{
DECLARE_SC(sc, TEXT("CSnapIn::ScDestroyExtensionList"));
// check if we have extensions
if ( m_pExtSI != NULL )
{
// assign to auto variable
// ( 'this' may not be valid if the only reference is from extension )
CExtSI *pExtension = m_pExtSI;
// update member pointer
m_pExtSI = NULL;
delete pExtension;
// delete the extension (it will delete the next and so on)
}
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScTempState_ResetReferenceCalculationData
*
* PURPOSE: resets external reference calculation data
* Used as the first step for external reference calculation process
*
* PARAMETERS:
*
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScTempState_ResetReferenceCalculationData( )
{
DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_ResetReferenceCalculationData"));
m_dwTempState_InternalRef = 0;
m_bTempState_HasStrongRef = 0;
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScTempState_UpdateInternalReferenceCounts
*
* PURPOSE: Informs snapin's extensions about the references kept to them
* Having this information extension snapin can know if it is
* referenced externally
*
* PARAMETERS:
*
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScTempState_UpdateInternalReferenceCounts( )
{
DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_UpdateInternalReferenceCounts"));
for ( CExtSI* pExtension = m_pExtSI; pExtension; pExtension = pExtension->Next() )
{
CSnapIn *pExtensionSnapin = pExtension->GetSnapIn();
sc = ScCheckPointers( pExtensionSnapin, E_UNEXPECTED );
if (sc)
return sc;
pExtensionSnapin->m_dwTempState_InternalRef++;
}
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScTempState_SetHasStrongReference
*
* PURPOSE: Marks itself as having external strong references (external to snapin cache)
* Marks own extensions as well.
*
* PARAMETERS:
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScTempState_SetHasStrongReference()
{
DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_SetHasStrongReference"));
// do nothing if already marked (else we'll have the infinite loop)
if ( m_bTempState_HasStrongRef )
return sc;
m_bTempState_HasStrongRef = true;
// recurse to all extensions (they inherit the strong reference too)
for ( CExtSI* pExtension = m_pExtSI; pExtension; pExtension = pExtension->Next() )
{
CSnapIn *pExtensionSnapin = pExtension->GetSnapIn();
sc = ScCheckPointers( pExtensionSnapin, E_UNEXPECTED );
if (sc)
return sc;
sc = pExtensionSnapin->ScTempState_SetHasStrongReference();
if (sc)
return sc;
}
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScTempState_MarkIfExternallyReferenced
*
* PURPOSE: Used as an intermediate step calculating external references
* compares internal references to total references.
* If has external references, marks itself as 'Externally referenced'
*
* PARAMETERS:
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScTempState_MarkIfExternallyReferenced()
{
DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_MarkIfExternallyReferenced"));
DWORD dwStrongRef = m_dwRef - m_dwTempState_InternalRef - 1/*chache reference*/;
if ( dwStrongRef > 0 )
{
// now mark itself and the extensions as having strong reference
sc = ScTempState_SetHasStrongReference();
if (sc)
return sc;
}
return sc;
}
/***************************************************************************\
*
* METHOD: CSnapIn::ScTempState_IsExternallyReferenced
*
* PURPOSE: Returns the cached reference status claculated by preceding
* call to CSnapInsCache::ScMarkExternallyReferencedSnapins.
*
* PARAMETERS:
* bool& bReferenced [out] - true if snapin has external (to snapin cache) strong references
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
SC CSnapIn::ScTempState_IsExternallyReferenced( bool& bReferenced ) const
{
DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_IsExternallyReferenced"));
bReferenced = m_bTempState_HasStrongRef;
return sc;
}