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.

1436 lines
37 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: psetstg.cxx
  7. //
  8. // Contents: Implementation of common class for OFS and DocFile
  9. // IPropertySetStorage
  10. //
  11. // Classes: CPropertySetStorage
  12. // CEnumSTATPROPSETSTG
  13. //
  14. // History: 1-Mar-95 BillMo Created.
  15. // 09-May-96 MikeHill Don't delete a CPropertyStorage object,
  16. // it deletes itself in the Release.
  17. // 22-May-96 MikeHill Set STATPROPSETSTG.dwOSVersion.
  18. // 06-Jun-96 MikeHill Added input validation.
  19. // 15-Jul-96 MikeHill - Handle STATSTG as OLECHAR (not WCHAR).
  20. // - Added CDocFilePropertySetStorage imp.
  21. // 07-Feb-97 Danl - Removed CDocFilePropertySetStorage.
  22. // - Moved _Create, _Open, & _Delete
  23. // into Create, Open & Delete
  24. // 10-Mar-98 MikeHill Pass grfMode into CPropertyStorage
  25. // create/open methods.
  26. // 06-May-98 MikeHill Use CoTaskMem rather than new/delete.
  27. // 5/18/98 MikeHill
  28. // - Cleaned up constructor by moving parameters to a
  29. // new Init method.
  30. // 6/11/98 MikeHill
  31. // - Dbg outs.
  32. // - Don't use out-parm as temp-parm in Create, Open.
  33. //
  34. // Notes:
  35. //
  36. //--------------------------------------------------------------------------
  37. #include <pch.cxx>
  38. #include <prophdr.hxx>
  39. #ifdef _MAC_NODOC
  40. ASSERTDATA // File-specific data for FnAssert
  41. #endif
  42. //
  43. // debugging support
  44. //
  45. #if DBG
  46. CHAR *
  47. DbgFmtId(REFFMTID rfmtid, CHAR *pszBuf)
  48. {
  49. PropSprintfA(pszBuf, "rfmtid=%08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X",
  50. rfmtid.Data1,
  51. rfmtid.Data2,
  52. rfmtid.Data3,
  53. rfmtid.Data4[0],
  54. rfmtid.Data4[1],
  55. rfmtid.Data4[2],
  56. rfmtid.Data4[3],
  57. rfmtid.Data4[4],
  58. rfmtid.Data4[5],
  59. rfmtid.Data4[6],
  60. rfmtid.Data4[7]);
  61. return(pszBuf);
  62. }
  63. CHAR *
  64. DbgMode(DWORD grfMode, CHAR *psz)
  65. {
  66. *psz = 0;
  67. if (grfMode & STGM_TRANSACTED)
  68. strcat(psz, "STGM_TRANSACTED | ");
  69. else
  70. strcat(psz, "STGM_DIRECT | ");
  71. if (grfMode & STGM_SIMPLE)
  72. strcat(psz, "STGM_SIMPLE | ");
  73. switch (grfMode & 3)
  74. {
  75. case STGM_READ:
  76. strcat(psz, "STGM_READ |");
  77. break;
  78. case STGM_WRITE:
  79. strcat(psz, "STGM_WRITE |");
  80. break;
  81. case STGM_READWRITE:
  82. strcat(psz, "STGM_READWRITE |");
  83. break;
  84. default:
  85. strcat(psz, "BAD grfMode |");
  86. break;
  87. }
  88. switch (grfMode & 0x70)
  89. {
  90. case STGM_SHARE_DENY_NONE:
  91. strcat(psz, "STGM_SHARE_DENY_NONE |");
  92. break;
  93. case STGM_SHARE_DENY_READ:
  94. strcat(psz, "STGM_SHARE_DENY_READ |");
  95. break;
  96. case STGM_SHARE_DENY_WRITE:
  97. strcat(psz, "STGM_SHARE_DENY_WRITE |");
  98. break;
  99. case STGM_SHARE_EXCLUSIVE:
  100. strcat(psz, "STGM_SHARE_EXCLUSIVE |");
  101. break;
  102. default:
  103. strcat(psz, "BAD grfMode | ");
  104. break;
  105. }
  106. if (grfMode & STGM_PRIORITY)
  107. strcat(psz, "STGM_PRIORITY | ");
  108. if (grfMode & STGM_DELETEONRELEASE)
  109. strcat(psz, "STGM_DELETEONRELEASE | ");
  110. if (grfMode & STGM_NOSCRATCH)
  111. strcat(psz, "STGM_NOSCRATCH | ");
  112. if (grfMode & STGM_CREATE)
  113. strcat(psz, "STGM_CREATE | ");
  114. if (grfMode & STGM_CONVERT)
  115. strcat(psz, "STGM_CONVERT | ");
  116. if (grfMode & STGM_FAILIFTHERE)
  117. strcat(psz, "STGM_FAILIFTHERE | ");
  118. return(psz);
  119. }
  120. CHAR *
  121. DbgFlags(DWORD grfFlags, CHAR *psz)
  122. {
  123. strcpy(psz, "grfFlags=");
  124. if (grfFlags & PROPSETFLAG_NONSIMPLE)
  125. strcat(psz, "PROPSETFLAG_NONSIMPLE |");
  126. else
  127. strcat(psz, "PROPSETFLAG_SIMPLE |");
  128. if (grfFlags & PROPSETFLAG_ANSI)
  129. strcat(psz, "PROPSETFLAG_ANSI |");
  130. else
  131. strcat(psz, "PROPSETFLAG_WIDECHAR |");
  132. return(psz);
  133. }
  134. #endif
  135. //+----------------------------------------------------------------------------
  136. //
  137. // Member: CPropertySetStorage::Init
  138. //
  139. // Synopsis: This method is used to provide the IStorage in which
  140. // property sets (IPropertyStorage's) will be created/opened.
  141. //
  142. // Arguments: [IStorage*]
  143. // The containing storage.
  144. // [IBlockingLock*]
  145. // The locking mechanism this CPropertySetStorage should
  146. // use. May be NULL.
  147. // [BOOL] (fControlLifetimes)
  148. // If true, we must addref the IStorage. E.g. in the docfile
  149. // implementation, CPropertySetStorage is a base class
  150. // for CExposedStorage, and this flag is set false.
  151. //
  152. //+----------------------------------------------------------------------------
  153. void
  154. CPropertySetStorage::Init( IStorage *pstg,
  155. IBlockingLock *pBlockingLock,
  156. BOOL fControlLifetimes )
  157. {
  158. DfpAssert( NULL == _pstg && NULL == _pBlockingLock );
  159. _pstg = pstg;
  160. _pBlockingLock = pBlockingLock;
  161. if( fControlLifetimes )
  162. {
  163. _fContainingStgIsRefed = TRUE;
  164. pstg->AddRef();
  165. if( NULL != pBlockingLock )
  166. pBlockingLock->AddRef();
  167. }
  168. }
  169. //+-------------------------------------------------------------------
  170. //
  171. // Member: CPropertySetStorage::Create
  172. //
  173. // Synopsis: Create a property set for outermost client of
  174. // IPropertSetStorage.
  175. //
  176. // Arguments: Passed through to CPropertyStorage ctor.
  177. //
  178. // Returns: S_OK or failure code.
  179. //
  180. // Notes: Create a new CPropertyStorage object which will
  181. // implement IPropertyStorage. The _pprivstg parameter
  182. // passed into CPropertyStorage::CPropertyStorage is
  183. // used to create (via QI) a matching type of mapped
  184. // stream (for OFS or DocFile properties.)
  185. //
  186. //--------------------------------------------------------------------
  187. HRESULT CPropertySetStorage::Create( REFFMTID rfmtid,
  188. const CLSID * pclsid,
  189. DWORD grfFlags,
  190. DWORD grfMode,
  191. IPropertyStorage ** ppprstg)
  192. {
  193. // ------
  194. // Locals
  195. // ------
  196. HRESULT hr;
  197. IStream *pstmPropSet = NULL;
  198. IStorage *pstgPropSet = NULL;
  199. CPropertyStorage *pcPropStg = NULL;
  200. BOOL fCreated = FALSE;
  201. INT nPass = 0;
  202. BOOL fLocked = FALSE;
  203. CPropSetName psn;
  204. DBGBUF(buf1);
  205. DBGBUF(buf2);
  206. DBGBUF(buf3);
  207. propXTrace( "CPropertySetStorage::Create" );
  208. // ----------
  209. // Validation
  210. // ----------
  211. if (S_OK != (hr = Validate()))
  212. goto Exit;
  213. Lock();
  214. fLocked = TRUE;
  215. GEN_VDATEREADPTRIN_LABEL(&rfmtid, FMTID, E_INVALIDARG, Exit, hr);
  216. GEN_VDATEPTRIN_LABEL(pclsid, CLSID, E_INVALIDARG, Exit, hr);
  217. GEN_VDATEPTROUT_LABEL( ppprstg, IPropertyStorage*, E_INVALIDARG, Exit, hr);
  218. propTraceParameters(( "%s, %s, %s",
  219. static_cast<const char*>(CStringize(rfmtid)),
  220. static_cast<const char*>(CStringize( SGrfFlags(grfFlags))),
  221. static_cast<const char*>(CStringize(SGrfMode(grfMode))) ));
  222. // We don't support PROPSETFLAG_UNBUFFERED from the IPropertySetStorage
  223. // interface. This may only be used in the StgOpenPropStg
  224. // and StgCreatePropStg APIs. This was done because we can't support
  225. // the flag on IPropertySetStorage::Open, so it would be inconsistent
  226. // to support it on the Create method.
  227. if( grfFlags & PROPSETFLAG_UNBUFFERED )
  228. {
  229. hr = STG_E_INVALIDFLAG;
  230. goto Exit;
  231. }
  232. hr = CheckFlagsOnCreateOrOpen(TRUE,grfMode);
  233. if (hr != S_OK)
  234. {
  235. goto Exit;
  236. }
  237. psn = CPropSetName(rfmtid);
  238. *ppprstg = NULL;
  239. // --------------------------------
  240. // Create a child Stream or Storage
  241. // --------------------------------
  242. // We'll make one or two passes (two if we the stream/storage
  243. // already exists and we have to delete it).
  244. while( nPass <= 1 )
  245. {
  246. if( PROPSETFLAG_NONSIMPLE & grfFlags )
  247. {
  248. // The Child should be a Storage
  249. hr = _pstg->CreateStorage( psn.GetPropSetName(),
  250. grfMode,
  251. 0L, 0L,
  252. &pstgPropSet );
  253. if( SUCCEEDED(hr) )
  254. {
  255. fCreated = TRUE;
  256. if( NULL != pclsid )
  257. {
  258. // We should also set the CLSID of the Storage.
  259. hr = pstgPropSet->SetClass(*pclsid);
  260. if( FAILED(hr) && E_NOTIMPL != hr ) goto Exit;
  261. hr = S_OK;
  262. }
  263. }
  264. } // if( PROPSETFLAG_NONSIMPLE & grfFlags )
  265. else
  266. {
  267. // The Child should be a Stream
  268. if( IsEqualGUID( rfmtid, FMTID_UserDefinedProperties ))
  269. {
  270. hr = CreateUserDefinedStream( _pstg, psn, grfMode, &fCreated, &pstmPropSet );
  271. }
  272. else
  273. {
  274. hr = _pstg->CreateStream(psn.GetPropSetName(),
  275. grfMode & ~STGM_TRANSACTED,
  276. 0, 0, &pstmPropSet);
  277. if( hr == S_OK )
  278. fCreated = TRUE;
  279. }
  280. }
  281. // If the create failed because the element already existed,
  282. // and if STGM_CREATE was set, then let's delete the existing
  283. // element and try again.
  284. if( hr == STG_E_FILEALREADYEXISTS
  285. &&
  286. grfMode & STGM_CREATE
  287. &&
  288. 0 == nPass )
  289. {
  290. hr = _pstg->DestroyElement( psn.GetPropSetName() );
  291. if( FAILED(hr) )
  292. goto Exit;
  293. nPass++;
  294. }
  295. // If we failed for any other reason, then it's fatal.
  296. else if( FAILED(hr) )
  297. goto Exit;
  298. // Otherwise (we succeeded), we can move on.
  299. else
  300. break;
  301. } // while( nPass <= 1 )
  302. // ---------------------------
  303. // Create the Property Storage
  304. // ---------------------------
  305. // Create a CPropertyStorage
  306. pcPropStg = new CPropertyStorage( _MSOpts );
  307. if( NULL == pcPropStg )
  308. {
  309. hr = E_OUTOFMEMORY;
  310. goto Exit;
  311. }
  312. // Initialize the property set.
  313. if( PROPSETFLAG_NONSIMPLE & grfFlags )
  314. // We need a non-simple IPropertyStorage
  315. hr = pcPropStg->Create( pstgPropSet, rfmtid, pclsid, grfFlags, grfMode);
  316. else
  317. // We need a simple IPropertyStorage
  318. hr = pcPropStg->Create( pstmPropSet, rfmtid, pclsid, grfFlags, grfMode );
  319. if( FAILED(hr) ) goto Exit;
  320. // ----
  321. // Exit
  322. // ----
  323. *ppprstg = static_cast<IPropertyStorage*>(pcPropStg);
  324. pcPropStg = NULL;
  325. hr = S_OK;
  326. Exit:
  327. // On failure ...
  328. if( FAILED(hr) )
  329. {
  330. // If an entry was created, attempt to delete it.
  331. if( fCreated )
  332. _pstg->DestroyElement( psn.GetPropSetName() );
  333. }
  334. if( NULL != pcPropStg )
  335. delete pcPropStg;
  336. if( NULL != pstmPropSet )
  337. pstmPropSet->Release();
  338. if( NULL != pstgPropSet )
  339. pstgPropSet->Release();
  340. if( fLocked )
  341. Unlock();
  342. if( STG_E_FILEALREADYEXISTS == hr )
  343. propSuppressExitErrors();
  344. return( hr );
  345. }
  346. //+-------------------------------------------------------------------
  347. //
  348. // Member: CPropertySetStorage::Open
  349. //
  350. // Synopsis: Open a property set for outermost client.
  351. //
  352. // Arguments: passed through to CPropertyStorage ctor.
  353. //
  354. // Returns: S_OK or error.
  355. //
  356. //--------------------------------------------------------------------
  357. HRESULT CPropertySetStorage::Open( REFFMTID rfmtid,
  358. DWORD grfMode,
  359. IPropertyStorage ** ppprstg)
  360. {
  361. HRESULT hr;
  362. IUnknown *punkPropSet = NULL;
  363. BOOL fSimple = TRUE;
  364. BOOL fLocked = FALSE;
  365. CPropertyStorage *pcPropStg = NULL;
  366. CPropSetName psn;
  367. DBGBUF(buf1);
  368. DBGBUF(buf2);
  369. propXTrace( "CPropertySetStorage::Open" );
  370. // ----------
  371. // Validation
  372. // ----------
  373. // Validate 'this'
  374. if (S_OK != (hr = Validate()))
  375. goto Exit;
  376. Lock();
  377. fLocked = TRUE;
  378. // Validate inputs
  379. GEN_VDATEREADPTRIN_LABEL(&rfmtid, FMTID, E_INVALIDARG, Exit, hr);
  380. GEN_VDATEPTROUT_LABEL( ppprstg, IPropertyStorage*, E_INVALIDARG, Exit, hr);
  381. propTraceParameters(( "%s, %s, %p",
  382. DbgFmtId(rfmtid, buf1), DbgMode(grfMode, buf2), ppprstg ));
  383. psn = CPropSetName(rfmtid);
  384. *ppprstg = NULL;
  385. // --------------------------------
  386. // Open the child Stream or Storage
  387. // --------------------------------
  388. hr = _pstg->OpenStream( psn.GetPropSetName(),
  389. 0L,
  390. grfMode & ~STGM_TRANSACTED,
  391. 0L,
  392. (IStream**) &punkPropSet );
  393. if( STG_E_FILENOTFOUND == hr )
  394. {
  395. fSimple = FALSE;
  396. hr = _pstg->OpenStorage( psn.GetPropSetName(),
  397. NULL,
  398. grfMode,
  399. NULL,
  400. 0L,
  401. (IStorage**) &punkPropSet );
  402. }
  403. if( FAILED(hr) ) goto Exit;
  404. // -------------------------
  405. // Open the Property Storage
  406. // -------------------------
  407. // Create an empty CPropertyStorage object.
  408. pcPropStg = new CPropertyStorage( _MSOpts );
  409. if( NULL == pcPropStg )
  410. {
  411. hr = E_OUTOFMEMORY;
  412. goto Exit;
  413. }
  414. // Open the property set and load it into the CPropertyStorage
  415. // object. We pas the default grfFlags, letting the Open method
  416. // infer its correct value from the property set.
  417. if( !fSimple )
  418. {
  419. hr = pcPropStg->Open(static_cast<IStorage*>(punkPropSet), // Addref-ed
  420. rfmtid,
  421. PROPSETFLAG_DEFAULT, // Flags are inferred
  422. grfMode );
  423. }
  424. else
  425. {
  426. hr = pcPropStg->Open( static_cast<IStream*>(punkPropSet), // Addref-ed
  427. rfmtid,
  428. PROPSETFLAG_DEFAULT, // Flags are inferred
  429. grfMode,
  430. FALSE ); // Don't delete this property set
  431. }
  432. if( FAILED(hr) ) goto Exit;
  433. // ----
  434. // Exit
  435. // ----
  436. *ppprstg = static_cast<IPropertyStorage*>(pcPropStg);
  437. pcPropStg = NULL;
  438. hr = S_OK;
  439. Exit:
  440. if( NULL != pcPropStg )
  441. delete pcPropStg;
  442. if( NULL != punkPropSet )
  443. punkPropSet->Release();
  444. if( fLocked )
  445. Unlock();
  446. if( STG_E_FILENOTFOUND == hr )
  447. propSuppressExitErrors();
  448. return(hr);
  449. }
  450. //+-------------------------------------------------------------------
  451. //
  452. // Member: CPropertySetStorage::Delete
  453. //
  454. // Synopsis: Delete the specified property set.
  455. //
  456. // Arguments: [rfmtid] -- format id of property set to delete.
  457. //
  458. // Returns: S_OK if successful, error otherwise.
  459. //
  460. // Notes: Get the matching name and try the element deletion.
  461. //
  462. //--------------------------------------------------------------------
  463. HRESULT CPropertySetStorage::Delete( REFFMTID rfmtid)
  464. {
  465. HRESULT hr = S_OK;
  466. IStream *pstm = NULL;
  467. BOOL fLocked = FALSE;
  468. CPropSetName psn;
  469. DBGBUF(buf);
  470. propXTrace( "CPropertySetStorage::Delete" );
  471. // ----------
  472. // Validation
  473. // ----------
  474. // Validate 'this'
  475. if (S_OK != (hr = Validate()))
  476. goto Exit;
  477. Lock();
  478. fLocked = TRUE;
  479. // Validate the input
  480. GEN_VDATEREADPTRIN_LABEL(&rfmtid, FMTID, E_INVALIDARG, Exit, hr);
  481. propTraceParameters(( "%s", DbgFmtId(rfmtid, buf) ));
  482. psn = CPropSetName(rfmtid);
  483. // --------------------------
  484. // Delete the PropertyStorage
  485. // --------------------------
  486. // Check for the special-case
  487. if( IsEqualIID( rfmtid, FMTID_UserDefinedProperties ))
  488. {
  489. // This property set is actually the second section of the Document
  490. // Summary Information property set. We must delete this
  491. // section, but we can't delete the Stream because it
  492. // still contains the first section.
  493. CPropertyStorage* pprstg;
  494. // Open the Stream.
  495. hr = _pstg->OpenStream( psn.GetPropSetName(),
  496. NULL,
  497. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  498. 0L,
  499. &pstm );
  500. if( FAILED(hr) ) goto Exit;
  501. // Create a CPropertyStorage
  502. pprstg = new CPropertyStorage( _MSOpts );
  503. if( NULL == pprstg )
  504. {
  505. hr = E_OUTOFMEMORY;
  506. goto Exit;
  507. }
  508. // Use the CPropertyStorage to delete the section.
  509. hr = pprstg->Open( pstm,
  510. rfmtid,
  511. PROPSETFLAG_DEFAULT,
  512. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  513. TRUE ); // Delete this section
  514. pprstg->Release(); // Deletes *pprstg
  515. pprstg = NULL;
  516. if( FAILED(hr) ) goto Exit;
  517. } // if( IsEqualIID( rfmtid, FMTID_DocSummaryInformation2 ))
  518. else
  519. {
  520. // This is not a special case, so we can just delete
  521. // the Stream. Note that if the rfmtid represents the first
  522. // section of the DocumentSummaryInformation set, we might be
  523. // deleting the second section here as well. That is a documented
  524. // side-effect.
  525. hr = _pstg->DestroyElement(psn.GetPropSetName());
  526. if( FAILED(hr) ) goto Exit;
  527. } // if( IsEqualIID( rfmtid, FMTID_UserDefinedProperties )) ... else
  528. // ----
  529. // Exit
  530. // ----
  531. hr = S_OK;
  532. Exit:
  533. if( NULL != pstm )
  534. pstm->Release();
  535. if( fLocked )
  536. Unlock();
  537. if( STG_E_FILENOTFOUND == hr )
  538. propSuppressExitErrors();
  539. return(hr);
  540. }
  541. //+-------------------------------------------------------------------
  542. //
  543. // Member: CPropertySetStorage::Enum
  544. //
  545. // Synopsis: Create an enumerator over the property set
  546. //
  547. // Arguments: [ppenum] -- where to return the pointer to the
  548. // enumerator.
  549. //
  550. // Returns: S_OK if ok, error otherwise.
  551. //
  552. // Notes: [ppenum] is NULL on error.
  553. //
  554. //--------------------------------------------------------------------
  555. HRESULT CPropertySetStorage::Enum( IEnumSTATPROPSETSTG ** ppenum)
  556. {
  557. HRESULT hr;
  558. BOOL fLocked = FALSE;
  559. propXTrace( "CPropertySetStorage::Enum" );
  560. // ----------
  561. // Validation
  562. // ----------
  563. // Validate 'this'
  564. if (S_OK != (hr = Validate()))
  565. goto Exit;
  566. Lock();
  567. fLocked = TRUE;
  568. // Validate the input
  569. GEN_VDATEPTROUT_LABEL( ppenum, IEnumSTATPROPSETSTG*, E_INVALIDARG, Exit, hr);
  570. *ppenum = NULL;
  571. propTraceParameters(( "%p", ppenum ));
  572. // --------------------
  573. // Create the enuerator
  574. // --------------------
  575. hr = STG_E_INSUFFICIENTMEMORY;
  576. *ppenum = new CEnumSTATPROPSETSTG(_pstg, &hr);
  577. if (FAILED(hr))
  578. {
  579. delete (CEnumSTATPROPSETSTG*) *ppenum;
  580. *ppenum = NULL;
  581. }
  582. // ----
  583. // Exit
  584. // ----
  585. Exit:
  586. if( fLocked )
  587. Unlock();
  588. return(hr);
  589. }
  590. //+-------------------------------------------------------------------
  591. //
  592. // Member: CEnumSTATPROPSETSTG::CEnumSTATPROPSETSTG
  593. //
  594. // Synopsis: Constructor which is used to implement
  595. // IPropertySetStorage::Enum
  596. //
  597. // Arguments: [pstg] -- the storage of the container to enumerate.
  598. // [phr] -- place to return HRESULT, S_OK or error.
  599. //
  600. // Notes: We use an STATSTG enumerator over the actual storage
  601. // to get the information about the property sets.
  602. //
  603. //--------------------------------------------------------------------
  604. CEnumSTATPROPSETSTG::CEnumSTATPROPSETSTG(IStorage *pstg, HRESULT *phr)
  605. {
  606. HRESULT & hr = *phr;
  607. _ulSig = ENUMSTATPROPSETSTG_SIG;
  608. _cRefs = 1;
  609. hr = pstg->EnumElements(FALSE, NULL, 0, &_penumSTATSTG);
  610. if (FAILED(hr))
  611. _penumSTATSTG = NULL;
  612. _cstatTotalInArray = 0;
  613. _istatNextToRead = 0;
  614. }
  615. //+-------------------------------------------------------------------
  616. //
  617. // Member: CEnumSTATPROPSETSTG::CEnumSTATPROPSETSTG
  618. //
  619. // Synopsis: Copy constructor which is used to implement
  620. // IEnumSTATPROPSETSTG::Clone.
  621. //
  622. // Arguments: [Other] -- The CEnumSTATPROPSETSTG to clone.
  623. // [phr] -- place to return HRESULT, S_OK or error.
  624. //
  625. //--------------------------------------------------------------------
  626. CEnumSTATPROPSETSTG::CEnumSTATPROPSETSTG( CEnumSTATPROPSETSTG &Other,
  627. HRESULT *phr)
  628. {
  629. HRESULT & hr = *phr;
  630. _ulSig = ENUMSTATPROPSETSTG_SIG;
  631. _cRefs = 1;
  632. _cstatTotalInArray = 0;
  633. _istatNextToRead = Other._istatNextToRead;
  634. hr = Other._penumSTATSTG->Clone(&_penumSTATSTG);
  635. if (hr == S_OK)
  636. {
  637. // Copy the data in the buffer
  638. memcpy(_statarray, Other._statarray, sizeof(_statarray));
  639. _cstatTotalInArray = Other._cstatTotalInArray;
  640. // Copy the strings in the buffer
  641. for (ULONG i=0; i<_cstatTotalInArray; i++)
  642. {
  643. _statarray[i].pwcsName = reinterpret_cast<OLECHAR*>
  644. ( CoTaskMemAlloc( sizeof(OLECHAR)*( ocslen(Other._statarray[i].pwcsName) + 1 ) ));
  645. if (_statarray[i].pwcsName == NULL)
  646. {
  647. _cstatTotalInArray = i;
  648. hr = STG_E_INSUFFICIENTMEMORY;
  649. break;
  650. }
  651. else
  652. {
  653. ocscpy(_statarray[i].pwcsName, Other._statarray[i].pwcsName);
  654. }
  655. }
  656. }
  657. // note: destructor will cleanup the the strings or enumerator left behind
  658. // in the error case
  659. }
  660. //+-------------------------------------------------------------------
  661. //
  662. // Member: CEnumSTATPROPSETSTG::~CEnumSTATPROPSETSTG
  663. //
  664. // Synopsis: Delete the enumerator.
  665. //
  666. // Notes: Just releases the contained IEnumSTATSTG
  667. //
  668. //--------------------------------------------------------------------
  669. CEnumSTATPROPSETSTG::~CEnumSTATPROPSETSTG()
  670. {
  671. _ulSig = ENUMSTATPROPSETSTG_SIGDEL;
  672. if (_penumSTATSTG != NULL)
  673. _penumSTATSTG->Release();
  674. CleanupStatArray();
  675. }
  676. //+-------------------------------------------------------------------
  677. //
  678. // Member: CEnumSTATPROPSETSTG::QueryInterface, AddRef, Release
  679. //
  680. // Synopsis: IUnknown
  681. //
  682. // Arguments: The usual thing.
  683. //
  684. //--------------------------------------------------------------------
  685. HRESULT CEnumSTATPROPSETSTG::QueryInterface( REFIID riid, void **ppvObject)
  686. {
  687. HRESULT hr;
  688. if (S_OK != (hr = Validate()))
  689. return(hr);
  690. *ppvObject = NULL;
  691. if (IsEqualIID(riid, IID_IEnumSTATPROPSETSTG))
  692. {
  693. *ppvObject = (IEnumSTATPROPSETSTG *)this;
  694. CEnumSTATPROPSETSTG::AddRef();
  695. }
  696. else
  697. if (IsEqualIID(riid, IID_IUnknown))
  698. {
  699. *ppvObject = (IUnknown *)this;
  700. CEnumSTATPROPSETSTG::AddRef();
  701. }
  702. else
  703. {
  704. hr = E_NOINTERFACE;
  705. }
  706. return(hr);
  707. }
  708. //+-------------------------------------------------------------------
  709. //
  710. // Member: CEnumSTATPROPSETSTG::AddRef
  711. //
  712. //--------------------------------------------------------------------
  713. ULONG CEnumSTATPROPSETSTG::AddRef(void)
  714. {
  715. if (S_OK != Validate())
  716. return(0);
  717. InterlockedIncrement(&_cRefs);
  718. return(_cRefs);
  719. }
  720. //+-------------------------------------------------------------------
  721. //
  722. // Member: CEnumSTATPROPSETSTG::Release
  723. //
  724. //--------------------------------------------------------------------
  725. ULONG CEnumSTATPROPSETSTG::Release(void)
  726. {
  727. LONG lRet;
  728. if (S_OK != Validate())
  729. return(0);
  730. lRet = InterlockedDecrement(&_cRefs);
  731. if (lRet == 0)
  732. {
  733. delete this;
  734. }
  735. else
  736. if (lRet <0)
  737. {
  738. lRet = 0;
  739. }
  740. return(lRet);
  741. }
  742. //+-------------------------------------------------------------------
  743. //
  744. // Member: CEnumSTATPROPSETSTG::Next
  745. //
  746. // Synopsis: Implement IEnumSTATPROPSETSTG for ofs and docfile.
  747. //
  748. // Arguments: [celt] -- Count of elements to attempt to retrieve.
  749. // [rgelt] -- Where to put the results. Must be valid for at least
  750. // celt * sizeof(STATPROPSETSTG) bytes in length.
  751. // [pceltFetched] -- Count of elements returned is put here if
  752. // the pointer is non-null. If celt > 1, pceltFetched must
  753. // be valid non-NULL. If pcelt is non-NULL, it must be valid.
  754. // if pcelt is NULL, celt must be 1.
  755. //
  756. // Returns: S_OK if ok, error otherwise.
  757. //
  758. // Notes: We use a stack buffer to get more stuff per call to
  759. // underlying storage IEnumSTATSTG::Next. We then copy
  760. // data from the STATSTG's to STATPROPSETSTG's.
  761. //
  762. // An outer loop enumerates into statarray and then an
  763. // inner loop copies each batch into the [rgelt] buffer.
  764. //
  765. //--------------------------------------------------------------------
  766. HRESULT CEnumSTATPROPSETSTG::Next(ULONG celt,
  767. STATPROPSETSTG * rgelt,
  768. ULONG * pceltFetched)
  769. {
  770. HRESULT hr;
  771. ULONG celtCallerTotal;
  772. // ----------
  773. // Validation
  774. // ----------
  775. // Validate 'this'
  776. if (S_OK != (hr = Validate()))
  777. return(hr);
  778. // Validate inputs
  779. if (NULL == pceltFetched)
  780. {
  781. if (1 != celt)
  782. return(STG_E_INVALIDPARAMETER);
  783. }
  784. else
  785. {
  786. VDATEPTROUT( pceltFetched, ULONG );
  787. *pceltFetched = 0;
  788. }
  789. if (0 == celt)
  790. return(hr);
  791. if( !IsValidPtrOut(rgelt, celt * sizeof(rgelt[0])) )
  792. return( E_INVALIDARG );
  793. // -----------------------
  794. // Perform the enumeration
  795. // -----------------------
  796. celtCallerTotal = 0;
  797. //
  798. // we do this loop until we have what the caller wanted or error, or
  799. // no more.
  800. //
  801. do
  802. {
  803. //
  804. // If our internal buffer is empty, we (re)load it
  805. //
  806. if (_istatNextToRead == _cstatTotalInArray)
  807. {
  808. if (_cstatTotalInArray != 0)
  809. CleanupStatArray();
  810. hr = _penumSTATSTG->Next(sizeof(_statarray)/sizeof(_statarray[0]),
  811. _statarray,
  812. &_cstatTotalInArray);
  813. }
  814. // S_OK or S_FALSE indicate that we got something
  815. if (SUCCEEDED(hr))
  816. {
  817. //
  818. // we loop reading out of this buffer until either we have
  819. // all that the caller asked for, or we have exhausted the
  820. // buffer.
  821. //
  822. for (; celtCallerTotal < celt &&
  823. _istatNextToRead < _cstatTotalInArray ;
  824. _istatNextToRead++)
  825. {
  826. OLECHAR *pocsName = _statarray[_istatNextToRead].pwcsName;
  827. BOOL fDone = FALSE;
  828. DfpAssert(pocsName != NULL);
  829. if (pocsName[0] == OC_PROPSET0)
  830. {
  831. // SPEC: if no matching fmtid then return GUID_NULL
  832. // *** get fmtid *** //
  833. if (!NT_SUCCESS(PrPropertySetNameToGuid(
  834. ocslen(pocsName), pocsName, &rgelt->fmtid)))
  835. {
  836. ZeroMemory(&rgelt->fmtid, sizeof(rgelt->fmtid));
  837. }
  838. // *** get clsid *** //
  839. // *** get grfFlags *** //
  840. // SPEC: don't support returning PROPSETFLAG_ANSI
  841. if (_statarray[_istatNextToRead].type == STGTY_STORAGE)
  842. {
  843. rgelt->clsid = _statarray[_istatNextToRead].clsid;
  844. rgelt->grfFlags = PROPSETFLAG_NONSIMPLE;
  845. }
  846. else
  847. {
  848. // SPEC: don't get the clsid for !PROPSET_NONSIMPLE
  849. ZeroMemory(&rgelt->clsid, sizeof(rgelt->clsid));
  850. rgelt->grfFlags = 0;
  851. }
  852. // *** get mtime *** //
  853. rgelt->mtime = _statarray[_istatNextToRead].mtime;
  854. // *** get ctime *** //
  855. rgelt->ctime = _statarray[_istatNextToRead].ctime;
  856. // *** get atime *** //
  857. rgelt->atime = _statarray[_istatNextToRead].atime;
  858. // *** default the OS Version *** //
  859. rgelt->dwOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  860. rgelt ++;
  861. celtCallerTotal ++;
  862. }
  863. }
  864. }
  865. }
  866. while (celtCallerTotal < celt && hr == S_OK);
  867. if (SUCCEEDED(hr))
  868. {
  869. hr = celt == celtCallerTotal ? S_OK : S_FALSE;
  870. DfpAssert(hr == S_OK || celtCallerTotal < celt);
  871. if (pceltFetched != NULL)
  872. *pceltFetched = celtCallerTotal;
  873. }
  874. return(hr);
  875. }
  876. //+-------------------------------------------------------------------
  877. //
  878. // Member: CEnumSTATPROPSETSTG::Skip
  879. //
  880. // Synopsis: Skip the requested number of elements.
  881. //
  882. // Arguments: [celt] -- number to skip.
  883. //
  884. // Returns: S_OK if all skipped, S_FALSE if less than requested
  885. // number skipped, error otherwise.
  886. //
  887. // Notes:
  888. //
  889. //--------------------------------------------------------------------
  890. HRESULT CEnumSTATPROPSETSTG::Skip(ULONG celt)
  891. {
  892. HRESULT hr;
  893. STATPROPSETSTG stat;
  894. ULONG celtCallerTotal = 0;
  895. if (S_OK != (hr = Validate()))
  896. return(hr);
  897. do
  898. {
  899. hr = Next(1, &stat, NULL);
  900. } while ( hr == S_OK && ++celtCallerTotal < celt );
  901. if (SUCCEEDED(hr))
  902. hr = celt == celtCallerTotal ? S_OK : S_FALSE;
  903. return(hr);
  904. }
  905. //+-------------------------------------------------------------------
  906. //
  907. // Member: CEnumSTATPROPSETSTG::CleanupStatArray
  908. //
  909. // Synopsis: Free any strings in the array.
  910. //
  911. //--------------------------------------------------------------------
  912. VOID CEnumSTATPROPSETSTG::CleanupStatArray()
  913. {
  914. for (ULONG i=0; i<_cstatTotalInArray; i++)
  915. {
  916. CoTaskMemFree( _statarray[i].pwcsName );
  917. _statarray[i].pwcsName = NULL;
  918. }
  919. _istatNextToRead = 0;
  920. _cstatTotalInArray = 0;
  921. }
  922. //+-------------------------------------------------------------------
  923. //
  924. // Member: CEnumSTATPROPSETSTG::Reset
  925. //
  926. // Synopsis: Reset the enumerator.
  927. //
  928. // Notes: Merely resetting the underlying enumerator should be
  929. // adequate,
  930. //
  931. //--------------------------------------------------------------------
  932. HRESULT CEnumSTATPROPSETSTG::Reset()
  933. {
  934. HRESULT hr;
  935. if (S_OK != (hr = Validate()))
  936. return(hr);
  937. hr = _penumSTATSTG->Reset();
  938. if (hr == S_OK)
  939. {
  940. CleanupStatArray();
  941. }
  942. return(hr);
  943. }
  944. //+-------------------------------------------------------------------
  945. //
  946. // Member: CEnumSTATPROPSETSTG::Clone
  947. //
  948. // Synopsis: Copy the enumeration state of this enumerator.
  949. //
  950. // Arguments: [ppenum] -- where to put the pointer to the clone
  951. //
  952. // Returns: S_OK if ok, error otherwise.
  953. //
  954. // Notes: We end up just calling IEnumSTATSTG::Clone in the
  955. // CEnumSTATPROPSETSTG constructor.
  956. //
  957. //--------------------------------------------------------------------
  958. HRESULT CEnumSTATPROPSETSTG::Clone(IEnumSTATPROPSETSTG ** ppenum)
  959. {
  960. HRESULT hr;
  961. // ----------
  962. // Validation
  963. // ----------
  964. // Validate 'this'
  965. if (S_OK != (hr = Validate()))
  966. return(hr);
  967. // Validate inputs
  968. VDATEPTROUT( ppenum, IEnumSTATPROPSETSTG* );
  969. // --------------------
  970. // Clone the enumerator
  971. // --------------------
  972. hr = STG_E_INSUFFICIENTMEMORY;
  973. *ppenum = new CEnumSTATPROPSETSTG(*this, &hr);
  974. if (FAILED(hr))
  975. {
  976. delete (CEnumSTATPROPSETSTG*) *ppenum;
  977. *ppenum = NULL;
  978. }
  979. return(hr);
  980. }
  981. //+-------------------------------------------------------------------
  982. //
  983. // Member: CPropertySetStorage::
  984. // QueryInterface, AddRef, and Release
  985. //
  986. // Synopsis: IUnknown members.
  987. //
  988. //--------------------------------------------------------------------
  989. HRESULT CPropertySetStorage::QueryInterface( REFIID riid, void **ppvObject)
  990. {
  991. HRESULT hr = S_OK;
  992. // ----------
  993. // Validation
  994. // ----------
  995. if (S_OK != (hr = Validate()))
  996. return(hr);
  997. VDATEREADPTRIN( &riid, IID );
  998. VDATEPTROUT( ppvObject, void* );
  999. // -----
  1000. // Query
  1001. // -----
  1002. if( IID_IPropertySetStorage == riid
  1003. ||
  1004. IID_IUnknown == riid )
  1005. {
  1006. *ppvObject = this;
  1007. this->AddRef();
  1008. }
  1009. else
  1010. {
  1011. *ppvObject = NULL;
  1012. hr = E_NOINTERFACE;
  1013. }
  1014. return( hr );
  1015. }
  1016. ULONG CPropertySetStorage::AddRef(void)
  1017. {
  1018. LONG lRet;
  1019. // ----------
  1020. // Validation
  1021. // ----------
  1022. if (S_OK != Validate())
  1023. return(0);
  1024. // ------
  1025. // AddRef
  1026. // ------
  1027. lRet = InterlockedIncrement( &_cReferences );
  1028. return( lRet );
  1029. }
  1030. ULONG CPropertySetStorage::Release(void)
  1031. {
  1032. LONG lRet;
  1033. // ----------
  1034. // Validation
  1035. // ----------
  1036. if (S_OK != Validate())
  1037. return(0);
  1038. // ----------------
  1039. // Decrement/Delete
  1040. // ----------------
  1041. lRet = InterlockedDecrement( &_cReferences );
  1042. if( 0 == lRet )
  1043. delete this;
  1044. else if( 0 > lRet )
  1045. lRet = 0;
  1046. return( lRet );
  1047. }
  1048. //+----------------------------------------------------------------------------
  1049. //
  1050. // Function: Lock & Unlock
  1051. //
  1052. // Synopsis: This methods take and release the CPropertySetStorage's
  1053. // critical section.
  1054. //
  1055. // Inputs: None
  1056. //
  1057. // Returns: Nothing
  1058. //
  1059. //+----------------------------------------------------------------------------
  1060. VOID
  1061. CPropertySetStorage::Lock()
  1062. {
  1063. #ifndef _MAC
  1064. if (NULL == _pBlockingLock)
  1065. {
  1066. DfpAssert (_fInitCriticalSection);
  1067. EnterCriticalSection( &_CriticalSection );
  1068. }
  1069. else
  1070. {
  1071. _pBlockingLock->Lock(INFINITE);
  1072. }
  1073. #endif
  1074. }
  1075. VOID
  1076. CPropertySetStorage::Unlock()
  1077. {
  1078. #ifndef _MAC
  1079. if (NULL == _pBlockingLock)
  1080. {
  1081. DfpAssert (_fInitCriticalSection);
  1082. LeaveCriticalSection( &_CriticalSection );
  1083. }
  1084. else
  1085. {
  1086. _pBlockingLock->Unlock();
  1087. }
  1088. #endif
  1089. }
  1090. //+-------------------------------------------------------------------
  1091. //
  1092. // Member: CPropertyStorage::CreateUserDefinedStream
  1093. //
  1094. // Synopsis: Open the "DocumentSummaryInformation" stream in order
  1095. // to create the UserDefined section of that property set.
  1096. // Create the stream only if it doesn't already exist.
  1097. //
  1098. // Arguments: [pstg] -- container storage
  1099. // [psn] -- the property set name
  1100. // [grfMode] -- mode of the property set
  1101. // [fCreated] -- TRUE if Stream is created, FALSE if opened.
  1102. // [ppStream] -- On return, the Stream for the property set
  1103. //
  1104. // Notes: This special case is necessary because this DocSumInfo
  1105. // property set is the only one in which we support more
  1106. // than one section. For this property set, if the caller
  1107. // Creates the second section, we must not *Create* the Stream,
  1108. // because that would lose the first Section. So, we must open it.
  1109. //
  1110. // This routine is only called when creating the second
  1111. // Section. The first Section is created normally (note
  1112. // that if the client creates the first section, the second
  1113. // section is lost).
  1114. //
  1115. // Also note that it may not be possible to open the Stream,
  1116. // since it may already be opened. This is significant
  1117. // because it may not be obvious to the caller. I.e.,
  1118. // to a client of IPropertyStorage, the 2 sections are
  1119. // distinct property sets, and you would think that you could
  1120. // open them for simultaneous write.
  1121. //
  1122. //--------------------------------------------------------------------
  1123. HRESULT
  1124. CPropertySetStorage::CreateUserDefinedStream( IStorage * pstg,
  1125. CPropSetName & psn,
  1126. DWORD grfMode,
  1127. BOOL * pfCreated,
  1128. IStream ** ppStream )
  1129. {
  1130. HRESULT hr;
  1131. DWORD grfOpenMode;
  1132. // Calculate the STGM flags to use for the Open. Create & Convert
  1133. // don't have meaning for the Open, and Transacted isn't supported
  1134. // by IPropertyStorage on the simple stream.
  1135. grfOpenMode = grfMode & ~(STGM_CREATE | STGM_CONVERT | STGM_TRANSACTED);
  1136. *pfCreated = FALSE;
  1137. // Try an Open
  1138. hr = pstg->OpenStream( psn.GetPropSetName(), NULL,
  1139. grfOpenMode,
  1140. 0L, ppStream );
  1141. // If the file wasn't there, try a create.
  1142. if(( hr == STG_E_FILENOTFOUND ) || ( hr == STG_E_INVALIDFUNCTION))
  1143. {
  1144. hr = pstg->CreateStream(psn.GetPropSetName(), grfMode, 0, 0, ppStream);
  1145. if( SUCCEEDED( hr ))
  1146. {
  1147. *pfCreated = TRUE;
  1148. }
  1149. }
  1150. return( hr );
  1151. } // CPropertySetStorage::CreateUserDefinedStream