//____________________________________________________________________________ // // 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) { 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)) { wsprintf (pszBuffer, _T("%d.%d.%d.%d"), HIWORD (pffi->dwFileVersionMS), LOWORD (pffi->dwFileVersionMS), HIWORD (pffi->dwFileVersionLS), LOWORD (pffi->dwFileVersionLS)); } 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 *pSnapin = NULL; sc = CComObject::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(""); 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) { static const TCHAR szStandaloneSection[] = _T("Standalone Snap-ins"); static const TCHAR szStandaloneCountKey[] = _T("StandaloneCount"); HRESULT hr = S_OK; 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; ASSERT(pSnapIn != NULL); if (pSnapIn == NULL) continue; pSnapIn->Dump (pszDumpFile, this); /* * if this is a stand-alone, update the "Standalone Snap-ins" section */ if (pSnapIn->IsStandAlone()) { TCHAR szKeyPrefix[16]; wsprintf (szKeyPrefix, _T("Standalone%d."), ++cStandalones); 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) { hr = err.Error(); ASSERT (false && "Caught _com_error"); } return (hr); } /*+-------------------------------------------------------------------------* * 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; // "" /* * 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(&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* pBuf, DWORD dwBufLen) const { ASSERT(pBuf != NULL && dwBufLen != NULL); tstring strKeyName = g_szCLSID; strKeyName += _T("\\"); strKeyName += tstringFromCLSID (m_clsidSnapIn); strKeyName += _T("\\"); strKeyName += _T("InprocServer32"); *pBuf = 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, pBuf, dwBufLen); } return (lstrlen (pBuf)); } 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= * Module= * Version= * Standalone=<1 if standalone, 0 if extension> * ExtensionCount= * Extension1={clsid} (extension name) * ... * ExtensionN={clsid} (extension name) *--------------------------------------------------------------------------*/ HRESULT CSnapIn::Dump (LPCTSTR pszDumpFile, CSnapInsCache* pCache) { /* * 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) lstrcpy (szModule, _T("")); SafeWritePrivateProfileString (strSection.data(), _T("Module"), szModule, pszDumpFile); /* * write Version */ TCHAR szVersion[64]; if (!fFoundModule || !GetModuleVersion (szModule, szVersion)) lstrcpy (szVersion, _T("")); 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]; wsprintf (szKeyPrefix, _T("Extension%d."), i+1); 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(&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; }