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.

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