Source code of Windows XP (NT5)
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.

1901 lines
51 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1999
  5. //
  6. // File: SnapIn.cpp
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 9/11/1996 RaviR Created
  15. //
  16. //____________________________________________________________________________
  17. #include "stdafx.h"
  18. #include "util.h"
  19. #include "NodeMgr.h"
  20. #include "regutil.h"
  21. #include "regkeyex.h"
  22. #include "tstring.h"
  23. #include "about.h"
  24. #include "bitmap.h"
  25. #ifdef _DEBUG
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. /*
  30. * define our own Win64 symbol to make it easy to include 64-bit only
  31. * code in the 32-bit build, so we can exercise some code on 32-bit Windows
  32. * where the debuggers are better
  33. */
  34. #ifdef _WIN64
  35. #define MMC_WIN64
  36. #endif
  37. #ifdef MMC_WIN64
  38. #include "wow64reg.h" // for REG_OPTION_OPEN_32BITKEY
  39. #endif
  40. #ifdef DBG
  41. #ifdef MMC_WIN64
  42. CTraceTag tagSnapinAnalysis64 (_T("64/32-bit interop"), _T("Snap-in analysis"));
  43. CTraceTag tagVerboseSnapinAnalysis64 (_T("64/32-bit interop"), _T("Snap-in analysis (verbose)"));
  44. #endif // MMC_WIN64
  45. #endif
  46. /*+-------------------------------------------------------------------------*
  47. * tstringFromCLSID
  48. *
  49. * Returns the text representation of a CLSID in a tstring.
  50. *--------------------------------------------------------------------------*/
  51. tstring tstringFromCLSID (REFCLSID clsid)
  52. {
  53. WCHAR wzCLSID[40];
  54. int nChars = StringFromGUID2 (clsid, wzCLSID, countof(wzCLSID));
  55. if (nChars == 0)
  56. return tstring();
  57. USES_CONVERSION;
  58. return (W2T (wzCLSID));
  59. }
  60. /*+-------------------------------------------------------------------------*
  61. * GetModuleVersion
  62. *
  63. * Reads the version resource in a module and returns the version string.
  64. *--------------------------------------------------------------------------*/
  65. DWORD GetModuleVersion (LPCTSTR pszModule, LPTSTR pszBuffer)
  66. {
  67. static bool fAttemptedVersionDllLoad = false;
  68. static DWORD (APIENTRY* pfnGetFileVersionInfoSize)(LPCTSTR, LPDWORD) = NULL;
  69. static BOOL (APIENTRY* pfnGetFileVersionInfo)(LPCTSTR, DWORD, DWORD, LPVOID) = NULL;
  70. static BOOL (APIENTRY* pfnVerQueryValue)(LPBYTE, LPCTSTR, LPVOID*, PUINT) = NULL;
  71. if (!fAttemptedVersionDllLoad)
  72. {
  73. /*
  74. * only try once
  75. */
  76. fAttemptedVersionDllLoad = true;
  77. HINSTANCE hinst = LoadLibrary (_T("version.dll"));
  78. if (hinst != NULL)
  79. {
  80. #ifdef UNICODE
  81. (FARPROC&)pfnGetFileVersionInfoSize = GetProcAddress (hinst, "GetFileVersionInfoSizeW");
  82. (FARPROC&)pfnGetFileVersionInfo = GetProcAddress (hinst, "GetFileVersionInfoW");
  83. (FARPROC&)pfnVerQueryValue = GetProcAddress (hinst, "VerQueryValueW");
  84. #else
  85. (FARPROC&)pfnGetFileVersionInfoSize = GetProcAddress (hinst, "GetFileVersionInfoSizeA");
  86. (FARPROC&)pfnGetFileVersionInfo = GetProcAddress (hinst, "GetFileVersionInfoA");
  87. (FARPROC&)pfnVerQueryValue = GetProcAddress (hinst, "VerQueryValueA");
  88. #endif
  89. }
  90. }
  91. *pszBuffer = 0;
  92. if (pfnGetFileVersionInfoSize != NULL)
  93. {
  94. ASSERT (pfnGetFileVersionInfo != NULL);
  95. ASSERT (pfnVerQueryValue != NULL);
  96. ULONG lUnused;
  97. DWORD cbVerInfo = pfnGetFileVersionInfoSize (pszModule, &lUnused);
  98. if (cbVerInfo > 0)
  99. {
  100. LPBYTE pbVerInfo = new BYTE[cbVerInfo];
  101. VS_FIXEDFILEINFO* pffi;
  102. if (pfnGetFileVersionInfo != NULL && pfnVerQueryValue != NULL &&
  103. pfnGetFileVersionInfo (pszModule, NULL, cbVerInfo, pbVerInfo) &&
  104. pfnVerQueryValue (pbVerInfo, _T("\\"), (void**) &pffi, (UINT*)&lUnused))
  105. {
  106. wsprintf (pszBuffer, _T("%d.%d.%d.%d"),
  107. HIWORD (pffi->dwFileVersionMS),
  108. LOWORD (pffi->dwFileVersionMS),
  109. HIWORD (pffi->dwFileVersionLS),
  110. LOWORD (pffi->dwFileVersionLS));
  111. }
  112. delete[] pbVerInfo;
  113. }
  114. }
  115. return (lstrlen (pszBuffer));
  116. }
  117. /*+-------------------------------------------------------------------------*
  118. * SafeWriteProfileString
  119. *
  120. *
  121. *--------------------------------------------------------------------------*/
  122. inline void SafeWritePrivateProfileString (
  123. LPCTSTR pszSection,
  124. LPCTSTR pszKey,
  125. LPCTSTR psz,
  126. LPCTSTR pszFile)
  127. {
  128. if (!WritePrivateProfileString (pszSection, pszKey, psz, pszFile))
  129. THROW_ON_FAIL (HRESULT_FROM_WIN32 (GetLastError()));
  130. }
  131. //____________________________________________________________________________
  132. //
  133. // Member: CSnapIn::CSnapIn, Constructor
  134. //
  135. // History: 9/19/1996 RaviR Created
  136. //____________________________________________________________________________
  137. //
  138. // {E6DFFF74-6FE7-11d0-B509-00C04FD9080A}
  139. const GUID IID_CSnapIn =
  140. { 0xe6dfff74, 0x6fe7, 0x11d0, { 0xb5, 0x9, 0x0, 0xc0, 0x4f, 0xd9, 0x8, 0xa } };
  141. // {7A85B79C-BDED-11d1-A4FA-00C04FB6DD2C}
  142. static const GUID GUID_EnableAllExtensions =
  143. { 0x7a85b79c, 0xbded, 0x11d1, { 0xa4, 0xfa, 0x0, 0xc0, 0x4f, 0xb6, 0xdd, 0x2c } };
  144. DEBUG_DECLARE_INSTANCE_COUNTER(CSnapIn);
  145. CSnapIn::CSnapIn()
  146. :m_pExtSI(NULL), m_dwFlags(SNAPIN_ENABLE_ALL_EXTS), m_ExtPersistor(*this)
  147. {
  148. TRACE_CONSTRUCTOR(CSnapIn);
  149. #ifdef DBG
  150. dbg_cRef = 0;
  151. #endif
  152. DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapIn);
  153. }
  154. CSnapIn::~CSnapIn()
  155. {
  156. DECLARE_SC(sc, TEXT("CSnapIn::~CSnapIn"));
  157. Dbg(DEB_USER1, _T("CSnapIn::~CSnapIn\n"));
  158. sc = ScDestroyExtensionList();
  159. if (sc)
  160. {
  161. }
  162. #ifdef DBG
  163. ASSERT(dbg_cRef <= 0);
  164. #endif
  165. DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapIn);
  166. }
  167. DEBUG_DECLARE_INSTANCE_COUNTER(CExtSI);
  168. CExtSI::CExtSI(CSnapIn* pSnapIn)
  169. : m_pSnapIn(pSnapIn), m_pNext(NULL), m_dwFlags(0)
  170. {
  171. ASSERT(pSnapIn != NULL);
  172. m_pSnapIn->AddRef();
  173. DEBUG_INCREMENT_INSTANCE_COUNTER(CExtSI);
  174. }
  175. CExtSI::~CExtSI(void)
  176. {
  177. SAFE_RELEASE(m_pSnapIn);
  178. delete m_pNext;
  179. DEBUG_DECREMENT_INSTANCE_COUNTER(CExtSI);
  180. }
  181. CSnapInsCache::CSnapInsCache()
  182. : m_bIsDirty(FALSE), m_bUpdateHelpColl(false)
  183. {
  184. }
  185. CSnapInsCache::~CSnapInsCache()
  186. {
  187. DECLARE_SC(sc, TEXT("CSnapInsCache::~CSnapInsCache"));
  188. // destruction will remove all snapins, but ask them to release extensions first,
  189. // this will break all circular references (else such snapins objects will be leaked).
  190. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  191. {
  192. // get pointer to the snapin
  193. CSnapIn* pSnapIn = it->second;
  194. sc = ScCheckPointers( pSnapIn, E_UNEXPECTED );
  195. if (sc)
  196. {
  197. sc.TraceAndClear();
  198. continue;
  199. }
  200. // ask snapin to destroy extension list
  201. sc = pSnapIn->ScDestroyExtensionList();
  202. if (sc)
  203. sc.TraceAndClear();
  204. }
  205. }
  206. /***************************************************************************\
  207. *
  208. * METHOD: CSnapInsCache::ScIsDirty
  209. *
  210. * PURPOSE: returns dirty status of Snapin Cache
  211. *
  212. * PARAMETERS:
  213. *
  214. * RETURNS:
  215. * SC - result code [SC(S_OK) - if dirty, SC(S_FALSE) else]
  216. *
  217. \***************************************************************************/
  218. SC CSnapInsCache::ScIsDirty()
  219. {
  220. DECLARE_SC(sc, TEXT("CSnapInsCache::ScIsDirty"));
  221. TraceDirtyFlag(TEXT("CSnapInsCache"), m_bIsDirty);
  222. sc = m_bIsDirty ? SC(S_OK) : SC(S_FALSE);
  223. return sc;
  224. }
  225. void CSnapInsCache::SetDirty(BOOL bIsDirty)
  226. {
  227. m_bIsDirty = bIsDirty;
  228. }
  229. /***************************************************************************\
  230. *
  231. * METHOD: CSnapInsCache::Purge
  232. *
  233. * PURPOSE: Cleanup Snapin Cache by usage information
  234. * Uses sphisticated algorithm to find out which snapins are not used
  235. * see ScMarkExternallyReferencedSnapins() for description
  236. * removes snapins which are not referenced externally
  237. *
  238. * PARAMETERS:
  239. * BOOL bExtensionsOnly
  240. *
  241. * RETURNS:
  242. * SC - result code
  243. *
  244. \***************************************************************************/
  245. void CSnapInsCache::Purge(BOOL bExtensionsOnly)
  246. {
  247. DECLARE_SC(sc, TEXT("CSnapInsCache::Purge"));
  248. int iSnapIn;
  249. // Delete all extensions marked as deleted
  250. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  251. {
  252. CSnapIn* pSnapIn = it->second;
  253. ASSERT(pSnapIn != NULL);
  254. if (it->second != NULL)
  255. it->second->PurgeExtensions();
  256. }
  257. if (bExtensionsOnly)
  258. return;
  259. // Delete all snapins that have no external references
  260. sc = ScMarkExternallyReferencedSnapins();
  261. if (sc)
  262. return; // error occured - do not remove anything
  263. // remove not referenced
  264. for ( it = m_snapins.begin(); it != m_snapins.end(); )
  265. {
  266. CSnapIn *pSnapin = it->second;
  267. sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
  268. if (sc)
  269. return;
  270. bool bExternallyReferenced;
  271. sc = pSnapin->ScTempState_IsExternallyReferenced( bExternallyReferenced );
  272. if (sc)
  273. return;
  274. if ( !bExternallyReferenced )
  275. {
  276. // destory extension list - it will break all circular references if such exist
  277. // (note- extension list is not needed anymore - snapin is not used anyway)
  278. sc = pSnapin->ScDestroyExtensionList();
  279. if (sc)
  280. return;
  281. // remove snapin from the cache;
  282. // in combination with the call above this will delete the object.
  283. it = m_snapins.erase( it );
  284. }
  285. else
  286. {
  287. ++it; // go to the next snapin
  288. }
  289. }
  290. }
  291. /***************************************************************************\
  292. *
  293. * METHOD: CSnapInsCache::ScMarkExternallyReferencedSnapins
  294. *
  295. * PURPOSE: Marks all snapins in cache according to presence of external references
  296. * This is done by following algorithm:
  297. * 1) For each snapin in the cache, all extensions have a temporary reference
  298. * count incremented. Thus, at the end of this step, each snapin's temp
  299. * ref count is equal to the number of snapins it extends.
  300. 2) Each snapin compares the temp reference count to the total number of
  301. references to it, taking into account the fact that the snapin cache
  302. itself holds a reference to each snapin. If the total references exceed
  303. the temp references, this indicates that the snapin has one or more
  304. external references to it.
  305. * Such a snapin is marked as "Externally referenced" as well as all its
  306. * extensions.
  307. *
  308. * At the end of the process each snapin has a boolean flag indicating if
  309. * the snapin is externally referenced. This flag is used in subsequential cache cleanup,
  310. * or help topic building operation.
  311. *
  312. * PARAMETERS:
  313. *
  314. * RETURNS:
  315. * SC - result code
  316. *
  317. \***************************************************************************/
  318. SC CSnapInsCache::ScMarkExternallyReferencedSnapins()
  319. {
  320. DECLARE_SC(sc, TEXT("CSnapInsCache::ScMarkExternallyReferencedSnapins"));
  321. // 1. reset the reference calculation data
  322. for ( map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it )
  323. {
  324. CSnapIn *pSnapin = it->second;
  325. sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
  326. if (sc)
  327. return sc;
  328. sc = pSnapin->ScTempState_ResetReferenceCalculationData();
  329. if (sc)
  330. return sc;
  331. }
  332. // 2. update internal reference counts
  333. for ( it = m_snapins.begin(); it != m_snapins.end(); ++it )
  334. {
  335. CSnapIn *pSnapin = it->second;
  336. sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
  337. if (sc)
  338. return sc;
  339. sc = pSnapin->ScTempState_UpdateInternalReferenceCounts();
  340. if (sc)
  341. return sc;
  342. }
  343. // now the snapins which have more references than internal ones do clearly
  344. // have direct external references
  345. // we can mark them and their extensions as "referenced"
  346. // 3. mark snapins with external references
  347. // Note: this step must occur after step 2 completes for ALL snapins.
  348. for ( it = m_snapins.begin(); it != m_snapins.end(); ++it )
  349. {
  350. CSnapIn *pSnapin = it->second;
  351. sc = ScCheckPointers( pSnapin, E_UNEXPECTED );
  352. if (sc)
  353. return sc;
  354. sc = pSnapin->ScTempState_MarkIfExternallyReferenced();
  355. if (sc)
  356. return sc;
  357. }
  358. return sc;
  359. }
  360. /***************************************************************************\
  361. *
  362. * METHOD: CSnapInsCache::ScGetSnapIn
  363. *
  364. * PURPOSE: either finds the snapin in cache , either creates the new one
  365. *
  366. * PARAMETERS:
  367. * REFCLSID rclsid - class id of snapin
  368. * CSnapIn** ppSnapIn - result
  369. *
  370. * RETURNS:
  371. * SC - result code
  372. *
  373. \***************************************************************************/
  374. SC CSnapInsCache::ScGetSnapIn(REFCLSID rclsid, CSnapIn** ppSnapIn)
  375. {
  376. DECLARE_SC(sc, TEXT("CSnapInsCache::ScGetSnapIn"));
  377. // first - parameter check
  378. sc = ScCheckPointers(ppSnapIn);
  379. if (sc)
  380. return sc;
  381. // second - initialization
  382. *ppSnapIn = NULL;
  383. //
  384. // See if it already exists.
  385. //
  386. sc = ScFindSnapIn(rclsid, ppSnapIn);
  387. if (!sc.IsError())
  388. return sc; // jus return OK if we have it
  389. //
  390. // Create a new one & cache it
  391. //
  392. try
  393. {
  394. // Allocate the object
  395. CComObject<CSnapIn> *pSnapin = NULL;
  396. sc = CComObject<CSnapIn>::CreateInstance(&pSnapin);
  397. if (sc)
  398. return sc;
  399. // be sure we didn't get the NULL
  400. sc = ScCheckPointers(pSnapin, E_UNEXPECTED);
  401. if (sc)
  402. return sc;
  403. CSnapInPtr spSnapin = pSnapin;
  404. // Copy the object impl clsid
  405. spSnapin->SetSnapInCLSID(rclsid);
  406. //
  407. // Cache the object.
  408. //
  409. // note - this insertion also AddRef's the pointer
  410. m_snapins[rclsid] = spSnapin;
  411. *ppSnapIn = spSnapin.Detach(); // transfer reference to caller
  412. }
  413. catch( std::bad_alloc )
  414. {
  415. sc = E_OUTOFMEMORY;
  416. }
  417. return sc;
  418. }
  419. #ifdef DBG
  420. void CSnapInsCache::DebugDump(void)
  421. {
  422. TRACE(_T("===========Dump of SnapinsCache ===============\n"));
  423. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  424. {
  425. OLECHAR strGUID[64];
  426. CSnapIn* pSnapIn = it->second;
  427. StringFromGUID2(pSnapIn->GetSnapInCLSID(), strGUID, countof(strGUID));
  428. #ifdef DBG
  429. TRACE(_T("%s: RefCnt = %d, %s\n"), strGUID, pSnapIn->m_dwRef,
  430. pSnapIn->HasNameSpaceChanged() ? _T("NameSpace changed") : _T("No change"));
  431. #endif
  432. CExtSI* pExt = pSnapIn->GetExtensionSnapIn();
  433. while (pExt != NULL)
  434. {
  435. StringFromGUID2(pExt->GetSnapIn()->GetSnapInCLSID(), strGUID, countof(strGUID));
  436. #ifdef DBG
  437. // TODO: go to registry to see the type of extension:
  438. // these flags are not updated consistently
  439. TRACE(_T(" %s: %s%s Extends(%s%s%s%s)\n"), strGUID,
  440. pExt->IsNew() ? _T("New ") : _T(""),
  441. pExt->IsMarkedForDeletion() ? _T("Deleted ") : _T(""),
  442. pExt->ExtendsNameSpace() ? _T("NameSpace ") : _T(""),
  443. pExt->ExtendsContextMenu() ? _T("Menu ") : _T(""),
  444. pExt->ExtendsToolBar() ? _T("ToolBar ") : _T(""),
  445. pExt->ExtendsPropertySheet() ? _T("Properties") : _T(""),
  446. pExt->ExtendsView() ? _T("View") : _T(""),
  447. pExt->ExtendsTask() ? _T("Task") : _T("")
  448. );
  449. #endif
  450. pExt = pExt->Next();
  451. }
  452. }
  453. }
  454. #endif // DBG
  455. /***************************************************************************\
  456. *
  457. * METHOD: CSnapInsCache::ScFindSnapIn
  458. *
  459. * PURPOSE: finds the snapin by class id and returns AddRef'ed pointer
  460. *
  461. * PARAMETERS:
  462. * REFCLSID rclsid - class id of the snapin
  463. * CSnapIn** ppSnapIn - resulting pointer
  464. *
  465. * RETURNS:
  466. * SC - result code
  467. *
  468. \***************************************************************************/
  469. SC CSnapInsCache::ScFindSnapIn(REFCLSID rclsid, CSnapIn** ppSnapIn)
  470. {
  471. DECLARE_SC(sc, TEXT("CSnapInsCache::ScFindSnapIn"));
  472. // first - parameter check
  473. sc = ScCheckPointers(ppSnapIn);
  474. if (sc)
  475. return sc;
  476. // second - initialization
  477. *ppSnapIn = NULL;
  478. // and now wee will se if we have one
  479. map_t::iterator it = m_snapins.find(rclsid);
  480. if (it == m_snapins.end())
  481. return E_FAIL; // not assigning to sc, since it's not really an error condition
  482. // be sure we do not return the NULL
  483. sc = ScCheckPointers(it->second, E_UNEXPECTED);
  484. if (sc)
  485. return sc;
  486. *ppSnapIn = it->second;
  487. (*ppSnapIn)->AddRef();
  488. return sc;
  489. }
  490. #ifdef TEMP_SNAPIN_MGRS_WORK
  491. // Get all extensions.
  492. void CSnapInsCache::GetAllExtensions(CSnapIn* pSI)
  493. {
  494. if (!pSI)
  495. return;
  496. CExtensionsCache extnsCache;
  497. HRESULT hr = MMCGetExtensionsForSnapIn(pSI->GetSnapInCLSID(), extnsCache);
  498. ASSERT(SUCCEEDED(hr));
  499. if (FAILED(hr))
  500. return;
  501. CExtensionsCacheIterator it(extnsCache);
  502. for (; it.IsEnd() == FALSE; it.Advance())
  503. {
  504. CSnapInPtr spSITemp;
  505. hr = GetSnapIn(it.GetKey(), &spSITemp);
  506. ASSERT(SUCCEEDED(hr));
  507. pSI->AddExtension(spSITemp);
  508. }
  509. }
  510. #endif // TEMP_SNAPIN_MGRS_WORK
  511. /***************************************************************************\
  512. *
  513. * METHOD: CSnapInsCache::ScSave
  514. *
  515. * PURPOSE: saves contents of Snapin Cache to IStream
  516. *
  517. * PARAMETERS:
  518. * IStream* pStream - save to this stream
  519. * BOOL bClearDirty - reset dirty flag after save
  520. *
  521. * RETURNS:
  522. * SC - result code
  523. *
  524. \***************************************************************************/
  525. SC CSnapInsCache::ScSave(IStream* pStream, BOOL bClearDirty)
  526. {
  527. DECLARE_SC(sc, TEXT("CSnapInsCache::ScSave"));
  528. // check the params
  529. sc = ScCheckPointers(pStream);
  530. if (sc)
  531. return sc;
  532. // iterate ans save all snapins
  533. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  534. {
  535. CSnapIn* pSnapIn = it->second;
  536. ASSERT(pSnapIn != NULL);
  537. if (pSnapIn != NULL)
  538. {
  539. sc = pSnapIn->Save(pStream, bClearDirty);
  540. if (sc)
  541. return sc;
  542. }
  543. }
  544. // terminating marker
  545. ULONG bytesWritten;
  546. sc = pStream->Write(&GUID_NULL, sizeof(GUID_NULL), &bytesWritten);
  547. if (sc)
  548. return sc;
  549. ASSERT(bytesWritten == sizeof(GUID_NULL));
  550. if (bClearDirty)
  551. SetDirty(FALSE);
  552. return sc;
  553. }
  554. /*+-------------------------------------------------------------------------*
  555. *
  556. * CSnapInsCache::Persist
  557. *
  558. * PURPOSE: Persists the CSnapInsCache to the specified persistor.
  559. *
  560. * PARAMETERS:
  561. * CPersistor& persistor :
  562. *
  563. * RETURNS:
  564. * void
  565. *
  566. *+-------------------------------------------------------------------------*/
  567. void CSnapInsCache::Persist(CPersistor& persistor)
  568. {
  569. if (persistor.IsStoring())
  570. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  571. {
  572. CSnapIn* pSnapIn = it->second;
  573. ASSERT(pSnapIn != NULL);
  574. if (pSnapIn != NULL)
  575. persistor.Persist(*pSnapIn);
  576. }
  577. else
  578. {
  579. XMLListCollectionBase::Persist(persistor);
  580. SetDirty(FALSE);
  581. }
  582. }
  583. /*+-------------------------------------------------------------------------*
  584. *
  585. * CSnapInsCache::OnNewElement
  586. *
  587. * PURPOSE: called for each saved instance found in XML file.
  588. * creates and uploads new snapin entry
  589. *
  590. * PARAMETERS:
  591. * CPersistor& persistor :
  592. *
  593. * RETURNS:
  594. * void
  595. *
  596. *+-------------------------------------------------------------------------*/
  597. void CSnapInsCache::OnNewElement(CPersistor& persistor)
  598. {
  599. DECLARE_SC(sc, TEXT("CSnapInsCache::OnNewElement"));
  600. ASSERT(persistor.IsLoading());
  601. CLSID clsid;
  602. CPersistor persistorSnapin(persistor, XML_TAG_SNAPIN);
  603. persistor.PersistAttribute(XML_ATTR_SNAPIN_CLSID, clsid);
  604. // create and upload snapin
  605. CSnapInPtr spSnapIn;
  606. sc = ScGetSnapIn(clsid, &spSnapIn);
  607. if (sc) // failed to creatre
  608. sc.Throw();
  609. if (spSnapIn != NULL)
  610. spSnapIn->PersistLoad(persistor,this);
  611. else // OK reported, pointer still NULL
  612. sc.Throw(E_POINTER);
  613. }
  614. /***************************************************************************\
  615. *
  616. * METHOD: CSnapInsCache::ScLoad
  617. *
  618. * PURPOSE: loads snapin cache from IStream
  619. *
  620. * PARAMETERS:
  621. * IStream* pStream - stream to load from
  622. *
  623. * RETURNS:
  624. * SC - result code
  625. *
  626. \***************************************************************************/
  627. SC CSnapInsCache::ScLoad(IStream* pStream)
  628. {
  629. DECLARE_SC(sc, TEXT("CSnapInsCache::ScLoad"));
  630. // parameter check
  631. sc = ScCheckPointers(pStream);
  632. if (sc)
  633. return sc;
  634. // loop thru saved snapins...
  635. do
  636. {
  637. CLSID clsid;
  638. ULONG bytesRead;
  639. sc = pStream->Read(&clsid, sizeof(clsid), &bytesRead);
  640. if (sc)
  641. return sc;
  642. ASSERT(bytesRead == sizeof(clsid));
  643. // ... until special marker is found
  644. if (clsid == GUID_NULL)
  645. {
  646. SetDirty(FALSE);
  647. return S_OK;
  648. }
  649. // creale new snapin
  650. CSnapInPtr spSnapIn;
  651. sc = ScGetSnapIn(clsid, &spSnapIn);
  652. if (sc)
  653. return sc;
  654. // recheck the pointer
  655. sc = ScCheckPointers(spSnapIn, E_UNEXPECTED);
  656. if (sc)
  657. return sc;
  658. // load the contents of snapin
  659. sc = spSnapIn->Load(this, pStream);
  660. if (sc)
  661. return sc;
  662. } while (true);
  663. return E_FAIL; // shouldl never get here.
  664. }
  665. static void WriteSnapInCLSID (
  666. CSnapIn* pSnapIn,
  667. LPCTSTR pszSection,
  668. LPCTSTR pszKeyPrefix,
  669. LPCTSTR pszFilename)
  670. {
  671. tstring strKey = _T("CLSID");
  672. if (pszKeyPrefix != NULL)
  673. strKey = pszKeyPrefix + strKey;
  674. tstring strCLSID = tstringFromCLSID (pSnapIn->GetSnapInCLSID());
  675. SafeWritePrivateProfileString (pszSection, strKey.data(), strCLSID.data(), pszFilename);
  676. }
  677. static void WriteSnapInName (
  678. CSnapIn* pSnapIn,
  679. LPCTSTR pszSection,
  680. LPCTSTR pszKeyPrefix,
  681. LPCTSTR pszFilename)
  682. {
  683. tstring strKey = _T("Name");
  684. if (pszKeyPrefix != NULL)
  685. strKey = pszKeyPrefix + strKey;
  686. WTL::CString strName;
  687. SC sc = pSnapIn->ScGetSnapInName (strName);
  688. if (sc.IsError() || strName.IsEmpty())
  689. strName = _T("<unknown>");
  690. SafeWritePrivateProfileString (pszSection, strKey.data(), strName, pszFilename);
  691. }
  692. static void AppendString (tstring& str, LPCTSTR pszToAppend)
  693. {
  694. if (!str.empty())
  695. str += _T(", ");
  696. str += pszToAppend;
  697. }
  698. static void WriteExtensionType (
  699. DWORD dwExtensionFlags,
  700. LPCTSTR pszSection,
  701. LPCTSTR pszKeyPrefix,
  702. LPCTSTR pszFilename)
  703. {
  704. tstring strKey = _T("Type");
  705. if (pszKeyPrefix != NULL)
  706. strKey = pszKeyPrefix + strKey;
  707. struct {
  708. CExtSI::EXTSI_FLAGS flag;
  709. LPCTSTR pszDescription;
  710. } FlagMap[] = {
  711. { CExtSI::EXT_TYPE_REQUIRED, _T("required") },
  712. { CExtSI::EXT_TYPE_STATIC, _T("static") },
  713. { CExtSI::EXT_TYPE_DYNAMIC, _T("dynamic") },
  714. { CExtSI::EXT_TYPE_NAMESPACE, _T("namespace") },
  715. { CExtSI::EXT_TYPE_CONTEXTMENU, _T("context menu") },
  716. { CExtSI::EXT_TYPE_TOOLBAR, _T("toolbar") },
  717. { CExtSI::EXT_TYPE_PROPERTYSHEET, _T("property sheet") },
  718. { CExtSI::EXT_TYPE_TASK, _T("taskpad") },
  719. { CExtSI::EXT_TYPE_VIEW, _T("view") },
  720. };
  721. tstring strType;
  722. for (int i = 0; i < countof (FlagMap); i++)
  723. {
  724. if (dwExtensionFlags & FlagMap[i].flag)
  725. AppendString (strType, FlagMap[i].pszDescription);
  726. }
  727. SafeWritePrivateProfileString (pszSection, strKey.data(), strType.data(), pszFilename);
  728. }
  729. HRESULT CSnapInsCache::Dump (LPCTSTR pszDumpFile)
  730. {
  731. static const TCHAR szStandaloneSection[] = _T("Standalone Snap-ins");
  732. static const TCHAR szStandaloneCountKey[] = _T("StandaloneCount");
  733. HRESULT hr = S_OK;
  734. int cStandalones = 0;
  735. try
  736. {
  737. /*
  738. * no stand-alone snap-ins found yet (write it now so it's at the
  739. * beginning of the section, for human readability)
  740. */
  741. SafeWritePrivateProfileString (szStandaloneSection, szStandaloneCountKey, _T("0"), pszDumpFile);
  742. /*
  743. * dump each snap-in to the file
  744. */
  745. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  746. {
  747. CSnapIn* pSnapIn = it->second;
  748. ASSERT(pSnapIn != NULL);
  749. if (pSnapIn == NULL)
  750. continue;
  751. pSnapIn->Dump (pszDumpFile, this);
  752. /*
  753. * if this is a stand-alone, update the "Standalone Snap-ins" section
  754. */
  755. if (pSnapIn->IsStandAlone())
  756. {
  757. TCHAR szKeyPrefix[16];
  758. wsprintf (szKeyPrefix, _T("Standalone%d."), ++cStandalones);
  759. WriteSnapInCLSID (pSnapIn, szStandaloneSection, szKeyPrefix, pszDumpFile);
  760. WriteSnapInName (pSnapIn, szStandaloneSection, szKeyPrefix, pszDumpFile);
  761. }
  762. }
  763. /*
  764. * if we found stand-alones, update the count
  765. */
  766. if (cStandalones > 0)
  767. {
  768. TCHAR szStandaloneCount[6];
  769. _itot (cStandalones, szStandaloneCount, 10);
  770. SafeWritePrivateProfileString (szStandaloneSection, szStandaloneCountKey,
  771. szStandaloneCount, pszDumpFile);
  772. }
  773. }
  774. catch (_com_error& err)
  775. {
  776. hr = err.Error();
  777. ASSERT (false && "Caught _com_error");
  778. }
  779. return (hr);
  780. }
  781. /*+-------------------------------------------------------------------------*
  782. * CSnapInsCache::ScCheckSnapinAvailability
  783. *
  784. *
  785. *--------------------------------------------------------------------------*/
  786. SC CSnapInsCache::ScCheckSnapinAvailability (CAvailableSnapinInfo& asi)
  787. {
  788. DECLARE_SC (sc, _T("CSnapInsCache::ScCheckSnapinAvailability"));
  789. #ifdef MMC_WIN64
  790. asi.m_cTotalSnapins = m_snapins.size();
  791. asi.m_vAvailableSnapins.clear();
  792. /*
  793. * destroy any existing imagelist
  794. */
  795. if (asi.m_himl)
  796. ImageList_Destroy (asi.m_himl);
  797. /*
  798. * if we're interested in 32-bit snap-ins, make sure the registry APIs
  799. * go to the 32-bit registry hive.
  800. */
  801. const REGSAM samDesired = (asi.m_f32Bit) ? KEY_READ | REG_OPTION_OPEN_32BITKEY
  802. : KEY_READ;
  803. CRegKey keyClsid;
  804. sc = ScFromWin32 (keyClsid.Open (HKEY_CLASSES_ROOT, _T("CLSID"), samDesired));
  805. if (sc)
  806. return (sc);
  807. CStr strUnknownSnapinName;
  808. VERIFY (strUnknownSnapinName.LoadString (GetStringModule(), IDS_UnknownSnapinName));
  809. /*
  810. * create an imagelist, tracing (but not aborting) on failure
  811. */
  812. const int nImageListFolder = 0;
  813. WTL::CImageList iml;
  814. if (!iml.Create (IDB_FOLDER_16, 16 /*cx*/, 4 /*cGrow*/, RGB(255,0,255) /*crMask*/))
  815. sc.FromLastError().TraceAndClear();
  816. /*
  817. * for each snap-in in the cache...
  818. */
  819. for (map_t::iterator it = m_snapins.begin(); it != m_snapins.end(); ++it)
  820. {
  821. /*
  822. * ...check to see if there's an HKCR\CLSID\{clsid}\InprocServer32
  823. * entry for it. If there is, we'll assume the snap-in is "available".
  824. */
  825. tstring strSnapinClsid = tstringFromCLSID (it->first);
  826. tstring strInprocServerKey = strSnapinClsid + _T("\\InprocServer32");
  827. CRegKey keyInprocServer;
  828. LONG lResult = keyInprocServer.Open (keyClsid, strInprocServerKey.data(), samDesired);
  829. bool fSnapinAvailable = (lResult == ERROR_SUCCESS);
  830. /*
  831. * if the snap-in's available, get it's name and put it in the
  832. * available snap-ins collection
  833. */
  834. if (fSnapinAvailable)
  835. {
  836. CBasicSnapinInfo bsi;
  837. bsi.m_clsid = it->first;
  838. CSnapIn*pSnapin = it->second;
  839. /*
  840. * get the snap-in's name
  841. */
  842. WTL::CString strSnapinName;
  843. if ((pSnapin != NULL) && !pSnapin->ScGetSnapInName(strSnapinName).IsError())
  844. bsi.m_strName = strSnapinName;
  845. else
  846. bsi.m_strName = strUnknownSnapinName; // "<unknown>"
  847. /*
  848. * Get the snap-in's image from its about object
  849. * (failures here aren't fatal and don't need to be traced).
  850. * We'll use a generic folder icon if we can't get an image
  851. * from the snap-in's about object.
  852. */
  853. CLSID clsidAbout;
  854. CSnapinAbout snapinAbout;
  855. if (!iml.IsNull())
  856. {
  857. if (!ScGetAboutFromSnapinCLSID(bsi.m_clsid, clsidAbout).IsError() &&
  858. snapinAbout.GetBasicInformation (clsidAbout))
  859. {
  860. /*
  861. * the bitmaps returned by GetSmallImages are owned by
  862. * the CSnapinAbout object (don't need to delete here)
  863. */
  864. HBITMAP hbmSmall;
  865. HBITMAP hbmSmallOpen; // unused here, but required for GetSmallImages
  866. COLORREF crMask;
  867. snapinAbout.GetSmallImages (&hbmSmall, &hbmSmallOpen, &crMask);
  868. /*
  869. * ImageList_AddMasked will mess up the background of
  870. * its input bitmap, but the input bitmap won't be
  871. * reused, so we don't need to make a copy like we
  872. * usually do.
  873. */
  874. WTL::CBitmap bmpSmall = CopyBitmap (hbmSmall);
  875. if (!bmpSmall.IsNull())
  876. bsi.m_nImageIndex = iml.Add (bmpSmall, crMask);
  877. else
  878. bsi.m_nImageIndex = nImageListFolder;
  879. }
  880. else
  881. bsi.m_nImageIndex = nImageListFolder;
  882. }
  883. /*
  884. * put it in the available snap-ins collection
  885. */
  886. asi.m_vAvailableSnapins.push_back (bsi);
  887. }
  888. #ifdef DBG
  889. if (fSnapinAvailable)
  890. Trace (tagVerboseSnapinAnalysis64,
  891. _T(" available: %s (image=%d)"),
  892. asi.m_vAvailableSnapins.back().m_strName.data(),
  893. asi.m_vAvailableSnapins.back().m_nImageIndex);
  894. else
  895. Trace (tagVerboseSnapinAnalysis64, _T("unavailable: %s"), strSnapinClsid.data());
  896. #endif
  897. }
  898. Trace (tagSnapinAnalysis64, _T("%d-bit snap-in analysis: %d total, %d available"), asi.m_f32Bit ? 32 : 64, asi.m_cTotalSnapins, asi.m_vAvailableSnapins.size());
  899. /*
  900. * give the imagelist to the CAvailableSnapinInfo
  901. */
  902. asi.m_himl = iml.Detach();
  903. #else
  904. sc = E_NOTIMPL;
  905. #endif // !MMC_WIN64
  906. return (sc);
  907. }
  908. void CSnapIn::MarkExtensionDeleted(CSnapIn* pSnapIn)
  909. {
  910. ASSERT(pSnapIn != NULL);
  911. CExtSI* pExt = m_pExtSI;
  912. while (pExt != NULL)
  913. {
  914. if (pExt->GetSnapIn() == pSnapIn)
  915. {
  916. pExt->MarkDeleted();
  917. return;
  918. }
  919. pExt = pExt->Next();
  920. }
  921. // wasn't in the list !
  922. ASSERT(FALSE);
  923. }
  924. //
  925. // Delete all extensions marked for deletion
  926. // Also reset any New flags
  927. //
  928. void CSnapIn::PurgeExtensions()
  929. {
  930. CExtSI* pExt = m_pExtSI;
  931. CExtSI* pExtPrev = NULL;
  932. // step through linked list, deleting marked nodes
  933. while (pExt != NULL)
  934. {
  935. if (pExt->IsMarkedForDeletion())
  936. {
  937. CExtSI *pExtNext = pExt->Next();
  938. if (pExtPrev)
  939. pExtPrev->SetNext(pExtNext);
  940. else
  941. m_pExtSI = pExtNext;
  942. // clear next link so extensions doesn't take the whole chain
  943. // with it when it is deleted
  944. pExt->SetNext(NULL);
  945. delete pExt;
  946. pExt = pExtNext;
  947. }
  948. else
  949. {
  950. pExt->SetNew(FALSE);
  951. pExtPrev = pExt;
  952. pExt = pExt->Next();
  953. }
  954. }
  955. }
  956. CExtSI* CSnapIn::FindExtension(const CLSID& rclsid)
  957. {
  958. CExtSI* pExt = m_pExtSI;
  959. while (pExt != NULL && !IsEqualCLSID(rclsid, pExt->GetSnapIn()->GetSnapInCLSID()))
  960. {
  961. pExt = pExt->Next();
  962. }
  963. return pExt;
  964. }
  965. CExtSI* CSnapIn::AddExtension(CSnapIn* pSI)
  966. {
  967. CExtSI* pExtSI = new CExtSI(pSI);
  968. ASSERT(pExtSI != NULL);
  969. if ( pExtSI == NULL )
  970. return NULL;
  971. // insert extension in increasing GUID order
  972. CExtSI* pExtPrev = NULL;
  973. CExtSI* pExtTemp = m_pExtSI;
  974. while (pExtTemp != NULL && pExtTemp->GetCLSID() < pExtSI->GetCLSID())
  975. {
  976. pExtPrev = pExtTemp;
  977. pExtTemp = pExtTemp->Next();
  978. }
  979. if (pExtPrev == NULL)
  980. {
  981. pExtSI->SetNext(m_pExtSI);
  982. m_pExtSI = pExtSI;
  983. }
  984. else
  985. {
  986. pExtSI->SetNext(pExtPrev->Next());
  987. pExtPrev->SetNext(pExtSI);
  988. }
  989. // mark as new
  990. pExtSI->SetNew();
  991. return pExtSI;
  992. }
  993. HRESULT CSnapIn::Save(IStream* pStream, BOOL fClearDirty)
  994. {
  995. ASSERT(pStream != NULL);
  996. if (pStream == NULL)
  997. return E_INVALIDARG;
  998. ULONG bytesWritten;
  999. HRESULT hr = pStream->Write(&GetSnapInCLSID(), sizeof(CLSID), &bytesWritten);
  1000. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(CLSID));
  1001. if (FAILED(hr))
  1002. return hr;
  1003. // If all extensions are enabled, then write special guid & flag and return
  1004. if (AreAllExtensionsEnabled())
  1005. {
  1006. hr = pStream->Write(&GUID_EnableAllExtensions, sizeof(GUID), &bytesWritten);
  1007. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(GUID));
  1008. if (FAILED(hr))
  1009. return hr;
  1010. int iSnapInEnable = DoesSnapInEnableAll() ? 1 : 0;
  1011. hr = pStream->Write(&iSnapInEnable, sizeof(int), &bytesWritten);
  1012. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(int));
  1013. return hr;
  1014. }
  1015. if (m_pExtSI)
  1016. {
  1017. hr = m_pExtSI->Save(pStream, fClearDirty);
  1018. ASSERT(SUCCEEDED(hr));
  1019. if (FAILED(hr))
  1020. return hr;
  1021. }
  1022. // NULL guid to terminate extensions list
  1023. hr = pStream->Write(&GUID_NULL, sizeof(GUID_NULL), &bytesWritten);
  1024. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(GUID_NULL));
  1025. if (FAILED(hr))
  1026. return hr;
  1027. return S_OK;
  1028. }
  1029. HKEY CSnapIn::OpenKey (REGSAM samDesired /*=KEY_ALL_ACCESS*/) const
  1030. {
  1031. MMC_ATL::CRegKey SnapInKey;
  1032. MMC_ATL::CRegKey AllSnapInsKey;
  1033. if (AllSnapInsKey.Open (HKEY_LOCAL_MACHINE, SNAPINS_KEY, samDesired) == ERROR_SUCCESS)
  1034. {
  1035. OLECHAR szItemKey[40];
  1036. int nChars = StringFromGUID2 (m_clsidSnapIn, szItemKey, countof(szItemKey));
  1037. if (nChars == 0)
  1038. return NULL;
  1039. USES_CONVERSION;
  1040. SnapInKey.Open (AllSnapInsKey, OLE2T(szItemKey), samDesired);
  1041. }
  1042. return (SnapInKey.Detach());
  1043. }
  1044. /*+-------------------------------------------------------------------------*
  1045. *
  1046. * CSnapIn::Persist
  1047. *
  1048. * PURPOSE: Persists the CSnapIn to the specified persistor.
  1049. *
  1050. * PARAMETERS:
  1051. * CPersistor& persistor :
  1052. *
  1053. * RETURNS:
  1054. * void
  1055. *
  1056. *+-------------------------------------------------------------------------*/
  1057. void CSnapIn::Persist(CPersistor& persistor)
  1058. {
  1059. if (persistor.IsStoring())
  1060. persistor.PersistAttribute(XML_ATTR_SNAPIN_CLSID, *const_cast<GUID*>(&GetSnapInCLSID()));
  1061. BOOL bAreAllExtensionsEnabled = AreAllExtensionsEnabled();
  1062. persistor.PersistAttribute(XML_ATTR_SNAPIN_EXTN_ENABLED, CXMLBoolean(bAreAllExtensionsEnabled));
  1063. SetAllExtensionsEnabled(bAreAllExtensionsEnabled);
  1064. if(bAreAllExtensionsEnabled) // if all extensions are enabled, don't save anything else.
  1065. return;
  1066. // save the extension information if it exists
  1067. persistor.Persist(m_ExtPersistor);
  1068. }
  1069. //+-------------------------------------------------------------------
  1070. //
  1071. // Member: CSnapIn::ScGetSnapInName
  1072. //
  1073. // Synopsis: Return the name of this snapin.
  1074. //
  1075. // Arguments:
  1076. //
  1077. // Returns: SC
  1078. //
  1079. //--------------------------------------------------------------------
  1080. SC CSnapIn::ScGetSnapInName (WTL::CString& strSnapInName) const
  1081. {
  1082. DECLARE_SC(sc, _T("CSnapIn::ScGetSnapInName"));
  1083. sc = ScGetSnapinNameFromRegistry (m_clsidSnapIn, strSnapInName);
  1084. if (sc)
  1085. return (sc);
  1086. return (sc);
  1087. }
  1088. DWORD CSnapIn::GetSnapInModule(TCHAR* pBuf, DWORD dwBufLen) const
  1089. {
  1090. ASSERT(pBuf != NULL && dwBufLen != NULL);
  1091. tstring strKeyName = g_szCLSID;
  1092. strKeyName += _T("\\");
  1093. strKeyName += tstringFromCLSID (m_clsidSnapIn);
  1094. strKeyName += _T("\\");
  1095. strKeyName += _T("InprocServer32");
  1096. *pBuf = 0;
  1097. MMC_ATL::CRegKey keyServer;
  1098. if (keyServer.Open (HKEY_CLASSES_ROOT, strKeyName.data(), KEY_QUERY_VALUE) == ERROR_SUCCESS)
  1099. {
  1100. TCHAR szModule[MAX_PATH];
  1101. DWORD cchModule = countof(szModule);
  1102. if (keyServer.QueryValue (szModule, NULL, &cchModule) == ERROR_SUCCESS)
  1103. ExpandEnvironmentStrings (szModule, pBuf, dwBufLen);
  1104. }
  1105. return (lstrlen (pBuf));
  1106. }
  1107. HRESULT CSnapIn::Load(CSnapInsCache* pCache, IStream* pStream, CExtSI*& pExtSI)
  1108. {
  1109. ASSERT(pStream != NULL);
  1110. if (pStream == NULL)
  1111. return E_INVALIDARG;
  1112. // Clear default enabling of all extensions. The true state will be
  1113. // determined from the persisted data.
  1114. SetAllExtensionsEnabled(FALSE);
  1115. // Read CLSID
  1116. CLSID clsid;
  1117. ULONG bytesRead;
  1118. HRESULT hr = pStream->Read(&clsid, sizeof(clsid), &bytesRead);
  1119. ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(clsid));
  1120. if (FAILED(hr))
  1121. return hr;
  1122. if (bytesRead != sizeof(clsid))
  1123. return hr = E_FAIL;
  1124. if (clsid == GUID_NULL)
  1125. return S_OK;
  1126. // If special "Enable all" guid encountered, read flag to see if
  1127. // snapin or user enabled all and return
  1128. if (clsid == GUID_EnableAllExtensions)
  1129. {
  1130. SetAllExtensionsEnabled();
  1131. int iSnapInEnable;
  1132. hr = pStream->Read(&iSnapInEnable, sizeof(int), &bytesRead);
  1133. ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(int));
  1134. if (iSnapInEnable)
  1135. SetSnapInEnablesAll();
  1136. return S_OK;
  1137. }
  1138. // Read extension type flags
  1139. DWORD dwExtTypes;
  1140. hr = pStream->Read(&dwExtTypes, sizeof(DWORD), &bytesRead);
  1141. ASSERT(SUCCEEDED(hr) && bytesRead == sizeof(DWORD));
  1142. if (FAILED(hr))
  1143. return hr;
  1144. if (pExtSI != NULL)
  1145. {
  1146. hr = Load(pCache, pStream, pExtSI);
  1147. ASSERT(hr == S_OK);
  1148. return hr == S_OK ? S_OK : E_FAIL;
  1149. }
  1150. CSnapInPtr spSnapIn;
  1151. SC sc = pCache->ScGetSnapIn(clsid, &spSnapIn);
  1152. if (sc)
  1153. return sc.ToHr();
  1154. ASSERT(spSnapIn != NULL);
  1155. pExtSI = new CExtSI(spSnapIn);
  1156. ASSERT(pExtSI != NULL);
  1157. if ( pExtSI == NULL )
  1158. return E_OUTOFMEMORY;
  1159. pExtSI->SetExtensionTypes(dwExtTypes);
  1160. hr = Load(pCache, pStream, pExtSI->Next());
  1161. ASSERT(hr == S_OK);
  1162. return hr == S_OK ? S_OK : E_FAIL;
  1163. }
  1164. HRESULT CSnapIn::Load(CSnapInsCache* pCache, IStream* pStream)
  1165. {
  1166. HRESULT hr = Load(pCache, pStream, m_pExtSI);
  1167. ASSERT(SUCCEEDED(hr));
  1168. if (FAILED(hr))
  1169. return hr;
  1170. return S_OK;
  1171. }
  1172. bool CSnapIn::IsStandAlone () const
  1173. {
  1174. MMC_ATL::CRegKey StandAloneKey;
  1175. MMC_ATL::CRegKey ItemKey;
  1176. ItemKey.Attach (OpenKey (KEY_READ));
  1177. if (ItemKey.m_hKey != NULL)
  1178. StandAloneKey.Open (ItemKey, g_szStandAlone, KEY_READ);
  1179. return (StandAloneKey.m_hKey != NULL);
  1180. }
  1181. /*+-------------------------------------------------------------------------*
  1182. * CSnapIn::Dump
  1183. *
  1184. * Dumps the information about this snap-in to a INI-style file. The
  1185. * format is:
  1186. *
  1187. * [{clsid}]
  1188. * Name=<NameString from registry>
  1189. * Module=<dll name>
  1190. * Version=<dll version number>
  1191. * Standalone=<1 if standalone, 0 if extension>
  1192. * ExtensionCount=<number of extensions>
  1193. * Extension1={clsid} (extension name)
  1194. * ...
  1195. * ExtensionN={clsid} (extension name)
  1196. *--------------------------------------------------------------------------*/
  1197. HRESULT CSnapIn::Dump (LPCTSTR pszDumpFile, CSnapInsCache* pCache)
  1198. {
  1199. /*
  1200. * use the CLSID as the section name
  1201. */
  1202. const tstring strSection = tstringFromCLSID (m_clsidSnapIn);
  1203. /*
  1204. * write Name
  1205. */
  1206. WriteSnapInName (this, strSection.data(), NULL, pszDumpFile);
  1207. /*
  1208. * write Module
  1209. */
  1210. TCHAR szModule[MAX_PATH];
  1211. bool fFoundModule = (GetSnapInModule (szModule, countof (szModule)) != 0);
  1212. if (!fFoundModule)
  1213. lstrcpy (szModule, _T("<unknown>"));
  1214. SafeWritePrivateProfileString (strSection.data(), _T("Module"), szModule, pszDumpFile);
  1215. /*
  1216. * write Version
  1217. */
  1218. TCHAR szVersion[64];
  1219. if (!fFoundModule || !GetModuleVersion (szModule, szVersion))
  1220. lstrcpy (szVersion, _T("<unknown>"));
  1221. SafeWritePrivateProfileString (strSection.data(), _T("Version"), szVersion, pszDumpFile);
  1222. /*
  1223. * write Standalone
  1224. */
  1225. SafeWritePrivateProfileString (strSection.data(), _T("Standalone"),
  1226. IsStandAlone() ? _T("1") : _T("0"),
  1227. pszDumpFile);
  1228. /*
  1229. * make sure the extension chain has been built
  1230. */
  1231. if (AreAllExtensionsEnabled())
  1232. {
  1233. /*
  1234. * Calling LoadRequiredExtensions with SNAPIN_SNAPIN_ENABLES_ALL set
  1235. * will result in SNAPIN_ENABLE_ALL_EXTS being cleared, which we don't
  1236. * want (rswaney).
  1237. *
  1238. * This happens because we haven't created the snap-in, so we can't
  1239. * pass an IComponentData from which LoadRequiredExtensions can QI
  1240. * for IRequiredExtensions. LoadRequiredExtensions uses
  1241. * IRequiredExtensions to determine whether SNAPIN_ENABLE_ALL_EXTS
  1242. * should be cleared or set. Since there's no IRequiredExtensions,
  1243. * SNAPIN_ENABLE_ALL_EXTS would be cleared.
  1244. */
  1245. SetSnapInEnablesAll (false);
  1246. LoadRequiredExtensions (this, NULL, pCache);
  1247. }
  1248. /*
  1249. * write ExtensionCount
  1250. */
  1251. TCHAR szExtCount[8];
  1252. CExtSI* pExt;
  1253. int cExtensions = 0;
  1254. // count the extensions
  1255. for (pExt = m_pExtSI; pExt != NULL; pExt = pExt->Next())
  1256. cExtensions++;
  1257. _itot (cExtensions, szExtCount, 10);
  1258. SafeWritePrivateProfileString (strSection.data(), _T("ExtensionCount"), szExtCount, pszDumpFile);
  1259. /*
  1260. * build up a cache of the extensions for this snap-in
  1261. */
  1262. CExtensionsCache ExtCache;
  1263. MMCGetExtensionsForSnapIn (m_clsidSnapIn, ExtCache);
  1264. /*
  1265. * write extensions
  1266. */
  1267. int i;
  1268. for (i = 0, pExt = m_pExtSI; i < cExtensions; i++, pExt = pExt->Next())
  1269. {
  1270. TCHAR szKeyPrefix[20];
  1271. wsprintf (szKeyPrefix, _T("Extension%d."), i+1);
  1272. DWORD dwExtFlags = ExtCache[pExt->GetSnapIn()->m_clsidSnapIn];
  1273. WriteSnapInCLSID (pExt->GetSnapIn(), strSection.data(), szKeyPrefix, pszDumpFile);
  1274. WriteSnapInName (pExt->GetSnapIn(), strSection.data(), szKeyPrefix, pszDumpFile);
  1275. WriteExtensionType (dwExtFlags, strSection.data(), szKeyPrefix, pszDumpFile);
  1276. }
  1277. return (S_OK);
  1278. }
  1279. HRESULT CExtSI::Save(IStream* pStream, BOOL fClearDirty)
  1280. {
  1281. ASSERT(pStream != NULL);
  1282. if (pStream == NULL)
  1283. return E_INVALIDARG;
  1284. // Save extension CLSID
  1285. ULONG bytesWritten;
  1286. HRESULT hr = pStream->Write(&GetCLSID(), sizeof(CLSID), &bytesWritten);
  1287. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(CLSID));
  1288. if (FAILED(hr))
  1289. return hr;
  1290. // Save extension types
  1291. DWORD dwExtTypes = m_dwFlags & EXT_TYPES_MASK;
  1292. hr = pStream->Write(&dwExtTypes, sizeof(DWORD), &bytesWritten);
  1293. ASSERT(SUCCEEDED(hr) && bytesWritten == sizeof(DWORD));
  1294. if (FAILED(hr))
  1295. return hr;
  1296. if (m_pNext == NULL)
  1297. return S_OK;
  1298. hr = m_pNext->Save(pStream, fClearDirty);
  1299. ASSERT(SUCCEEDED(hr));
  1300. if (FAILED(hr))
  1301. return hr;
  1302. return S_OK;
  1303. }
  1304. void CExtSI::Persist(CPersistor& persistor)
  1305. {
  1306. // create an "Extension" object beneath the "Extensions" object.
  1307. CPersistor persistorExtension(persistor, XML_TAG_SNAPIN_EXTENSION);
  1308. persistorExtension.PersistAttribute(XML_ATTR_SNAPIN_CLSID, *const_cast<GUID*>(&GetCLSID()));
  1309. }
  1310. /*+-------------------------------------------------------------------------*
  1311. *
  1312. * CExtSI::PersistNew
  1313. *
  1314. * PURPOSE: called to create and persist new extension entry
  1315. *
  1316. * PARAMETERS:
  1317. * CPersistor& persistor :
  1318. * CSnapIn& snapParent : parent to whom the extension belongs
  1319. * CSnapInsCache& snapCache : cache to put new (extension) snapin to
  1320. *
  1321. * RETURNS:
  1322. * void
  1323. *
  1324. *+-------------------------------------------------------------------------*/
  1325. void CExtSI::PersistNew(CPersistor &persistor, CSnapIn& snapParent, CSnapInsCache& snapCache)
  1326. {
  1327. DECLARE_SC(sc, TEXT("CExtSI::PersistNew"));
  1328. CLSID clsid;
  1329. CPersistor persistorExtension(persistor, XML_TAG_SNAPIN_EXTENSION);
  1330. persistorExtension.PersistAttribute(XML_ATTR_SNAPIN_CLSID, clsid);
  1331. CSnapInPtr spSnapIn;
  1332. sc = snapCache.ScGetSnapIn(clsid, &spSnapIn);
  1333. if (sc)
  1334. sc.Throw();
  1335. // create new extension entry
  1336. CExtSI *pExtSI = snapParent.AddExtension(spSnapIn);
  1337. sc = ScCheckPointers(pExtSI,E_FAIL);
  1338. if (sc)
  1339. sc.Throw();
  1340. // upload new extension entry info
  1341. pExtSI->Persist(persistor);
  1342. }
  1343. const CLSID& CExtSI::GetCLSID()
  1344. {
  1345. ASSERT(m_pSnapIn != NULL);
  1346. return m_pSnapIn ? m_pSnapIn->GetSnapInCLSID() : GUID_NULL;
  1347. }
  1348. /*+-------------------------------------------------------------------------*
  1349. *
  1350. * CSnapIn::PersistLoad
  1351. *
  1352. * PURPOSE: provided instead Persist to maintain reference to cache,
  1353. * required for registering new extensions during loading
  1354. *
  1355. * PARAMETERS:
  1356. * CPersistor& persistor :
  1357. * CSnapInsCache* pCache : cache to put new (extension) snapin to
  1358. *
  1359. * RETURNS:
  1360. * void
  1361. *
  1362. *+-------------------------------------------------------------------------*/
  1363. void CSnapIn::PersistLoad(CPersistor& persistor,CSnapInsCache* pCache)
  1364. {
  1365. m_ExtPersistor.SetCache(pCache);
  1366. persistor.Persist(*this);
  1367. m_ExtPersistor.SetCache(NULL);
  1368. }
  1369. /*+-------------------------------------------------------------------------*
  1370. *
  1371. * CSnapIn::CExtPersistor::Persist
  1372. *
  1373. * PURPOSE: persists collection of extensions for snapin
  1374. *
  1375. * PARAMETERS:
  1376. * CPersistor& persistor :
  1377. *
  1378. * RETURNS:
  1379. * void
  1380. *
  1381. *+-------------------------------------------------------------------------*/
  1382. void CSnapIn::CExtPersistor::Persist(CPersistor& persistor)
  1383. {
  1384. if (persistor.IsStoring())
  1385. {
  1386. CExtSI* pExt = GetParent().GetExtensionSnapIn();
  1387. while (pExt)
  1388. {
  1389. pExt->Persist(persistor);
  1390. pExt = pExt->Next();
  1391. }
  1392. }
  1393. else
  1394. {
  1395. XMLListCollectionBase::Persist(persistor);
  1396. }
  1397. }
  1398. /*+-------------------------------------------------------------------------*
  1399. *
  1400. * CSnapIn::CExtPersistor::OnNewElement
  1401. *
  1402. * PURPOSE: called for each new entry read from XML doc.
  1403. *
  1404. * PARAMETERS:
  1405. * CPersistor& persistor :
  1406. *
  1407. * RETURNS:
  1408. * void
  1409. *
  1410. *+-------------------------------------------------------------------------*/
  1411. void CSnapIn::CExtPersistor::OnNewElement(CPersistor& persistor)
  1412. {
  1413. DECLARE_SC(sc, TEXT("CSnapIn::CExtPersistor::OnNewElement"));
  1414. sc = (persistor.IsLoading() && m_pCache != NULL) ? S_OK : E_FAIL;
  1415. if (sc)
  1416. sc.Throw();
  1417. CExtSI::PersistNew(persistor, m_Parent, *m_pCache);
  1418. }
  1419. /***************************************************************************\
  1420. *
  1421. * METHOD: CSnapIn::ScDestroyExtensionList
  1422. *
  1423. * PURPOSE: destroys the list of extensions. used to do preliminary snapin cleanup
  1424. * to avoid circular references held by the extension sanpin
  1425. * locking the objects in the memory.
  1426. *
  1427. * PARAMETERS:
  1428. *
  1429. * RETURNS:
  1430. * SC - result code
  1431. *
  1432. \***************************************************************************/
  1433. SC CSnapIn::ScDestroyExtensionList()
  1434. {
  1435. DECLARE_SC(sc, TEXT("CSnapIn::ScDestroyExtensionList"));
  1436. // check if we have extensions
  1437. if ( m_pExtSI != NULL )
  1438. {
  1439. // assign to auto variable
  1440. // ( 'this' may not be valid if the only reference is from extension )
  1441. CExtSI *pExtension = m_pExtSI;
  1442. // update member pointer
  1443. m_pExtSI = NULL;
  1444. delete pExtension;
  1445. // delete the extension (it will delete the next and so on)
  1446. }
  1447. return sc;
  1448. }
  1449. /***************************************************************************\
  1450. *
  1451. * METHOD: CSnapIn::ScTempState_ResetReferenceCalculationData
  1452. *
  1453. * PURPOSE: resets external reference calculation data
  1454. * Used as the first step for external reference calculation process
  1455. *
  1456. * PARAMETERS:
  1457. *
  1458. *
  1459. * RETURNS:
  1460. * SC - result code
  1461. *
  1462. \***************************************************************************/
  1463. SC CSnapIn::ScTempState_ResetReferenceCalculationData( )
  1464. {
  1465. DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_ResetReferenceCalculationData"));
  1466. m_dwTempState_InternalRef = 0;
  1467. m_bTempState_HasStrongRef = 0;
  1468. return sc;
  1469. }
  1470. /***************************************************************************\
  1471. *
  1472. * METHOD: CSnapIn::ScTempState_UpdateInternalReferenceCounts
  1473. *
  1474. * PURPOSE: Informs snapin's extensions about the references kept to them
  1475. * Having this information extension snapin can know if it is
  1476. * referenced externally
  1477. *
  1478. * PARAMETERS:
  1479. *
  1480. *
  1481. * RETURNS:
  1482. * SC - result code
  1483. *
  1484. \***************************************************************************/
  1485. SC CSnapIn::ScTempState_UpdateInternalReferenceCounts( )
  1486. {
  1487. DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_UpdateInternalReferenceCounts"));
  1488. for ( CExtSI* pExtension = m_pExtSI; pExtension; pExtension = pExtension->Next() )
  1489. {
  1490. CSnapIn *pExtensionSnapin = pExtension->GetSnapIn();
  1491. sc = ScCheckPointers( pExtensionSnapin, E_UNEXPECTED );
  1492. if (sc)
  1493. return sc;
  1494. pExtensionSnapin->m_dwTempState_InternalRef++;
  1495. }
  1496. return sc;
  1497. }
  1498. /***************************************************************************\
  1499. *
  1500. * METHOD: CSnapIn::ScTempState_SetHasStrongReference
  1501. *
  1502. * PURPOSE: Marks itself as having external strong references (external to snapin cache)
  1503. * Marks own extensions as well.
  1504. *
  1505. * PARAMETERS:
  1506. *
  1507. * RETURNS:
  1508. * SC - result code
  1509. *
  1510. \***************************************************************************/
  1511. SC CSnapIn::ScTempState_SetHasStrongReference()
  1512. {
  1513. DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_SetHasStrongReference"));
  1514. // do nothing if already marked (else we'll have the infinite loop)
  1515. if ( m_bTempState_HasStrongRef )
  1516. return sc;
  1517. m_bTempState_HasStrongRef = true;
  1518. // recurse to all extensions (they inherit the strong reference too)
  1519. for ( CExtSI* pExtension = m_pExtSI; pExtension; pExtension = pExtension->Next() )
  1520. {
  1521. CSnapIn *pExtensionSnapin = pExtension->GetSnapIn();
  1522. sc = ScCheckPointers( pExtensionSnapin, E_UNEXPECTED );
  1523. if (sc)
  1524. return sc;
  1525. sc = pExtensionSnapin->ScTempState_SetHasStrongReference();
  1526. if (sc)
  1527. return sc;
  1528. }
  1529. return sc;
  1530. }
  1531. /***************************************************************************\
  1532. *
  1533. * METHOD: CSnapIn::ScTempState_MarkIfExternallyReferenced
  1534. *
  1535. * PURPOSE: Used as an intermediate step calculating external references
  1536. * compares internal references to total references.
  1537. * If has external references, marks itself as 'Externally referenced'
  1538. *
  1539. * PARAMETERS:
  1540. *
  1541. * RETURNS:
  1542. * SC - result code
  1543. *
  1544. \***************************************************************************/
  1545. SC CSnapIn::ScTempState_MarkIfExternallyReferenced()
  1546. {
  1547. DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_MarkIfExternallyReferenced"));
  1548. DWORD dwStrongRef = m_dwRef - m_dwTempState_InternalRef - 1/*chache reference*/;
  1549. if ( dwStrongRef > 0 )
  1550. {
  1551. // now mark itself and the extensions as having strong reference
  1552. sc = ScTempState_SetHasStrongReference();
  1553. if (sc)
  1554. return sc;
  1555. }
  1556. return sc;
  1557. }
  1558. /***************************************************************************\
  1559. *
  1560. * METHOD: CSnapIn::ScTempState_IsExternallyReferenced
  1561. *
  1562. * PURPOSE: Returns the cached reference status claculated by preceding
  1563. * call to CSnapInsCache::ScMarkExternallyReferencedSnapins.
  1564. *
  1565. * PARAMETERS:
  1566. * bool& bReferenced [out] - true if snapin has external (to snapin cache) strong references
  1567. *
  1568. * RETURNS:
  1569. * SC - result code
  1570. *
  1571. \***************************************************************************/
  1572. SC CSnapIn::ScTempState_IsExternallyReferenced( bool& bReferenced ) const
  1573. {
  1574. DECLARE_SC(sc, TEXT("CSnapIn::ScTempState_IsExternallyReferenced"));
  1575. bReferenced = m_bTempState_HasStrongRef;
  1576. return sc;
  1577. }