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.

551 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: doccnfg.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "doccnfg.h"
  12. #include "comdbg.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. //
  15. // external references
  16. extern const wchar_t* AMCSnapInCacheStreamName;
  17. /////////////////////////////////////////////////////////////////////////////
  18. //
  19. // Class CMMCDocConfig implementation
  20. CMMCDocConfig::~CMMCDocConfig()
  21. {
  22. if (IsFileOpen())
  23. CloseFile();
  24. }
  25. STDMETHODIMP CMMCDocConfig::InterfaceSupportsErrorInfo(REFIID riid)
  26. {
  27. return (InlineIsEqualGUID(IID_IDocConfig, riid)) ? S_OK : S_FALSE;
  28. }
  29. STDMETHODIMP CMMCDocConfig::OpenFile(BSTR bstrFilePath)
  30. {
  31. return ScOpenFile( bstrFilePath ).ToHr();
  32. }
  33. STDMETHODIMP CMMCDocConfig::CloseFile()
  34. {
  35. return ScCloseFile().ToHr();
  36. }
  37. STDMETHODIMP CMMCDocConfig::SaveFile(BSTR bstrFilePath)
  38. {
  39. return ScSaveFile(bstrFilePath).ToHr();
  40. }
  41. STDMETHODIMP CMMCDocConfig::EnableSnapInExtension(BSTR bstrSnapIn, BSTR bstrExt, VARIANT_BOOL bEnable)
  42. {
  43. return ScEnableSnapInExtension(bstrSnapIn, bstrExt, bEnable).ToHr();
  44. }
  45. /*+-------------------------------------------------------------------------*
  46. * CMMCDocConfig::Dump
  47. *
  48. *
  49. *--------------------------------------------------------------------------*/
  50. STDMETHODIMP CMMCDocConfig::Dump (LPCTSTR pszDumpFilePath)
  51. {
  52. return ScDump (pszDumpFilePath).ToHr();
  53. }
  54. /*+-------------------------------------------------------------------------*
  55. * CMMCDocConfig::CheckSnapinAvailability
  56. *
  57. *
  58. *--------------------------------------------------------------------------*/
  59. STDMETHODIMP CMMCDocConfig::CheckSnapinAvailability (CAvailableSnapinInfo& asi)
  60. {
  61. return ScCheckSnapinAvailability(asi).ToHr();
  62. }
  63. /***************************************************************************\
  64. *
  65. * METHOD: CMMCDocConfig::ScOpenFile
  66. *
  67. * PURPOSE: Opens the specified console file and reads snapin cache from it
  68. *
  69. * PARAMETERS:
  70. * BSTR bstrFilePath [in] file name to read from
  71. *
  72. * RETURNS:
  73. * SC - result code
  74. *
  75. \***************************************************************************/
  76. SC CMMCDocConfig::ScOpenFile(BSTR bstrFilePath)
  77. {
  78. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScOpenFile"));
  79. // Close currently open file
  80. if (IsFileOpen())
  81. {
  82. sc = ScCloseFile();
  83. if (sc)
  84. sc.TraceAndClear(); // report the error and ignore
  85. }
  86. // parameter check
  87. if (bstrFilePath == NULL || SysStringLen(bstrFilePath) == 0)
  88. return sc = E_INVALIDARG;
  89. USES_CONVERSION;
  90. LPCTSTR lpstrFilePath = OLE2CT(bstrFilePath);
  91. // create object to load the snapins
  92. CAutoPtr<CSnapInsCache> spSnapInsCache( new CSnapInsCache );
  93. sc = ScCheckPointers( spSnapInsCache, E_OUTOFMEMORY );
  94. if (sc)
  95. return sc;
  96. // load the data (use bas class method)
  97. bool bXmlBased = false;
  98. CXMLDocument xmlDocument;
  99. IStoragePtr spStorage;
  100. sc = ScLoadConsole( lpstrFilePath, bXmlBased, xmlDocument, &spStorage );
  101. if (sc)
  102. return sc;
  103. // examine file type
  104. if ( !bXmlBased )
  105. {
  106. // structured storage - based console
  107. IStreamPtr spStream;
  108. sc = OpenDebugStream(spStorage, AMCSnapInCacheStreamName,
  109. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, L"SnapInCache", &spStream);
  110. if (sc)
  111. return sc;
  112. sc = spSnapInsCache->ScLoad(spStream);
  113. if (sc)
  114. return sc;
  115. m_spStorage = spStorage;
  116. }
  117. else
  118. {
  119. // xml - based console
  120. try // xml implementation throws sc's
  121. {
  122. // construct parent document
  123. CXMLElement elemDoc = xmlDocument;
  124. CPersistor persistorFile(xmlDocument, elemDoc);
  125. // init
  126. persistorFile.SetLoading(true);
  127. // navigate to snapin cache
  128. CPersistor persistorConsole ( persistorFile, XML_TAG_MMC_CONSOLE_FILE );
  129. CPersistor persistorTree ( persistorConsole, XML_TAG_SCOPE_TREE );
  130. // load
  131. persistorTree.Persist(*spSnapInsCache);
  132. // hold onto the persistor info
  133. m_XMLDocument = persistorConsole.GetDocument();
  134. m_XMLElemConsole = persistorConsole.GetCurrentElement();
  135. m_XMLElemTree = persistorTree.GetCurrentElement();
  136. }
  137. catch(SC& sc_thrown)
  138. {
  139. return (sc = sc_thrown);
  140. }
  141. }
  142. // keep on the pointer
  143. m_spCache.Attach( spSnapInsCache.Detach() );
  144. m_strFilePath = lpstrFilePath;
  145. return sc;
  146. }
  147. /***************************************************************************\
  148. *
  149. * METHOD: CMMCDocConfig::ScCloseFile
  150. *
  151. * PURPOSE: closes open file
  152. *
  153. * PARAMETERS:
  154. *
  155. * RETURNS:
  156. * SC - result code
  157. *
  158. \***************************************************************************/
  159. SC CMMCDocConfig::ScCloseFile()
  160. {
  161. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScCloseFile"));
  162. if (!IsFileOpen())
  163. return sc = E_UNEXPECTED;
  164. // release everything
  165. m_spStorage = NULL;
  166. m_strFilePath.erase();
  167. m_spCache.Delete();
  168. m_XMLDocument = CXMLDocument();
  169. m_XMLElemConsole = CXMLElement();
  170. m_XMLElemTree = CXMLElement();
  171. return sc;
  172. }
  173. /***************************************************************************\
  174. *
  175. * METHOD: ScFindAndTruncateChild
  176. *
  177. * PURPOSE: helper; locates the element by tag and removes all element's contents
  178. * Doing so instead of deleting and recreating the element preserves all
  179. * the formating and tag order in xml document
  180. *
  181. * PARAMETERS:
  182. * CPersistor& parent [in] - parent persistor
  183. * LPCTSTR strTag [in] - child's tag
  184. * CXMLElement& child [out] - child's element
  185. *
  186. * RETURNS:
  187. * SC - result code
  188. *
  189. \***************************************************************************/
  190. SC ScFindAndTruncateChild(CPersistor& parent, LPCTSTR strTag, CXMLElement& child)
  191. {
  192. DECLARE_SC(sc, TEXT("ScTruncateChild"));
  193. try
  194. {
  195. // create persistor for the old cache tag
  196. parent.SetLoading(true); // we want 'loading-alike' navigation
  197. CPersistor persistorChild( parent, strTag );
  198. parent.SetLoading(false); // restore saving behavior
  199. // get the element
  200. CXMLElement elChild = persistorChild.GetCurrentElement();
  201. // get nodes under the element
  202. CXMLElementCollection colChildren;
  203. elChild.get_children( &colChildren );
  204. long count = 0;
  205. colChildren.get_count( &count );
  206. // iterate and delete all the nodes
  207. while (count > 0)
  208. {
  209. CXMLElement el;
  210. colChildren.item( 0, &el);
  211. elChild.removeChild(el);
  212. --count;
  213. }
  214. // return the element
  215. child = elChild;
  216. }
  217. catch(SC& sc_thrown)
  218. {
  219. return (sc = sc_thrown);
  220. }
  221. return sc;
  222. }
  223. /***************************************************************************\
  224. *
  225. * METHOD: CMMCDocConfig::ScSaveFile
  226. *
  227. * PURPOSE: Saves file to specified location
  228. *
  229. * PARAMETERS:
  230. * BSTR bstrFilePath [in] file path to save to. NULL -> same as load
  231. *
  232. * RETURNS:
  233. * SC - result code
  234. *
  235. \***************************************************************************/
  236. SC CMMCDocConfig::ScSaveFile(BSTR bstrFilePath)
  237. {
  238. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScSaveFile"));
  239. if (!IsFileOpen() || m_spCache == NULL)
  240. return sc = E_UNEXPECTED;
  241. USES_CONVERSION;
  242. // if new path specified, save local copy as new default
  243. if ( bstrFilePath && SysStringLen(bstrFilePath) != 0)
  244. m_strFilePath = OLE2CT(bstrFilePath);
  245. // remove extensions marked for deletion
  246. m_spCache->Purge(TRUE);
  247. if ( m_spStorage != NULL ) // not the XML way?
  248. {
  249. // replace snapin cache stream with new cache contents
  250. IStreamPtr spStream;
  251. sc = CreateDebugStream(m_spStorage, AMCSnapInCacheStreamName,
  252. STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, L"SnapInCache", &spStream);
  253. if (sc)
  254. return sc;
  255. // save the cache
  256. sc = m_spCache->ScSave(spStream, TRUE);
  257. if (sc)
  258. return sc;
  259. // Create storage for the requested file
  260. IStoragePtr spNewStorage;
  261. sc = CreateDebugDocfile( T2COLE( m_strFilePath.c_str() ),
  262. STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE,
  263. &spNewStorage);
  264. if (sc)
  265. return sc;
  266. // copy the working storage to the new file
  267. sc = m_spStorage->CopyTo(NULL, NULL, NULL, spNewStorage);
  268. if (sc)
  269. return sc;
  270. // lets hold on the new one
  271. m_spStorage = spNewStorage;
  272. }
  273. else
  274. {
  275. try // may throw
  276. {
  277. // save the data
  278. CPersistor persistorTree( m_XMLDocument, m_XMLElemTree );
  279. // this is more tricky than loading - we want to reuse the same tag
  280. CXMLElement elCache;
  281. sc = ScFindAndTruncateChild(persistorTree, m_spCache->GetXMLType(), elCache);
  282. if (sc)
  283. return sc;
  284. // create persistor for the new cache tag
  285. CPersistor persistorCache( persistorTree, elCache );
  286. // now persist under the new tag
  287. m_spCache->Persist(persistorCache);
  288. // update documents guid to invalidate user data
  289. GUID guidConsoleId;
  290. sc = CoCreateGuid(&guidConsoleId);
  291. if (sc)
  292. return sc;
  293. // persistor for console
  294. CPersistor persistorConsole ( m_XMLDocument, m_XMLElemConsole );
  295. persistorConsole.SetLoading(false);
  296. CXMLElement elGuid;
  297. sc = ScFindAndTruncateChild(persistorConsole, XML_TAG_CONSOLE_FILE_UID, elGuid);
  298. if (sc)
  299. return sc;
  300. // create persistor for the new guid tag
  301. CPersistor persistorGuid( persistorConsole, elGuid );
  302. // now persist under the new tag
  303. persistorGuid.PersistContents(guidConsoleId);
  304. //save to file
  305. sc = ScSaveConsole( m_strFilePath.c_str(), true/*bForAuthorMode*/, m_XMLDocument);
  306. if (sc)
  307. return sc;
  308. }
  309. catch(SC& sc_thrown)
  310. {
  311. return (sc = sc_thrown);
  312. }
  313. }
  314. return sc;
  315. }
  316. /***************************************************************************\
  317. *
  318. * METHOD: CMMCDocConfig::ScEnableSnapInExtension
  319. *
  320. * PURPOSE: Enables extension in snapin cache
  321. *
  322. * PARAMETERS:
  323. * BSTR bstrSnapIn [in] classid of the snapin
  324. * BSTR bstrExt [in] classid of extension
  325. * VARIANT_BOOL bEnable [in] enable/disable flag
  326. *
  327. * RETURNS:
  328. * SC - result code
  329. *
  330. \***************************************************************************/
  331. SC CMMCDocConfig::ScEnableSnapInExtension(BSTR bstrSnapIn, BSTR bstrExt, VARIANT_BOOL bEnable)
  332. {
  333. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScEnableSnapInExtension"));
  334. CLSID SnapInCLSID;
  335. CLSID ExtCLSID;
  336. CSnapInPtr spBaseSnapIn;
  337. CSnapInPtr spExtSnapIn;
  338. // convert input strings to CLSIDs
  339. sc = CLSIDFromString(bstrSnapIn, &SnapInCLSID);
  340. if (sc)
  341. return sc;
  342. sc = CLSIDFromString( bstrExt, &ExtCLSID);
  343. if (sc)
  344. return sc;
  345. // Locate base snap-in in cache
  346. sc = m_spCache->ScFindSnapIn(SnapInCLSID, &spBaseSnapIn);
  347. if (sc)
  348. return sc = E_INVALIDARG;
  349. // Check if extension is enabled
  350. CExtSI* pExt = spBaseSnapIn->GetExtensionSnapIn();
  351. while (pExt != NULL)
  352. {
  353. if (pExt->GetSnapIn()->GetSnapInCLSID() == ExtCLSID)
  354. break;
  355. pExt = pExt->Next();
  356. }
  357. // if extension is present and not marked for deletion
  358. if (pExt != NULL && !pExt->IsMarkedForDeletion())
  359. {
  360. // If should be disabled, just mark deleted
  361. if (!bEnable)
  362. pExt->MarkDeleted(TRUE);
  363. }
  364. else
  365. {
  366. // if should be enabled
  367. if (bEnable)
  368. {
  369. // if extension is present, just undelete
  370. if (pExt != NULL)
  371. {
  372. pExt->MarkDeleted(FALSE);
  373. }
  374. else
  375. {
  376. // Find or create cache entry for extension snapin
  377. sc = m_spCache->ScGetSnapIn(ExtCLSID, &spExtSnapIn);
  378. if (sc)
  379. return sc;
  380. // Add as extension to base snapin
  381. spBaseSnapIn->AddExtension(spExtSnapIn);
  382. }
  383. }
  384. }
  385. return sc;
  386. }
  387. /***************************************************************************\
  388. *
  389. * METHOD: CMMCDocConfig::ScDump
  390. *
  391. * PURPOSE: dumps contents of snapin cache
  392. *
  393. * PARAMETERS:
  394. * LPCTSTR pszDumpFilePath [in] file to dump to
  395. *
  396. * RETURNS:
  397. * SC - result code
  398. *
  399. \***************************************************************************/
  400. SC CMMCDocConfig::ScDump (LPCTSTR pszDumpFilePath)
  401. {
  402. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScDump"));
  403. /*
  404. * validate input
  405. */
  406. sc = ScCheckPointers (pszDumpFilePath);
  407. if (sc)
  408. return sc;
  409. if (pszDumpFilePath[0] == 0)
  410. return sc = E_INVALIDARG;
  411. /*
  412. * make sure a file is open
  413. */
  414. if (!IsFileOpen())
  415. return ((sc = E_UNEXPECTED).ToHr());
  416. sc = ScCheckPointers (m_spCache, E_UNEXPECTED);
  417. if (sc)
  418. return (sc.ToHr());
  419. return (m_spCache->Dump (pszDumpFilePath));
  420. }
  421. /***************************************************************************\
  422. *
  423. * METHOD: CMMCDocConfig::ScCheckSnapinAvailability
  424. *
  425. * PURPOSE:
  426. *
  427. * PARAMETERS:
  428. * BOOL f32bit [in] // check 32-bit (vs. 64-bit) snap-ins?
  429. * UINT& cTotalSnapins [out] // total number of snap-ins referenced in the console file
  430. * UINT& cAvailableSnapins [out] // number of snap-ins available in the requested memory model
  431. *
  432. * RETURNS:
  433. * SC - result code
  434. *
  435. \***************************************************************************/
  436. SC CMMCDocConfig::ScCheckSnapinAvailability (CAvailableSnapinInfo& asi)
  437. {
  438. DECLARE_SC(sc, TEXT("CMMCDocConfig::ScCheckSnapinAvailability"));
  439. /*
  440. * make sure a file is open
  441. */
  442. if (!IsFileOpen())
  443. return ((sc = E_UNEXPECTED).ToHr());
  444. sc = ScCheckPointers (m_spCache, E_UNEXPECTED);
  445. if (sc)
  446. return sc;
  447. sc = m_spCache->ScCheckSnapinAvailability (asi);
  448. if (sc)
  449. return sc;
  450. return sc;
  451. }