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

1942 lines
54 KiB

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