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.

3638 lines
96 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: propstg.cxx
  7. //
  8. // Contents: Class that directly implements IPropertyStorage
  9. //
  10. // Classes: CCoTaskAllocator
  11. // CPropertyStorage
  12. //
  13. // Notes: For methods that state 'if successful returns S_OK,
  14. // otherwise error code', the possible error codes include:
  15. //
  16. // STG_E_INVALIDHANDLE
  17. // STG_E_INSUFFICIENTMEMORY
  18. // STG_E_MEDIUMFULL
  19. // STG_E_REVERTED
  20. // STG_E_INVALIDPARAMETER
  21. // STG_E_INVALIDFLAG
  22. //
  23. // History: 1-Mar-95 BillMo Created.
  24. // 22-Feb-96 MikeHill Use VT_EMPTY instead of VT_ILLEGAL.
  25. // 14-Mar-96 MikeHill Set _fUserDefinedProperties in open constructor.
  26. // 09-May-96 MikeHill Don't return an error when someone calls
  27. // IPropertyStorage::Revert on a direct-mode propset.
  28. // 22-May-96 MikeHill Use the new _dwOSVersion.
  29. // 06-Jun-96 MikeHill Validate inputs.
  30. // 31-Jul-96 MikeHill - Treat prop names as OLECHARs, not WCHARs
  31. // - Added CDocFilePropertyStorage
  32. // - Modified for Mac support.
  33. // 07-Feb-97 Danl - Removed CDocFilePropertyStorage.
  34. // 10-Mar-98 MikeHill - Only stat for the grfMode on create/open
  35. // if it wasn't provided by the caller.
  36. // - Dbg outputs.
  37. // 5/6/98 MikeHill
  38. // - Use CoTaskMem rather than new/delete.
  39. // - Removed calls for defunct UnicodeCallouts.
  40. // - Added dbgouts.
  41. // - Changed GetCPropertySetStream to GetFormatVersion (DBG only).
  42. // 5/18/98 MikeHill
  43. // - Fixed typos.
  44. // 6/11/98 MikeHill
  45. // - Allow the codepage to change during WriteMultiple.
  46. // 8/18/98 MikeHill
  47. // - If the given _grfMode is zero, then probe the stream
  48. // to see if it's actually writeable.
  49. // - InitializePropertyStream now determines the CREATEPROP_
  50. // flags internally.
  51. //
  52. //--------------------------------------------------------------------------
  53. #include <pch.cxx>
  54. #include <tstr.h>
  55. #ifdef _MAC_NODOC
  56. ASSERTDATA // File-specific data for FnAssert
  57. #endif
  58. #ifndef _MAC // No InfoLevel debug functionality on Mac.
  59. DECLARE_INFOLEVEL(prop)
  60. #endif
  61. extern "C" const IID
  62. IID_IStorageTest = { /* 40621cf8-a17f-11d1-b28d-00c04fb9386d */
  63. 0x40621cf8,
  64. 0xa17f,
  65. 0x11d1,
  66. {0xb2, 0x8d, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d}
  67. };
  68. // The IMappedStream is implemented by all the IStream implementations,
  69. // and provides a mapping for CPropertySetStream.
  70. extern "C" const IID
  71. IID_IMappedStream = { /* 7d747d7f-a49e-11d1-b28e-00c04fb9386d */
  72. 0x7d747d7f,
  73. 0xa49e,
  74. 0x11d1,
  75. {0xb2, 0x8e, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d}
  76. };
  77. //+-------------------------------------------------------------------
  78. //
  79. // Member: CCoTaskAllocator::Allocate, Free.
  80. //
  81. // Synopsis: A PMemoryAllocator used by the Pr*
  82. // property set routines. This is required
  83. // so that those routines can work in any
  84. // heap.
  85. //
  86. //--------------------------------------------------------------------
  87. void *
  88. CCoTaskAllocator::Allocate(ULONG cbSize)
  89. {
  90. return( CoTaskMemAlloc(cbSize) );
  91. }
  92. void
  93. CCoTaskAllocator::Free(void *pv)
  94. {
  95. CoTaskMemFree( pv );
  96. }
  97. const OLECHAR g_oszPropertyContentsStreamName[] = OLESTR( "CONTENTS" );
  98. //+-------------------------------------------------------------------
  99. //
  100. // Member: CPropertyStorage::Initialize
  101. //
  102. // Synopsis: Initialize members to known values.
  103. //
  104. //--------------------------------------------------------------------
  105. void CPropertyStorage::Initialize()
  106. {
  107. _fExplicitelyProbedForWriteAccess = FALSE;
  108. _fUserDefinedProperties = FALSE;
  109. _ulSig = PROPERTYSTORAGE_SIG;
  110. _cRefs = 1;
  111. _pstgPropSet = NULL;
  112. _pstmPropSet = NULL;
  113. _dwOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  114. _np = NULL;
  115. _ms = NULL;
  116. _usCodePage = CP_WINUNICODE;
  117. _grfFlags = 0;
  118. _grfMode = 0;
  119. #if DBG
  120. _cLocks = 0;
  121. #endif
  122. }
  123. //+-------------------------------------------------------------------
  124. //
  125. // Member: CPropertyStorage::InitializePropertyStream.
  126. //
  127. // Synopsis: Initialize the storage-type specific members.
  128. //
  129. // Arguments: [pguid] -- FMTID, in for create only.
  130. // [pclsid] -- Class id, in for create only.
  131. // [CreateOpenDelete] -- has one of the following
  132. // values: CREATE_PROPSTREAM, OPEN_PROPSTREAM, or
  133. // DELETE_PROPSTREAM.
  134. //
  135. // Returns: HRESULT
  136. //
  137. // Requires:
  138. // _pstmPropSet -- The IStream of the main property set stream.
  139. //
  140. // Modifies:
  141. // _ms (IMappedStream *)
  142. //
  143. // (assumed NULL on entry) will be NULL or valid on exit
  144. //
  145. // _np (NTPROP) aka CPropertySetStream
  146. //
  147. // (assumed NULL on entry) will be NULL or valid on exit
  148. //
  149. // Notes:
  150. //
  151. //--------------------------------------------------------------------
  152. HRESULT
  153. CPropertyStorage::InitializePropertyStream(
  154. const GUID *pguid,
  155. GUID const *pclsid,
  156. EInitializePropertyStream CreateOpenDelete )
  157. {
  158. HRESULT hr = S_OK;
  159. DWORD grfBehavior = 0;
  160. USHORT createprop = 0; // Flags parameter to PrCreatePropertySet
  161. propITrace( "CPropertyStorage::InitializePropertyStream" );
  162. AssertLocked();
  163. // Set the CREATEPROP_ flags in createprop
  164. if( CREATE_PROPSTREAM == CreateOpenDelete )
  165. createprop = CREATEPROP_CREATE;
  166. else if( DELETE_PROPSTREAM == CreateOpenDelete )
  167. createprop = CREATEPROP_DELETE;
  168. else
  169. {
  170. DfpAssert( OPEN_PROPSTREAM == CreateOpenDelete );
  171. // If _grfMode is zero, it's either uninitialized or STGM_READ|STGM_SHARE_DENYNONE.
  172. // We'll consider it unknown for now, and probe the stream later to see if it's
  173. // writeable.
  174. if( 0 == _grfMode )
  175. createprop = CREATEPROP_UNKNOWN;
  176. else
  177. createprop = IsWriteable() ? CREATEPROP_WRITE : CREATEPROP_READ;
  178. }
  179. if( IsNonSimple() )
  180. createprop |= CREATEPROP_NONSIMPLE;
  181. // In the create path, set the behavior flag that will be passed to
  182. // PrCreatePropertySet. In the open path, this will be returned
  183. // from that function instead.
  184. if( PROPSETFLAG_CASE_SENSITIVE & _grfFlags
  185. &&
  186. CREATEPROP_CREATE & createprop )
  187. {
  188. grfBehavior = PROPSET_BEHAVIOR_CASE_SENSITIVE;
  189. }
  190. // Get an appropriate IMappedStream
  191. hr = CreateMappedStream();
  192. if( FAILED(hr) ) goto Exit;
  193. // Create the CPropertySetStream
  194. NTSTATUS Status;
  195. DfpAssert( NULL == _np );
  196. Status = PrCreatePropertySet(
  197. (NTMAPPEDSTREAM)_ms,
  198. createprop,
  199. pguid,
  200. pclsid,
  201. (NTMEMORYALLOCATOR) &_cCoTaskAllocator,
  202. GetUserDefaultLCID(),
  203. &_dwOSVersion,
  204. &_usCodePage,
  205. &grfBehavior,
  206. &_np);
  207. if (!NT_SUCCESS(Status))
  208. {
  209. propDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::InitializePropertyStream"
  210. " - PrCreatePropertySet Status=%08X\n", this, Status));
  211. hr = DfpNtStatusToHResult(Status);
  212. goto Exit;
  213. }
  214. // If this was a create, the input _grfFlags should match the Behavior
  215. DfpAssert( (PROPSETFLAG_CASE_SENSITIVE & _grfFlags) && (PROPSET_BEHAVIOR_CASE_SENSITIVE & grfBehavior)
  216. ||
  217. !(PROPSETFLAG_CASE_SENSITIVE & _grfFlags) && !(PROPSET_BEHAVIOR_CASE_SENSITIVE & grfBehavior)
  218. ||
  219. !(CREATEPROP_CREATE & createprop) );
  220. // Also if this was a create, the input _grfFlags should match the codepage
  221. DfpAssert( (PROPSETFLAG_ANSI & _grfFlags) && CP_WINUNICODE != _usCodePage
  222. ||
  223. !(PROPSETFLAG_ANSI & _grfFlags) && CP_WINUNICODE == _usCodePage
  224. ||
  225. !(CREATEPROP_CREATE & createprop) );
  226. // If this is an open, we need to update _grfFlags with the actual values,
  227. // so that we can return them in a Stat.
  228. if( CP_WINUNICODE != _usCodePage )
  229. _grfFlags |= PROPSETFLAG_ANSI;
  230. if( PROPSET_BEHAVIOR_CASE_SENSITIVE & grfBehavior )
  231. _grfFlags |= PROPSETFLAG_CASE_SENSITIVE;
  232. Exit:
  233. if( STG_E_FILENOTFOUND == hr )
  234. propSuppressExitErrors();
  235. return(hr);
  236. }
  237. //+-------------------------------------------------------------------
  238. //
  239. // Member: CPropertyStorage::~CPropertyStorage
  240. //
  241. // Synopsis: Free up object resources.
  242. //
  243. // Notes: Cleans up even from partial construction.
  244. //
  245. //--------------------------------------------------------------------
  246. CPropertyStorage::~CPropertyStorage()
  247. {
  248. HRESULT hr = S_OK;
  249. propITrace( "CPropertyStorage::~CPropertyStorage" );
  250. Lock();
  251. _ulSig = PROPERTYSTORAGE_SIGDEL; // prevent someone else deleting it
  252. // Close the property set. This causes the latest mapped stream data to be
  253. // written to the underlying stream. Errors are ignored, though, so
  254. // clients should call Commit before calling the final release, in order
  255. // to get an opportunity to recover from flush errors.
  256. if (_np != NULL)
  257. {
  258. PrClosePropertySet(_np);
  259. }
  260. // Free the mapped stream.
  261. DeleteMappedStream();
  262. // Free the Stream and/or Storage with the serialized data.
  263. // If it was opened in direct mode, then the data written
  264. // during PrClosePropertySet will be implicitely commited.
  265. // If it was opened in transacted mode, then data written
  266. // in PrClosePropertySet will be reverted and lost (of course,
  267. // to avoid this, the client would have called IPropertyStorage::Commit).
  268. RELEASE_INTERFACE( _pstmPropSet );
  269. if( _pstgPropSet != NULL )
  270. {
  271. // If we're not opened in transacted mode, call Commit.
  272. // This was added to handle NFF (NTFS property sets), in which case
  273. // we open a direct IStorage, but it actually gives us a transacted
  274. // storage, for the purpose of robustness.
  275. // We tell IsWriteable not to probe the stream if it's unsure
  276. // about the _grfMode; return FALSE in that case.
  277. if( IsWriteable(DO_NOT_PROBE) && !(STGM_TRANSACTED & _grfMode) )
  278. _pstgPropSet->Commit( STGC_DEFAULT );
  279. RELEASE_INTERFACE( _pstgPropSet );
  280. }
  281. if (_fInitCriticalSection)
  282. DeleteCriticalSection( &_CriticalSection );
  283. }
  284. //+-------------------------------------------------------------------
  285. //
  286. // Member: CPropertyStorage::QueryInterface, AddRef, Release
  287. //
  288. // Synopsis: IUnknown members
  289. //
  290. // Notes: IPropertyStorage supports IPropertyStorage and IUnknown
  291. //
  292. //--------------------------------------------------------------------
  293. HRESULT CPropertyStorage::QueryInterface( REFIID riid, void **ppvObject)
  294. {
  295. HRESULT hr;
  296. // ----------
  297. // Validation
  298. // ----------
  299. // Validate 'this'
  300. if (S_OK != (hr = ValidateRef()))
  301. return(hr);
  302. // Validate the inputs
  303. VDATEREADPTRIN( &riid, IID );
  304. VDATEPTROUT( ppvObject, void* );
  305. // -----------------
  306. // Perform the Query
  307. // -----------------
  308. *ppvObject = NULL;
  309. if( IID_IPropertyStorage == riid || IID_IUnknown == riid )
  310. {
  311. *ppvObject = static_cast<IPropertyStorage*>(this);
  312. CPropertyStorage::AddRef();
  313. }
  314. #if DBG
  315. else if( IID_IStorageTest == riid )
  316. {
  317. *ppvObject = static_cast<IStorageTest*>(this);
  318. CPropertyStorage::AddRef();
  319. }
  320. #endif // #if DBG
  321. else
  322. {
  323. hr = E_NOINTERFACE;
  324. }
  325. return(hr);
  326. }
  327. ULONG CPropertyStorage::AddRef(void)
  328. {
  329. if (S_OK != ValidateRef())
  330. return(0);
  331. InterlockedIncrement(&_cRefs);
  332. return(_cRefs);
  333. }
  334. ULONG CPropertyStorage::Release(void)
  335. {
  336. LONG lRet;
  337. if (S_OK != ValidateRef())
  338. return(0);
  339. lRet = InterlockedDecrement(&_cRefs);
  340. if (lRet == 0)
  341. {
  342. delete this; // this will do a flush if dirty
  343. }
  344. else
  345. if (lRet <0)
  346. {
  347. lRet = 0;
  348. }
  349. return(lRet);
  350. }
  351. //+-------------------------------------------------------------------
  352. //
  353. // Member: CPropertyStorage::CleanupOpenedObjects
  354. //
  355. // Synopsis: Cleans up the objects that have been opened
  356. // during the ReadMultiple. Sets all entries to
  357. // VT_ILLEGAL so that the later free doesn't try to
  358. // treat the pointers as interface pointers.
  359. //
  360. // Arguments: [avar] -- The user's array of PROPVARIANTs
  361. //
  362. // [pip] -- The array of INDIRECTPROPERTY structures
  363. // for non-simple properties.
  364. //
  365. // [cpspec] -- if 1 then no MAX_ULONG end of list marker.
  366. //
  367. // [iFailIndex] -- An index into [pip] which
  368. // indicates the non-simple property
  369. // which failed to open, and represents
  370. // the index at which the avar's begin
  371. // to be strings rather than IStream's et al.
  372. //
  373. // Notes:
  374. //
  375. //--------------------------------------------------------------------
  376. VOID CPropertyStorage::CleanupOpenedObjects(
  377. PROPVARIANT avar[],
  378. INDIRECTPROPERTY *pip,
  379. ULONG cpspec,
  380. ULONG iFailIndex)
  381. {
  382. HRESULT hr = S_OK;
  383. ULONG iStgProp;
  384. ULONG iiScan;
  385. propITrace( "CPropertyStorage::CleanupOpenedObjects" );
  386. AssertLocked();
  387. // the one that fails is passed in as ppPropVarFail.
  388. for (iiScan = 0;
  389. (iStgProp = pip[iiScan].Index) != MAX_ULONG;
  390. iiScan++)
  391. {
  392. // since we've just opened a bunch of storages we should
  393. // release them in this error case. We don't release the
  394. // one at ppPropVarFail because that one is still a string.
  395. PROPVARIANT *pPropVar = avar + iStgProp;
  396. if (iiScan < iFailIndex)
  397. {
  398. switch (pPropVar->vt)
  399. {
  400. case VT_STREAM:
  401. case VT_STREAMED_OBJECT:
  402. pPropVar->pStream->Release();
  403. break;
  404. case VT_STORAGE:
  405. case VT_STORED_OBJECT:
  406. pPropVar->pStorage->Release();
  407. break;
  408. }
  409. }
  410. else
  411. {
  412. CoTaskMemFree( pPropVar->pStream );
  413. }
  414. pPropVar->vt = VT_ILLEGAL;
  415. pPropVar->pStream = NULL; // mark pStorage and pStream as nul
  416. if (cpspec == 1)
  417. {
  418. break;
  419. }
  420. }
  421. }
  422. //+-------------------------------------------------------------------
  423. //
  424. // Member: CPropertyStorage::ReadMultiple
  425. //
  426. // Synopsis: Read properties from the property set.
  427. //
  428. // Arguments: [cpspec] -- Count of PROPSPECs in [rgpspec]
  429. // [rgpspec] -- Array of PROPSPECs
  430. // [rgpropvar] -- Array of PROPVARIANTs to be filled in
  431. // with callee allocated data.
  432. //
  433. // Returns: S_FALSE if none found
  434. // S_OK if >=1 found
  435. // FAILED(hr) otherwise.
  436. //
  437. // Notes: SPEC: Returning the same IStream* for the same
  438. // VT queried multiple times.
  439. //
  440. // PrQueryProperties has been specified to return
  441. // useful data: the count of properties found (controls
  442. // return code) and an array of indexes of non-simple
  443. // PROPSPECs (useful for simply opening the storages and
  444. // streams.) This extra returned data means we don't
  445. // have to walk the [rgpropvar] in the success cases.
  446. //
  447. //--------------------------------------------------------------------
  448. HRESULT CPropertyStorage::ReadMultiple(
  449. ULONG cpspec,
  450. const PROPSPEC rgpspec[],
  451. PROPVARIANT rgpropvar[])
  452. {
  453. NTSTATUS Status;
  454. HRESULT hr;
  455. INDIRECTPROPERTY * pip; //array for non-simple
  456. INDIRECTPROPERTY ip;
  457. ULONG cpropFound;
  458. BOOL fLocked = FALSE;
  459. propXTrace( "CPropertyStorage::ReadMultiple" );
  460. // ----------
  461. // Validation
  462. // ----------
  463. // Validate 'this'
  464. if (S_OK != (hr = Validate()))
  465. goto errRet;
  466. // Validate inputs
  467. if (0 == cpspec)
  468. {
  469. hr = S_FALSE;
  470. goto errRet;
  471. }
  472. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  473. goto errRet;
  474. if (S_OK != (hr = ValidateOutRGPROPVARIANT( cpspec, rgpropvar )))
  475. goto errRet;
  476. propTraceParameters(( "cpspec=%d, rgpspec=%08X, rgpropvar=%08X",
  477. cpspec, rgpspec, rgpropvar ));
  478. // -------------------
  479. // Read the Properties
  480. // -------------------
  481. Lock();
  482. fLocked = TRUE;
  483. if( IsReverted() )
  484. {
  485. hr = STG_E_REVERTED;
  486. goto errRet;
  487. }
  488. if( !IsReadable() )
  489. {
  490. hr = STG_E_ACCESSDENIED;
  491. goto errRet;
  492. }
  493. Status = PrQueryProperties(
  494. _np,
  495. cpspec,
  496. rgpspec,
  497. NULL, // don't want PROPID's
  498. cpspec == 1 ? (INDIRECTPROPERTY**)&ip : &pip,
  499. rgpropvar,
  500. &cpropFound);
  501. if (NT_SUCCESS(Status))
  502. {
  503. if (cpropFound != 0)
  504. {
  505. if (cpspec == 1)
  506. {
  507. if (ip.Index != MAX_ULONG)
  508. {
  509. pip = &ip;
  510. }
  511. else
  512. {
  513. pip = NULL;
  514. }
  515. }
  516. if (pip != NULL)
  517. {
  518. // we have one or more of VT_STREAM, VT_STREAMED_OBJECT,
  519. // VT_STORAGE, VT_STORED_OBJECT, VT_VERSIONED_STREAM
  520. ULONG iiScan;
  521. ULONG iStgProp;
  522. for (iiScan = 0;
  523. hr == S_OK && (iStgProp = pip[iiScan].Index) != MAX_ULONG;
  524. iiScan++ )
  525. {
  526. PROPVARIANT *pPropVar = rgpropvar + iStgProp;
  527. OLECHAR **pposzStreamOrStorageName = NULL;
  528. if (IsNonSimple() && pPropVar->pwszVal[0] != L'\0')
  529. {
  530. VOID *pStreamOrStorage = NULL;
  531. switch (pPropVar->vt)
  532. {
  533. case VT_VERSIONED_STREAM:
  534. pposzStreamOrStorageName
  535. = reinterpret_cast<OLECHAR**>( &(pPropVar->pVersionedStream->pStream) );
  536. // Fall through
  537. case VT_STREAM:
  538. case VT_STREAMED_OBJECT:
  539. if( NULL == pposzStreamOrStorageName )
  540. {
  541. pposzStreamOrStorageName
  542. = reinterpret_cast<OLECHAR**>( &(pPropVar->pStream) );
  543. }
  544. // Mask out the STGM_TRANSACTED bit because we don't
  545. // support it.
  546. hr = _pstgPropSet->OpenStream(*pposzStreamOrStorageName,
  547. NULL,
  548. GetChildOpenMode() & ~STGM_TRANSACTED,
  549. 0,
  550. (IStream**)&pStreamOrStorage);
  551. break;
  552. case VT_STORAGE:
  553. case VT_STORED_OBJECT:
  554. if( NULL == pposzStreamOrStorageName )
  555. {
  556. pposzStreamOrStorageName
  557. = reinterpret_cast<OLECHAR**>( &(pPropVar->pStorage) );
  558. }
  559. hr = _pstgPropSet->OpenStorage(*pposzStreamOrStorageName,
  560. NULL,
  561. GetChildOpenMode(),
  562. NULL,
  563. 0,
  564. (IStorage**)&pStreamOrStorage);
  565. break;
  566. default:
  567. DfpAssert( !OLESTR("Invalid non-simple property type") );
  568. hr = HRESULT_FROM_WIN32( ERROR_INTERNAL_ERROR );
  569. } // switch (pPropVar->vt)
  570. if (hr == S_OK)
  571. {
  572. // The pStream/pStorage entry currently points to a string
  573. // (the name of the stream/storage). Delete that string buffer
  574. // and put in the real stream/storage interface pointer.
  575. CoTaskMemFree( *pposzStreamOrStorageName );
  576. *pposzStreamOrStorageName = reinterpret_cast<OLECHAR*>( pStreamOrStorage );
  577. }
  578. else if (hr != STG_E_FILENOTFOUND)
  579. {
  580. // the one that fails is passed in as
  581. // iiScan and is still a string.
  582. CleanupOpenedObjects(rgpropvar, pip, cpspec, iiScan);
  583. }
  584. } // if (IsNonSimple() && pPropVar->pwszVal[0] != L'\0')
  585. else
  586. {
  587. hr = STG_E_FILENOTFOUND;
  588. }
  589. if (hr == STG_E_FILENOTFOUND)
  590. {
  591. // if the stream/storage is not found, or this is
  592. // a simple stream with VT_STORAGE etc, then treat
  593. // like the property is not found.
  594. if( VT_VERSIONED_STREAM == pPropVar->vt )
  595. {
  596. pPropVar->pVersionedStream->pStream->Release();
  597. CoTaskMemFree( pPropVar->pVersionedStream );
  598. }
  599. else
  600. {
  601. CoTaskMemFree( pPropVar->pszVal );
  602. }
  603. PropVariantInit( pPropVar );
  604. --cpropFound;
  605. hr = S_OK;
  606. }
  607. if (cpspec == 1)
  608. break;
  609. }
  610. if (cpspec != 1 && pip != NULL)
  611. CoTaskMemFree( pip );
  612. } // if (pip != NULL)
  613. if (hr != S_OK)
  614. {
  615. // we succeeded in getting the basic property types but
  616. // the non-simple stuff failed, so we zap out the whole lot
  617. // and return a complete failure
  618. FreePropVariantArray(cpspec, rgpropvar);
  619. }
  620. }
  621. if (hr == S_OK && cpropFound == 0)
  622. {
  623. hr = S_FALSE;
  624. }
  625. }
  626. else
  627. {
  628. hr = DfpNtStatusToHResult(Status);
  629. }
  630. // ----
  631. // Exit
  632. // ----
  633. errRet:
  634. if( fLocked )
  635. Unlock();
  636. if( HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == hr )
  637. propSuppressExitErrors();
  638. return(hr);
  639. }
  640. //+-------------------------------------------------------------------
  641. //
  642. // Member: CPropertyStorage::_WriteMultiple, private
  643. //
  644. // Synopsis: Write the properties to the property set. Allows
  645. // a NULL rgpropvar pointer for deletion case.
  646. //
  647. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  648. // [rgpspec] and [rgpropvar]
  649. //
  650. // [rgpspec] -- pointer to array of PROPSPECs
  651. //
  652. // [rgpropvar] -- pointer to array of PROPVARIANTs with
  653. // the values to write.
  654. //
  655. // [propidNameFirst] -- id below which not to assign
  656. // ids for named properties.
  657. //
  658. //
  659. // Returns: S_OK, -- all requested data was written.
  660. // S_FALSE -- all simple properties written, but non-simple
  661. // types (VT_STREAM etc) were ignored.
  662. // Errors --
  663. //
  664. // Modifies:
  665. //
  666. // Derivation:
  667. //
  668. // Notes: PrSetProperties has been carefully specified to return
  669. // useful information so that we can deal with the case
  670. // where a non-simple type (VT_STREAM etc) is overwritten
  671. // by a simple type.
  672. //
  673. // This routine assumes the object has been validated
  674. // and is writeable.
  675. //
  676. //--------------------------------------------------------------------
  677. HRESULT CPropertyStorage::_WriteMultiple(
  678. ULONG cpspec,
  679. const PROPSPEC rgpspec[],
  680. const PROPVARIANT rgpropvar[],
  681. PROPID propidNameFirst)
  682. {
  683. HRESULT hr;
  684. NTSTATUS Status;
  685. ULONG i;
  686. CStackPropIdArray rgPROPID;
  687. INDIRECTPROPERTY * pip;
  688. INDIRECTPROPERTY ip;
  689. if (S_OK != (hr = rgPROPID.Init(cpspec)))
  690. return(hr);
  691. propITrace( "CPropertyStorage::_WriteMultiple" );
  692. AssertLocked();
  693. Status = PrSetProperties(_np, // property set context
  694. cpspec, // property count
  695. propidNameFirst, // first propid for new named props
  696. rgpspec, // array of property specifiers
  697. &_usCodePage, // updated CodePage
  698. rgPROPID, // buffer for array of propids
  699. // the stream/storage names for indirect properties
  700. 1 == cpspec ? (INDIRECTPROPERTY**)&ip : &pip,
  701. rgpropvar);
  702. if (NT_SUCCESS(Status))
  703. {
  704. // The code page may have been modified. Update grfFlags to
  705. // reflect the current value.
  706. if( CP_WINUNICODE == _usCodePage )
  707. _grfFlags &= ~PROPSETFLAG_ANSI;
  708. else
  709. _grfFlags |= PROPSETFLAG_ANSI;
  710. // Point 'pip' to the INDIRECTPROPERTY array
  711. if (cpspec == 1)
  712. {
  713. if (ip.Index != MAX_ULONG)
  714. pip = &ip;
  715. else
  716. pip = NULL;
  717. }
  718. // If we have indirect properties, write them out now.
  719. if ( pip != NULL)
  720. {
  721. ULONG iiScan; // in this scope because we always use
  722. ULONG iStgProp; // these variables in the free memory loop below.
  723. if (IsSimple())
  724. {
  725. //
  726. // VT_STREAM was requested to be written and this
  727. // is a "SIMPLE" property set.
  728. //
  729. hr = STG_E_PROPSETMISMATCHED;
  730. }
  731. else
  732. {
  733. //
  734. // Two cases now:
  735. // 1. Wrote a simple over a non-simple -- must delete the
  736. // old non-simple.
  737. // 2. Wrote a non-simple -- must actually copy data into it.
  738. //
  739. for (iiScan = 0;
  740. hr == S_OK &&
  741. (iStgProp = pip[iiScan].Index) != MAX_ULONG;
  742. iiScan++ )
  743. {
  744. OLECHAR oszStdPropName[sizeof("prop")+10+1];
  745. const OLECHAR *poszPropName;
  746. const PROPVARIANT *pPropVar = rgpropvar + iStgProp;
  747. IStream *pstmFrom = NULL;
  748. poszPropName = static_cast<LPOLESTR>(pip[iiScan].poszName);
  749. if( NULL == poszPropName )
  750. {
  751. DfpAssert((LONG) iStgProp >= 0 && iStgProp < cpspec);
  752. PROPGENPROPERTYNAME( oszStdPropName, rgPROPID[iStgProp] );
  753. poszPropName = oszStdPropName;
  754. }
  755. DfpAssert( NULL != poszPropName );
  756. switch (rgpropvar == NULL ? VT_ILLEGAL : pPropVar->vt)
  757. {
  758. case VT_VERSIONED_STREAM:
  759. case VT_STREAM:
  760. case VT_STREAMED_OBJECT:
  761. {
  762. IStream *pstm;
  763. int i=0;
  764. if( VT_VERSIONED_STREAM == pPropVar->vt )
  765. pstmFrom = pPropVar->pVersionedStream->pStream;
  766. else
  767. pstmFrom = pPropVar->pStream;
  768. while (i<=1)
  769. {
  770. hr = _pstgPropSet->CreateStream(poszPropName,
  771. GetChildCreateMode() & ~STGM_TRANSACTED,
  772. 0, 0, &pstm);
  773. if (hr == S_OK)
  774. {
  775. if( NULL != pstmFrom )
  776. {
  777. ULARGE_INTEGER uli;
  778. memset(&uli, -1, sizeof(uli));
  779. hr = pstmFrom->CopyTo(pstm, uli, NULL, NULL);
  780. }
  781. pstm->Release();
  782. break;
  783. }
  784. else
  785. if (hr != STG_E_FILEALREADYEXISTS)
  786. {
  787. break;
  788. }
  789. else
  790. if (i == 0)
  791. {
  792. _pstgPropSet->DestroyElement(poszPropName);
  793. }
  794. i++;
  795. }
  796. }
  797. break;
  798. case VT_STORAGE:
  799. case VT_STORED_OBJECT:
  800. {
  801. IStorage *pstg;
  802. int i=0;
  803. while (i<=1)
  804. {
  805. hr = _pstgPropSet->CreateStorage(poszPropName,
  806. GetChildCreateMode(),
  807. 0,
  808. 0,
  809. &pstg);
  810. if (hr == S_OK)
  811. {
  812. if (pPropVar->pStorage != NULL)
  813. {
  814. hr = pPropVar->pStorage->CopyTo(0, NULL,
  815. NULL, pstg);
  816. }
  817. pstg->Release();
  818. break;
  819. }
  820. else
  821. if (hr != STG_E_FILEALREADYEXISTS)
  822. {
  823. break;
  824. }
  825. else
  826. if (i == 0)
  827. {
  828. _pstgPropSet->DestroyElement(poszPropName);
  829. }
  830. i++;
  831. }
  832. }
  833. break;
  834. default:
  835. //
  836. // Any other VT_ type is simple and therefore
  837. // was a non-simple overwritten by a simple.
  838. //
  839. hr = _pstgPropSet->DestroyElement( poszPropName );
  840. break;
  841. }
  842. if (cpspec == 1)
  843. break;
  844. } // for (iiScan = 0; ...
  845. } // if (IsSimple())
  846. // In both the success and failure cases we do this cleanup.
  847. for (iiScan = 0; pip[iiScan].Index != MAX_ULONG; iiScan++ )
  848. {
  849. if (pip[iiScan].poszName != NULL)
  850. CoTaskMemFree( pip[iiScan].poszName );
  851. if (cpspec == 1)
  852. break;
  853. }
  854. if (cpspec != 1 && pip != NULL)
  855. CoTaskMemFree( pip );
  856. } // if ( pip != NULL)
  857. else
  858. {
  859. //
  860. // No VT_STREAM etc was requested to be written.
  861. // and no simple property overwrote a non-simple one.
  862. }
  863. } // if (NT_SUCCESS(Status))
  864. else
  865. {
  866. hr = DfpNtStatusToHResult(Status);
  867. }
  868. if( HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == hr )
  869. propSuppressExitErrors();
  870. return(hr);
  871. }
  872. //+-------------------------------------------------------------------
  873. //
  874. // Member: CPropertyStorage::WriteMultiple
  875. //
  876. // Synopsis: Write properties.
  877. //
  878. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  879. // [rgpspec] and [rgpropvar]
  880. // [rgpspec] -- pointer to array of PROPSPECs
  881. // [rgpropvar] -- pointer to array of PROPVARIANTs with
  882. // the values to write.
  883. // [propidNameFirst] -- id below which not to assign
  884. // ids for named properties.
  885. //
  886. // Returns: S_OK, -- all requested data was written.
  887. // S_FALSE -- all simple properties written, but non-simple
  888. // types (VT_STREAM etc) were ignored.
  889. // Errors --
  890. //
  891. // Notes: Checks that rgpropvar is not NULL, then calls
  892. // _WriteMultiple.
  893. //
  894. //--------------------------------------------------------------------
  895. HRESULT CPropertyStorage::WriteMultiple(
  896. ULONG cpspec,
  897. const PROPSPEC rgpspec[],
  898. const PROPVARIANT rgpropvar[],
  899. PROPID propidNameFirst)
  900. {
  901. HRESULT hr;
  902. BOOL fLocked = FALSE;
  903. propXTrace( "CPropertyStorage::WriteMultiple" );
  904. // ----------
  905. // Validation
  906. // ----------
  907. // Validate 'this'
  908. if (S_OK != (hr = Validate()))
  909. goto errRet;
  910. // Validate the inputs
  911. if (0 == cpspec)
  912. {
  913. hr = S_OK;
  914. goto errRet;
  915. }
  916. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  917. goto errRet;
  918. if (S_OK != (hr = ValidateInRGPROPVARIANT( cpspec, rgpropvar )))
  919. goto errRet;
  920. propTraceParameters(( "cpspec=%d, rgpspec=%08X, rgpropvar=%08X, propidNameFirst=%d",
  921. cpspec, rgpspec, rgpropvar, propidNameFirst ));
  922. // Ensure we understand all the VarTypes in the input array.
  923. hr = ValidateVTs( cpspec, rgpropvar );
  924. if( FAILED(hr) ) goto errRet;
  925. // --------------------
  926. // Write the Properties
  927. // --------------------
  928. Lock();
  929. fLocked = TRUE;
  930. if( IsReverted() )
  931. {
  932. hr = STG_E_REVERTED;
  933. goto errRet;
  934. }
  935. if( !IsWriteable() )
  936. {
  937. hr = STG_E_ACCESSDENIED;
  938. goto errRet;
  939. }
  940. hr = _WriteMultiple(cpspec, rgpspec, rgpropvar, propidNameFirst);
  941. if (hr == STG_E_INSUFFICIENTMEMORY)
  942. {
  943. hr = S_OK;
  944. for (ULONG i=0; hr == S_OK && i < cpspec; i++)
  945. {
  946. hr = _WriteMultiple(1, rgpspec+i, rgpropvar+i, propidNameFirst);
  947. if( FAILED(hr) ) goto errRet;
  948. }
  949. }
  950. if( FAILED(hr) ) goto errRet;
  951. // If buffering is not desired, flush the property storage
  952. // to the underlying Stream.
  953. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  954. {
  955. NTSTATUS Status = PrFlushPropertySet(_np);
  956. if (!NT_SUCCESS(Status))
  957. {
  958. hr = DfpNtStatusToHResult(Status);
  959. }
  960. }
  961. // ----
  962. // Exit
  963. // ----
  964. errRet:
  965. if( fLocked )
  966. Unlock();
  967. if( HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == hr )
  968. propSuppressExitErrors();
  969. return(hr);
  970. }
  971. //+-------------------------------------------------------------------
  972. //
  973. // Member: CPropertyStorage::DeleteMultiple
  974. //
  975. // Synopsis: Delete properties.
  976. //
  977. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  978. // [rgpspec] and [rgpropvar]
  979. // [rgpspec] -- pointer to array of PROPSPECs
  980. //
  981. // Returns: S_OK, -- all requested data was deleted.
  982. // S_FALSE -- all simple properties written, but non-simple
  983. // types (VT_STREAM etc) were ignored.
  984. // Errors --
  985. //
  986. // Notes: Checks that rgpropvar is not NULL, then calls
  987. // _WriteMultiple.
  988. //
  989. //--------------------------------------------------------------------
  990. HRESULT CPropertyStorage::DeleteMultiple(
  991. ULONG cpspec,
  992. const PROPSPEC rgpspec[])
  993. {
  994. HRESULT hr;
  995. BOOL fLocked = FALSE;
  996. propXTrace( "CPropertyStorage::DeleteMultiple" );
  997. // ----------
  998. // Validation
  999. // ----------
  1000. // Validate 'this'
  1001. if (S_OK != (hr = Validate()))
  1002. goto errRet;
  1003. // Validate the inputs
  1004. if (0 == cpspec)
  1005. {
  1006. hr = S_OK;
  1007. goto errRet;
  1008. }
  1009. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  1010. goto errRet;
  1011. propTraceParameters(( "cpspec=%d, rgpspec=%08X", cpspec, rgpspec ));
  1012. // ---------------------
  1013. // Delete the Properties
  1014. // ---------------------
  1015. Lock();
  1016. fLocked = TRUE;
  1017. if( IsReverted() )
  1018. {
  1019. hr = STG_E_REVERTED;
  1020. goto errRet;
  1021. }
  1022. if( !IsWriteable() )
  1023. {
  1024. hr = STG_E_ACCESSDENIED;
  1025. goto errRet;
  1026. }
  1027. hr = _WriteMultiple(cpspec, rgpspec, NULL, 2);
  1028. if (hr == STG_E_INSUFFICIENTMEMORY)
  1029. {
  1030. hr = S_OK;
  1031. for (ULONG i=0; hr == S_OK && i < cpspec; i++)
  1032. {
  1033. hr = _WriteMultiple(1, rgpspec+i, NULL, 2);
  1034. if( FAILED(hr) ) goto errRet;
  1035. }
  1036. }
  1037. if( FAILED(hr) ) goto errRet;
  1038. // If buffering is not desired, flush the property storage
  1039. // to the underlying Stream.
  1040. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  1041. {
  1042. NTSTATUS Status = PrFlushPropertySet(_np);
  1043. if (!NT_SUCCESS(Status))
  1044. {
  1045. hr = DfpNtStatusToHResult(Status);
  1046. }
  1047. }
  1048. // ----
  1049. // Exit
  1050. // ----
  1051. errRet:
  1052. if( fLocked )
  1053. Unlock();
  1054. return hr;
  1055. }
  1056. //+-------------------------------------------------------------------
  1057. //
  1058. // Member: CPropertyStorage::ReadPropertyNames
  1059. //
  1060. // Synopsis: Attempt to read names for all identified properties.
  1061. //
  1062. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  1063. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  1064. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  1065. //
  1066. // Returns: S_OK -- success, one or more names returned
  1067. // S_FALSE -- success, no names returned
  1068. // STG_E_INVALIDHEADER -- no propid->name mapping property
  1069. // other errors -- STG_E_INSUFFICIENTMEMORY etc
  1070. //
  1071. //--------------------------------------------------------------------
  1072. HRESULT CPropertyStorage::ReadPropertyNames(
  1073. ULONG cpropid,
  1074. const PROPID rgpropid[],
  1075. LPOLESTR rglpwstrName[])
  1076. {
  1077. HRESULT hr;
  1078. NTSTATUS Status;
  1079. BOOL fLocked = FALSE;
  1080. propXTrace( "CPropertyStorage::ReadPropertyNames" );
  1081. // --------
  1082. // Validate
  1083. // --------
  1084. // Validate 'this'
  1085. if (S_OK != (hr = Validate()))
  1086. goto errRet;
  1087. // Validate the inputs
  1088. if (0 == cpropid)
  1089. {
  1090. hr = S_FALSE;
  1091. goto errRet;
  1092. }
  1093. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  1094. goto errRet;
  1095. if (S_OK != (hr = ValidateOutRGLPOLESTR( cpropid, rglpwstrName )))
  1096. goto errRet;
  1097. propTraceParameters(( "cpropid=%d, rgpropid=%08X, rglpwstrName=%08X",
  1098. cpropid, rgpropid, rglpwstrName ));
  1099. // --------------
  1100. // Read the Names
  1101. // --------------
  1102. Lock();
  1103. fLocked = TRUE;
  1104. if( IsReverted() )
  1105. {
  1106. hr = STG_E_REVERTED;
  1107. goto errRet;
  1108. }
  1109. if( !IsReadable() )
  1110. {
  1111. hr = STG_E_ACCESSDENIED;
  1112. goto errRet;
  1113. }
  1114. Status = PrQueryPropertyNames(_np, cpropid, rgpropid, rglpwstrName);
  1115. if (Status == STATUS_NOT_FOUND)
  1116. hr = STG_E_INVALIDHEADER;
  1117. else
  1118. if (Status == STATUS_BUFFER_ALL_ZEROS)
  1119. hr = S_FALSE;
  1120. else
  1121. if (!NT_SUCCESS(Status))
  1122. hr = DfpNtStatusToHResult(Status);
  1123. // ----
  1124. // Exit
  1125. // ----
  1126. errRet:
  1127. if( fLocked )
  1128. Unlock();
  1129. return hr;
  1130. }
  1131. //+-------------------------------------------------------------------
  1132. //
  1133. // Member: CPropertyStorage::_WritePropertyNames
  1134. //
  1135. // Synopsis: Internal function used by WritePropertyNames and
  1136. // DeletePropertyNames.
  1137. //
  1138. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  1139. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  1140. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  1141. //
  1142. // Returns: S_OK if successful, otherwise error code.
  1143. //
  1144. //--------------------------------------------------------------------
  1145. HRESULT CPropertyStorage::_WritePropertyNames(
  1146. ULONG cpropid,
  1147. const PROPID rgpropid[],
  1148. const LPOLESTR rglpwstrName[])
  1149. {
  1150. NTSTATUS Status;
  1151. AssertLocked();
  1152. Status = PrSetPropertyNames(_np, cpropid, rgpropid, (OLECHAR const * const *) rglpwstrName);
  1153. return NT_SUCCESS(Status) ? S_OK : DfpNtStatusToHResult(Status);
  1154. }
  1155. //+-------------------------------------------------------------------
  1156. //
  1157. // Member: CPropertyStorage::WritePropertyNames
  1158. //
  1159. // Synopsis: Attempt to write names for all identified properties.
  1160. //
  1161. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  1162. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  1163. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  1164. //
  1165. // Returns: S_OK -- success, otherwise error code.
  1166. //
  1167. //--------------------------------------------------------------------
  1168. HRESULT CPropertyStorage::WritePropertyNames(
  1169. ULONG cpropid,
  1170. const PROPID rgpropid[],
  1171. const LPOLESTR rglpwstrName[])
  1172. {
  1173. HRESULT hr;
  1174. BOOL fLocked = FALSE;
  1175. propXTrace( "CPropertyStorage::WritePropertyNames" );
  1176. // ----------
  1177. // Validation
  1178. // ----------
  1179. // Validate 'this'
  1180. if (S_OK != (hr = Validate()))
  1181. goto errRet;
  1182. // Validate inputs
  1183. if (0 == cpropid)
  1184. {
  1185. hr = S_OK;
  1186. goto errRet;
  1187. }
  1188. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  1189. goto errRet;
  1190. if (S_OK != (hr = ValidateInRGLPOLESTR( cpropid, rglpwstrName )))
  1191. goto errRet;
  1192. propTraceParameters(( "cpropid=%d, rgpropid=%08X, rglpwstrName=%08X",
  1193. cpropid, rgpropid, rglpwstrName ));
  1194. // ---------------
  1195. // Write the Names
  1196. // ---------------
  1197. Lock();
  1198. fLocked = TRUE;
  1199. if( IsReverted() )
  1200. {
  1201. hr = STG_E_REVERTED;
  1202. goto errRet;
  1203. }
  1204. if( !IsWriteable() )
  1205. {
  1206. hr = STG_E_ACCESSDENIED;
  1207. goto errRet;
  1208. }
  1209. hr = _WritePropertyNames(cpropid, rgpropid, rglpwstrName);
  1210. if (hr == STG_E_INSUFFICIENTMEMORY)
  1211. {
  1212. hr = S_OK;
  1213. for (ULONG i=0; hr == S_OK && i < cpropid; i++)
  1214. {
  1215. hr = _WritePropertyNames(1, rgpropid+i, rglpwstrName+i);
  1216. if( FAILED(hr) ) goto errRet;
  1217. }
  1218. }
  1219. if( FAILED(hr) ) goto errRet;
  1220. // If buffering is not desired, flush the property storage
  1221. // to the underlying Stream.
  1222. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  1223. {
  1224. NTSTATUS Status = PrFlushPropertySet(_np);
  1225. if (!NT_SUCCESS(Status))
  1226. {
  1227. hr = DfpNtStatusToHResult(Status);
  1228. }
  1229. }
  1230. // ----
  1231. // Exit
  1232. // ----
  1233. errRet:
  1234. if( fLocked )
  1235. Unlock();
  1236. return hr;
  1237. }
  1238. //+-------------------------------------------------------------------
  1239. //
  1240. // Member: CPropertyStorage::DeletePropertyNames
  1241. //
  1242. // Synopsis: Attempt to delete names for all identified properties.
  1243. //
  1244. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  1245. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  1246. //
  1247. // Returns: S_OK -- success, otherwise error.
  1248. //
  1249. //--------------------------------------------------------------------
  1250. HRESULT CPropertyStorage::DeletePropertyNames(
  1251. ULONG cpropid,
  1252. const PROPID rgpropid[])
  1253. {
  1254. HRESULT hr;
  1255. BOOL fLocked = FALSE;
  1256. propXTrace( "CPropertyStorage::DeletePropertyNames" );
  1257. // ----------
  1258. // Validation
  1259. // ----------
  1260. // Validate 'this'
  1261. if (S_OK != (hr = Validate()))
  1262. goto errRet;
  1263. // Validate the inputs
  1264. if( 0 == cpropid )
  1265. {
  1266. hr = S_OK;
  1267. goto errRet;
  1268. }
  1269. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  1270. goto errRet;
  1271. propTraceParameters(( "cpropid=%d, rgpropid=%08X)", cpropid, rgpropid ));
  1272. // ----------------
  1273. // Delete the Names
  1274. // ----------------
  1275. Lock();
  1276. fLocked = TRUE;
  1277. if( IsReverted() )
  1278. {
  1279. hr = STG_E_REVERTED;
  1280. goto errRet;
  1281. }
  1282. if( !IsWriteable() )
  1283. {
  1284. hr = STG_E_ACCESSDENIED;
  1285. goto errRet;
  1286. }
  1287. hr = _WritePropertyNames(cpropid, rgpropid, NULL);
  1288. if (hr == STG_E_INSUFFICIENTMEMORY)
  1289. {
  1290. hr = S_OK;
  1291. for (ULONG i=0; hr == S_OK && i < cpropid; i++)
  1292. {
  1293. hr = _WritePropertyNames(1, rgpropid+i, NULL);
  1294. if( FAILED(hr) ) goto errRet;
  1295. }
  1296. }
  1297. if( FAILED(hr) ) goto errRet;
  1298. // If buffering is not desired, flush the property storage
  1299. // to the underlying Stream.
  1300. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  1301. {
  1302. NTSTATUS Status = PrFlushPropertySet(_np);
  1303. if (!NT_SUCCESS(Status))
  1304. {
  1305. hr = DfpNtStatusToHResult(Status);
  1306. }
  1307. }
  1308. // ----
  1309. // Exit
  1310. // ----
  1311. errRet:
  1312. if( fLocked )
  1313. Unlock();
  1314. return hr;
  1315. }
  1316. //+-------------------------------------------------------------------
  1317. //
  1318. // Member: CPropertyStorage::Commit
  1319. //
  1320. // Synopsis: Flush and/or commit the property set
  1321. //
  1322. // Arguments: [grfCommittFlags] -- Commit flags.
  1323. //
  1324. // Returns: S_OK -- success, otherwise error.
  1325. //
  1326. // Notes: For both simple and non-simple, this flushes the
  1327. // memory image to disk subsystem. In addition,
  1328. // for non-simple transacted-mode property sets, this
  1329. // performs a commit on the property set.
  1330. //
  1331. //--------------------------------------------------------------------
  1332. HRESULT CPropertyStorage::Commit(DWORD grfCommitFlags)
  1333. {
  1334. HRESULT hr;
  1335. NTSTATUS Status;
  1336. BOOL fLocked = FALSE;
  1337. propXTrace( "CPropertyStorage::Commit" );
  1338. // ----------
  1339. // Validation
  1340. // ----------
  1341. // Validate 'this'
  1342. if (S_OK != (hr = Validate()))
  1343. goto errRet;
  1344. // Validate the inputs
  1345. if (S_OK != (hr = VerifyCommitFlags(grfCommitFlags)))
  1346. goto errRet;
  1347. propTraceParameters(( "grfCommitFlags=%08X", grfCommitFlags ));
  1348. // --------------------------
  1349. // Commit the PropertyStorage
  1350. // --------------------------
  1351. Lock();
  1352. fLocked = TRUE;
  1353. if( IsReverted() )
  1354. {
  1355. hr = STG_E_REVERTED;
  1356. goto errRet;
  1357. }
  1358. if( !IsWriteable() )
  1359. {
  1360. hr = STG_E_ACCESSDENIED;
  1361. goto errRet;
  1362. }
  1363. Status = PrFlushPropertySet(_np);
  1364. if (!NT_SUCCESS(Status))
  1365. {
  1366. hr = DfpNtStatusToHResult(Status);
  1367. }
  1368. if (IsNonSimple())
  1369. {
  1370. if (hr == S_OK)
  1371. hr = _pstgPropSet->Commit(grfCommitFlags);
  1372. }
  1373. // ----
  1374. // Exit
  1375. // ----
  1376. errRet:
  1377. if( fLocked )
  1378. Unlock();
  1379. return(hr);
  1380. }
  1381. //+-------------------------------------------------------------------
  1382. //
  1383. // Member: CPropertyStorage::Revert
  1384. //
  1385. // Synopsis: For non-simple property sets, revert it.
  1386. //
  1387. // Returns: S_OK if successful. STG_E_UNIMPLEMENTEDFUNCTION for
  1388. // simple property sets.
  1389. //
  1390. // Notes: For non-simple property sets, call the underlying
  1391. // storage's Revert and re-open the 'contents' stream.
  1392. //
  1393. //--------------------------------------------------------------------
  1394. HRESULT CPropertyStorage::Revert()
  1395. {
  1396. HRESULT hr;
  1397. BOOL fLocked = FALSE;
  1398. propXTrace( "CPropertyStorage::Revert" );
  1399. if (S_OK != (hr = Validate()))
  1400. goto errRet;
  1401. Lock(); fLocked = TRUE;
  1402. if (IsNonSimple())
  1403. {
  1404. hr = _pstgPropSet->Revert();
  1405. if (hr == S_OK)
  1406. {
  1407. PrClosePropertySet(_np);
  1408. _np = NULL;
  1409. _pstmPropSet->Release();
  1410. _pstmPropSet = NULL;
  1411. DeleteMappedStream();
  1412. // if one of these fails then this object becomes invalid (zombie)
  1413. // Mask out the STGM_TRANSACTED bit because we don't support it.
  1414. hr = _pstgPropSet->OpenStream(g_oszPropertyContentsStreamName, NULL,
  1415. GetChildOpenMode() & ~STGM_TRANSACTED,
  1416. 0, &_pstmPropSet);
  1417. if (hr == S_OK)
  1418. {
  1419. // Initialize the property set. If this property set is the 2nd section
  1420. // of the DocumentSummaryInformation property set (used by Office),
  1421. // then we must specify the FMTID.
  1422. hr = InitializePropertyStream(
  1423. _fUserDefinedProperties ? &FMTID_UserDefinedProperties : NULL,
  1424. NULL, // pguid
  1425. OPEN_PROPSTREAM );
  1426. }
  1427. if (hr != S_OK)
  1428. {
  1429. _ulSig = PROPERTYSTORAGE_SIGZOMBIE;
  1430. }
  1431. }
  1432. }
  1433. else
  1434. hr = S_OK;
  1435. errRet:
  1436. if( fLocked )
  1437. Unlock();
  1438. return(hr);
  1439. }
  1440. //+-------------------------------------------------------------------
  1441. //
  1442. // Member: CPropertyStorage::Enum
  1443. //
  1444. // Synopsis: Create an enumerator over the property set.
  1445. //
  1446. // Arguments: [ppenum] -- where to return the IEnumSTATPROPSTG *
  1447. //
  1448. // Returns: S_OK or error.
  1449. //
  1450. // Notes: The constructor of CEnumSTATPROPSTG creates a
  1451. // CStatArray which reads the entire property set and
  1452. // which can be shared when IEnumSTATPROPSTG::Clone is
  1453. // used.
  1454. //
  1455. //--------------------------------------------------------------------
  1456. HRESULT CPropertyStorage::Enum(IEnumSTATPROPSTG ** ppenum)
  1457. {
  1458. HRESULT hr;
  1459. BOOL fLocked = FALSE;
  1460. IStatArray *psa = NULL;
  1461. IEnumSTATPROPSTG *penum = NULL;
  1462. propXTrace( "CPropertyStorage::Enum" );
  1463. // ----------
  1464. // Validation
  1465. // ----------
  1466. // Validate 'this'
  1467. if (S_OK != (hr = Validate()))
  1468. return(hr);
  1469. // Validate the inputs
  1470. VDATEPTROUT( ppenum, IEnumSTATPROPSTG* );
  1471. *ppenum = NULL;
  1472. propTraceParameters(( "ppenum=%p", ppenum ));
  1473. Lock(); fLocked = TRUE;
  1474. if( IsReverted() )
  1475. {
  1476. hr = STG_E_REVERTED;
  1477. goto Exit;
  1478. }
  1479. if( !IsReadable() )
  1480. {
  1481. hr = STG_E_ACCESSDENIED;
  1482. goto Exit;
  1483. }
  1484. // ----------------------
  1485. // Create the Enumeration
  1486. // ----------------------
  1487. psa = (IStatArray*) new CStatArray( _np, &hr );
  1488. if( NULL == psa )
  1489. hr = STG_E_INSUFFICIENTMEMORY;
  1490. if( FAILED(hr) ) goto Exit;
  1491. penum = new CEnumSTATPROPSTG( psa );
  1492. if( NULL == penum )
  1493. {
  1494. hr = STG_E_INSUFFICIENTMEMORY;
  1495. goto Exit;
  1496. }
  1497. *ppenum = penum;
  1498. penum = NULL;
  1499. // ----
  1500. // Exit
  1501. // ----
  1502. Exit:
  1503. RELEASE_INTERFACE( penum );
  1504. RELEASE_INTERFACE( psa );
  1505. if( fLocked )
  1506. Unlock();
  1507. return(hr);
  1508. }
  1509. //+-------------------------------------------------------------------
  1510. //
  1511. // Member: CPropertyStorage::SetTimes
  1512. //
  1513. // Synopsis: Set the given times on the underlying storage
  1514. //
  1515. // Arguments: [pctime] -- creation time
  1516. // [patime[ -- access time
  1517. // [pmtime] -- modify time
  1518. //
  1519. // Returns: S_OK or error.
  1520. //
  1521. // Notes:
  1522. // (non-simple only) Only the times supported by the
  1523. // underlying docfile implementation are
  1524. // supported.
  1525. //
  1526. //--------------------------------------------------------------------
  1527. HRESULT CPropertyStorage::SetTimes(
  1528. FILETIME const * pctime,
  1529. FILETIME const * patime,
  1530. FILETIME const * pmtime)
  1531. {
  1532. HRESULT hr;
  1533. BOOL fLocked = FALSE;
  1534. propXTrace( "CPropertyStorage::SetTimes" );
  1535. // ----------
  1536. // Validation
  1537. // ----------
  1538. // Validate 'this'
  1539. if (S_OK != (hr = Validate()))
  1540. goto errRet;
  1541. // Validate the inputs
  1542. VDATEPTRIN_LABEL( pctime, FILETIME, errRet, hr );
  1543. VDATEPTRIN_LABEL( patime, FILETIME, errRet, hr );
  1544. VDATEPTRIN_LABEL( pmtime, FILETIME, errRet, hr );
  1545. propTraceParameters(( "pctime=%08x:%08x, patime=%08x:%08x, pmtime=%08x:%08x",
  1546. pctime->dwHighDateTime, pctime->dwLowDateTime,
  1547. patime->dwHighDateTime, patime->dwLowDateTime,
  1548. pmtime->dwHighDateTime, pmtime->dwLowDateTime ));
  1549. Lock();
  1550. fLocked = TRUE;
  1551. if( IsReverted() )
  1552. {
  1553. hr = STG_E_REVERTED;
  1554. goto errRet;
  1555. }
  1556. if( !IsWriteable() )
  1557. {
  1558. hr = STG_E_ACCESSDENIED;
  1559. goto errRet;
  1560. }
  1561. // -------------
  1562. // Set the Times
  1563. // -------------
  1564. if (IsNonSimple())
  1565. {
  1566. hr = _pstgPropSet->SetElementTimes(
  1567. NULL,
  1568. pctime,
  1569. patime,
  1570. pmtime);
  1571. }
  1572. if( FAILED(hr) ) goto errRet;
  1573. // ----
  1574. // Exit
  1575. // ----
  1576. errRet:
  1577. if( fLocked )
  1578. Unlock();
  1579. return(hr);
  1580. }
  1581. //+-------------------------------------------------------------------
  1582. //
  1583. // Member: CPropertyStorage::SetClass
  1584. //
  1585. // Synopsis: Sets the class of the property set.
  1586. //
  1587. // Arguments: [clsid] -- class id to set.
  1588. //
  1589. // Returns: S_OK or error.
  1590. //
  1591. // Notes: If non-simple, the underlying storage has SetClass
  1592. // called. Both simple and non-simple will have
  1593. // clsid set into the property set stream.
  1594. //
  1595. //--------------------------------------------------------------------
  1596. HRESULT CPropertyStorage::SetClass(REFCLSID clsid)
  1597. {
  1598. HRESULT hr;
  1599. NTSTATUS Status;
  1600. BOOL fLocked = FALSE;
  1601. DBGBUF(buf);
  1602. propXTrace( "CPropertyStorage::SetClass" );
  1603. // ----------
  1604. // Validation
  1605. // ----------
  1606. // Validate 'this'
  1607. if (S_OK != (hr = Validate()))
  1608. goto errRet;
  1609. // Validate the inputs
  1610. GEN_VDATEREADPTRIN_LABEL(&clsid, CLSID, E_INVALIDARG, errRet, hr);
  1611. propTraceParameters(( "clsid=%s", DbgFmtId(clsid, buf) ));
  1612. // -------------
  1613. // Set the CLSID
  1614. // -------------
  1615. Lock();
  1616. fLocked = TRUE;
  1617. if( IsReverted() )
  1618. {
  1619. hr = STG_E_REVERTED;
  1620. goto errRet;
  1621. }
  1622. if( !IsWriteable() )
  1623. {
  1624. hr = STG_E_ACCESSDENIED;
  1625. goto errRet;
  1626. }
  1627. // Set it in the property set header
  1628. Status = PrSetPropertySetClassId(_np, &clsid);
  1629. if (NT_SUCCESS(Status))
  1630. {
  1631. // And if this is an IStorage, set it there as well.
  1632. if (IsNonSimple())
  1633. {
  1634. hr = _pstgPropSet->SetClass(clsid);
  1635. }
  1636. }
  1637. else
  1638. {
  1639. hr = DfpNtStatusToHResult(Status);
  1640. }
  1641. if( FAILED(hr) ) goto errRet;
  1642. // If buffering is not desired, flush the property storage
  1643. // to the underlying Stream.
  1644. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  1645. {
  1646. NTSTATUS Status = PrFlushPropertySet(_np);
  1647. if (!NT_SUCCESS(Status))
  1648. {
  1649. hr = DfpNtStatusToHResult(Status);
  1650. }
  1651. }
  1652. // ----
  1653. // Exit
  1654. // ----
  1655. errRet:
  1656. if( fLocked )
  1657. Unlock();
  1658. return(hr);
  1659. }
  1660. //+-------------------------------------------------------------------
  1661. //
  1662. // Member: CPropertyStorage::Stat
  1663. //
  1664. // Synopsis: Get STATPROPSETSTG about the property set.
  1665. //
  1666. // Arguments: [p] -- STATPROPSETSTG *
  1667. //
  1668. // Returns: S_OK if successful, error otherwise. On failure,
  1669. // *p is all zeros.
  1670. //
  1671. // Notes: See spec. Gets times from underlying storage or stream
  1672. // using IStorage or IStream ::Stat.
  1673. //
  1674. //--------------------------------------------------------------------
  1675. HRESULT CPropertyStorage::Stat(STATPROPSETSTG * pstatpropsetstg)
  1676. {
  1677. HRESULT hr;
  1678. NTSTATUS Status;
  1679. BOOL fLocked = FALSE;
  1680. propXTrace( "CPropertyStorage::Stat" )
  1681. // ----------
  1682. // Validation
  1683. // ----------
  1684. // Validate 'this'
  1685. if (S_OK != (hr = Validate()))
  1686. goto errRet;
  1687. // Validate inputs
  1688. VDATEPTROUT_LABEL(pstatpropsetstg, STATPROPSETSTG, errRet, hr);
  1689. propTraceParameters(( "STATPROPSETSTG *p = %08X", pstatpropsetstg ));
  1690. // ------------
  1691. // Get the Stat
  1692. // ------------
  1693. Lock();
  1694. fLocked = TRUE;
  1695. if( IsReverted() )
  1696. {
  1697. hr = STG_E_REVERTED;
  1698. goto errRet;
  1699. }
  1700. if( !IsReadable() )
  1701. {
  1702. hr = STG_E_ACCESSDENIED;
  1703. goto errRet;
  1704. }
  1705. ZeroMemory(pstatpropsetstg, sizeof(*pstatpropsetstg));
  1706. // returns mtime, ansi flag, clsid, fmtid
  1707. Status = PrQueryPropertySet(_np, pstatpropsetstg);
  1708. if (NT_SUCCESS(Status))
  1709. {
  1710. STATSTG statstg;
  1711. hr = S_OK;
  1712. if( NULL != _pstgPropSet || NULL != _pstmPropSet )
  1713. {
  1714. if (IsNonSimple())
  1715. {
  1716. hr = _pstgPropSet->Stat(&statstg, STATFLAG_NONAME);
  1717. }
  1718. else
  1719. {
  1720. hr = _pstmPropSet->Stat(&statstg, STATFLAG_NONAME);
  1721. }
  1722. if (hr == S_OK)
  1723. {
  1724. pstatpropsetstg->mtime = statstg.mtime;
  1725. pstatpropsetstg->ctime = statstg.ctime;
  1726. pstatpropsetstg->atime = statstg.atime;
  1727. pstatpropsetstg->grfFlags = _grfFlags;
  1728. pstatpropsetstg->dwOSVersion = _dwOSVersion;
  1729. }
  1730. }
  1731. }
  1732. else
  1733. {
  1734. hr = DfpNtStatusToHResult(Status);
  1735. }
  1736. if (FAILED(hr))
  1737. {
  1738. ZeroMemory(pstatpropsetstg, sizeof(*pstatpropsetstg));
  1739. }
  1740. // ----
  1741. // Exit
  1742. // ----
  1743. errRet:
  1744. if( fLocked )
  1745. Unlock();
  1746. return(hr);
  1747. }
  1748. //+-------------------------------------------------------------------
  1749. //
  1750. // Member: CStatArray::CStatArray
  1751. //
  1752. //--------------------------------------------------------------------
  1753. CStatArray::CStatArray(NTPROP np, HRESULT *phr)
  1754. {
  1755. NTSTATUS Status;
  1756. ULONG ulKeyZero;
  1757. ULONG cpropAllocated;
  1758. _cpropActual = 0;
  1759. _cRefs = 1;
  1760. _psps = NULL;
  1761. do
  1762. {
  1763. // when *pkey == 0, *pcprop == MAXULONG, aprs == NULL and asps == NULL on input,
  1764. // *pcprop will be the total count of properties in the enumeration set. OLE needs to
  1765. // allocate memory and enumerate out of the cached PROPID+propname list.
  1766. ulKeyZero = 0;
  1767. _cpropActual = MAX_ULONG;
  1768. CoTaskMemFree( _psps );
  1769. _psps = NULL;
  1770. Status = PrEnumerateProperties(
  1771. np,
  1772. ENUMPROP_NONAMES,
  1773. &ulKeyZero,
  1774. &_cpropActual,
  1775. NULL, // aprs
  1776. NULL);
  1777. if (!NT_SUCCESS(Status))
  1778. break;
  1779. cpropAllocated = _cpropActual + 1;
  1780. _psps = reinterpret_cast<STATPROPSTG*>
  1781. ( CoTaskMemAlloc( sizeof(STATPROPSTG) * cpropAllocated ) );
  1782. if (_psps == NULL)
  1783. {
  1784. Status = STATUS_INSUFFICIENT_RESOURCES;
  1785. break;
  1786. }
  1787. ulKeyZero = 0;
  1788. Status = PrEnumerateProperties(
  1789. np,
  1790. 0,
  1791. &ulKeyZero,
  1792. &cpropAllocated,
  1793. NULL, // aprs
  1794. _psps);
  1795. } while (NT_SUCCESS(Status) && cpropAllocated != _cpropActual);
  1796. *phr = NT_SUCCESS(Status) ? S_OK : DfpNtStatusToHResult(Status);
  1797. }
  1798. //+-------------------------------------------------------------------
  1799. //
  1800. // Member: CStatArray::~CStatArray
  1801. //
  1802. // Synopsis: Deallocated the object's data.
  1803. //
  1804. //--------------------------------------------------------------------
  1805. CStatArray::~CStatArray()
  1806. {
  1807. if( NULL != _psps )
  1808. {
  1809. STATPROPSTG *psps = _psps;
  1810. while( _cpropActual )
  1811. {
  1812. CoTaskMemFree( psps->lpwstrName );
  1813. _cpropActual--;
  1814. psps++;
  1815. }
  1816. CoTaskMemFree( _psps );
  1817. }
  1818. }
  1819. //+----------------------------------------------------------------------------
  1820. //
  1821. // Member: CStatArray:: QueryInterface/AddRef/Release
  1822. //
  1823. //+----------------------------------------------------------------------------
  1824. STDMETHODIMP
  1825. CStatArray::QueryInterface( REFIID riid, void **ppvObject)
  1826. {
  1827. return E_NOINTERFACE;
  1828. }
  1829. STDMETHODIMP_(ULONG)
  1830. CStatArray::AddRef(void)
  1831. {
  1832. LONG lRet;
  1833. lRet = InterlockedIncrement(&_cRefs);
  1834. return(lRet);
  1835. }
  1836. STDMETHODIMP_(ULONG) CStatArray::Release(void)
  1837. {
  1838. LONG lRet;
  1839. lRet = InterlockedDecrement(&_cRefs);
  1840. if (lRet == 0)
  1841. {
  1842. delete this;
  1843. }
  1844. else
  1845. if (lRet <0)
  1846. {
  1847. lRet = 0;
  1848. }
  1849. return(lRet);
  1850. }
  1851. //+-------------------------------------------------------------------
  1852. //
  1853. // Member: CStatArray::NextAt
  1854. //
  1855. // Synopsis: Read from the internal STATPROPSTG array.
  1856. //
  1857. // Effects: The cursor is passed in, and this function acts
  1858. // as a IEnumXX::Next would behave if the current cursor
  1859. // was [ipropNext].
  1860. //
  1861. // Arguments: [ipropNext] -- index of cursor to use
  1862. // [pspsDest] -- if NULL, emulate read's effect on cursor.
  1863. // if non-NULL, return data with cursor effect.
  1864. // [pceltFetched] -- buffer for count fetched
  1865. //
  1866. // Returns: STATUS_SUCCESS if successful, otherwise
  1867. // STATUS_INSUFFICIENT_RESOURCES.
  1868. //
  1869. // Notes:
  1870. //
  1871. //--------------------------------------------------------------------
  1872. NTSTATUS
  1873. CStatArray::NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched)
  1874. {
  1875. ULONG ipropLastPlus1;
  1876. //
  1877. // Copy the requested number of elements from the cache
  1878. // (including strings, the allocation of which may fail.)
  1879. //
  1880. ipropLastPlus1 = ipropNext + *pceltFetched;
  1881. if (ipropLastPlus1 > _cpropActual)
  1882. {
  1883. ipropLastPlus1 = _cpropActual;
  1884. }
  1885. *pceltFetched = ipropLastPlus1 - ipropNext;
  1886. if (pspsDest != NULL)
  1887. return CopySTATPROPSTG(*pceltFetched, pspsDest, _psps + ipropNext);
  1888. else
  1889. return(STATUS_SUCCESS);
  1890. }
  1891. //+-------------------------------------------------------------------
  1892. //
  1893. // Member: CEnumSTATPROPSTG::CEnumSTATPROPSTG
  1894. //
  1895. // Synopsis: Constructor which is used by IEnumSTATPROPSTG::Clone.
  1896. //
  1897. // Arguments: [other] -- the CEnumSTATPROPSTG to copy
  1898. // [phr] -- the error code.
  1899. //
  1900. // Notes: Since the CStatArray actually contains the object this
  1901. // just adds to the ref count.
  1902. //
  1903. //--------------------------------------------------------------------
  1904. CEnumSTATPROPSTG::CEnumSTATPROPSTG(const CEnumSTATPROPSTG & other )
  1905. {
  1906. _ulSig = ENUMSTATPROPSTG_SIG;
  1907. _cRefs = 1;
  1908. _psa = other._psa;
  1909. _psa->AddRef();
  1910. _ipropNext = other._ipropNext;
  1911. }
  1912. //+-------------------------------------------------------------------
  1913. //
  1914. // Member: CEnumSTATPROPSTG::~CEnumSTATPROPSTG
  1915. //
  1916. // Synopsis: Deallocated storage.
  1917. //
  1918. // Arguments:
  1919. //
  1920. // Returns:
  1921. //
  1922. // Notes:
  1923. //
  1924. //--------------------------------------------------------------------
  1925. CEnumSTATPROPSTG::~CEnumSTATPROPSTG()
  1926. {
  1927. _ulSig = ENUMSTATPROPSTG_SIGDEL; // prevent another thread doing it - kinda
  1928. RELEASE_INTERFACE( _psa );
  1929. }
  1930. //+-------------------------------------------------------------------
  1931. //
  1932. // Member: CEnumSTATPROPSTG::QueryInterface
  1933. //
  1934. // Synopsis: Respond to IEnumSTATPROPSTG and IUnknown.
  1935. //
  1936. // Returns: S_OK or E_NOINTERFACE
  1937. //
  1938. //--------------------------------------------------------------------
  1939. HRESULT CEnumSTATPROPSTG::QueryInterface( REFIID riid, void **ppvObject)
  1940. {
  1941. HRESULT hr;
  1942. *ppvObject = NULL;
  1943. if (S_OK != (hr = Validate()))
  1944. return(hr);
  1945. if (IsEqualIID(riid, IID_IEnumSTATPROPSTG))
  1946. {
  1947. *ppvObject = (IEnumSTATPROPSTG *)this;
  1948. AddRef();
  1949. }
  1950. else
  1951. if (IsEqualIID(riid, IID_IUnknown))
  1952. {
  1953. *ppvObject = (IUnknown *)this;
  1954. AddRef();
  1955. }
  1956. else
  1957. {
  1958. hr = E_NOINTERFACE;
  1959. }
  1960. return(hr);
  1961. }
  1962. //+-------------------------------------------------------------------
  1963. //
  1964. // Member: CEnumSTATPROPSTG::AddRef
  1965. //
  1966. // Synopsis: Add 1 to ref count.
  1967. //
  1968. //--------------------------------------------------------------------
  1969. ULONG CEnumSTATPROPSTG::AddRef(void)
  1970. {
  1971. long cRefs;
  1972. if (S_OK != Validate())
  1973. return(0);
  1974. cRefs = InterlockedIncrement(&_cRefs);
  1975. return(cRefs);
  1976. }
  1977. //+-------------------------------------------------------------------
  1978. //
  1979. // Member: CEnumSTATPROPSTG::Release
  1980. //
  1981. // Synopsis: Subtract 1 from ref count and delete if 0.
  1982. //
  1983. //--------------------------------------------------------------------
  1984. ULONG CEnumSTATPROPSTG::Release(void)
  1985. {
  1986. LONG lRet;
  1987. if (S_OK != Validate())
  1988. return(0);
  1989. lRet = InterlockedDecrement(&_cRefs);
  1990. if (lRet == 0)
  1991. {
  1992. delete this;
  1993. }
  1994. else
  1995. if (lRet <0)
  1996. {
  1997. lRet = 0;
  1998. }
  1999. return(lRet);
  2000. }
  2001. //+-------------------------------------------------------------------
  2002. //
  2003. // Function: CopySTATPROPSTG
  2004. //
  2005. // Synopsis: Copy out the range of elements from [pspsSrc] to
  2006. // [pspsDest].
  2007. //
  2008. // Arguments: [celt] -- count of elements to copy
  2009. // [pspsDest] -- where to copy to, always filled with
  2010. // zeros before anything else (helps cleanup
  2011. // case.)
  2012. //
  2013. // [pspsSrc] -- where to copy from
  2014. //
  2015. // Returns: STATUS_SUCCESS if ok, otherwise
  2016. // STATUS_INSUFFICIENT_RESOURCES in which case there
  2017. // may be pointers that need deallocating. Use
  2018. // CleanupSTATPROPSTG to do that.
  2019. //
  2020. //--------------------------------------------------------------------
  2021. NTSTATUS
  2022. CopySTATPROPSTG(ULONG celt,
  2023. STATPROPSTG * pspsDest,
  2024. const STATPROPSTG * pspsSrc)
  2025. {
  2026. memset(pspsDest, 0, sizeof(*pspsDest) * celt);
  2027. while (celt)
  2028. {
  2029. *pspsDest = *pspsSrc;
  2030. if (pspsSrc->lpwstrName != NULL)
  2031. {
  2032. pspsDest->lpwstrName = reinterpret_cast<OLECHAR*>
  2033. ( CoTaskMemAlloc( sizeof(OLECHAR)*( 1 + ocslen(pspsSrc->lpwstrName) ) ));
  2034. if (pspsDest->lpwstrName != NULL)
  2035. {
  2036. ocscpy(pspsDest->lpwstrName,
  2037. pspsSrc->lpwstrName);
  2038. }
  2039. else
  2040. {
  2041. return STATUS_INSUFFICIENT_RESOURCES;
  2042. }
  2043. }
  2044. celt--;
  2045. pspsDest++;
  2046. pspsSrc++;
  2047. }
  2048. return(STATUS_SUCCESS);
  2049. }
  2050. //+-------------------------------------------------------------------
  2051. //
  2052. // Member: CEnumSTATPROPSTG::Next
  2053. //
  2054. // Synopsis: Get the next [celt] STATPROPSTGs from the enumerator.
  2055. //
  2056. // Arguments: [celt] -- count requested.
  2057. // [rgelt] -- where to return them
  2058. // [pceltFetched] -- buffer for returned-count.
  2059. // if pceltFetched==NULL && celt != 1 -> STG_E_INVALIDPARAMETER
  2060. // if pceltFetched!=NULL && celt == 0 -> S_OK
  2061. //
  2062. // Returns: S_OK if successful, otherwise error.
  2063. //
  2064. //--------------------------------------------------------------------
  2065. HRESULT CEnumSTATPROPSTG::Next(
  2066. ULONG celt,
  2067. STATPROPSTG * rgelt,
  2068. ULONG * pceltFetched)
  2069. {
  2070. HRESULT hr;
  2071. NTSTATUS Status;
  2072. ULONG celtFetched = celt;
  2073. // ----------
  2074. // Validation
  2075. // ----------
  2076. // Validate 'this'
  2077. if (S_OK != (hr = Validate()))
  2078. return(hr);
  2079. // Validate the inputs
  2080. if (NULL == pceltFetched)
  2081. {
  2082. if (celt != 1)
  2083. return(STG_E_INVALIDPARAMETER);
  2084. }
  2085. else
  2086. {
  2087. VDATEPTROUT( pceltFetched, ULONG );
  2088. *pceltFetched = 0;
  2089. }
  2090. if( 0 == celt )
  2091. return( S_OK );
  2092. if( !IsValidPtrOut(rgelt, celt * sizeof(rgelt[0])) )
  2093. return( E_INVALIDARG );
  2094. // -----------------------
  2095. // Perform the enumeration
  2096. // -----------------------
  2097. if (celt == 0)
  2098. return(hr);
  2099. Status = _psa->NextAt(_ipropNext, rgelt, &celtFetched);
  2100. if (NT_SUCCESS(Status))
  2101. {
  2102. _ipropNext += celtFetched;
  2103. if (pceltFetched != NULL)
  2104. *pceltFetched = celtFetched;
  2105. hr = celtFetched == celt ? S_OK : S_FALSE;
  2106. }
  2107. else
  2108. {
  2109. hr = DfpNtStatusToHResult(Status);
  2110. }
  2111. return(hr);
  2112. }
  2113. //+-------------------------------------------------------------------
  2114. //
  2115. // Member: CEnumSTATPROPSTG::Skip
  2116. //
  2117. // Synopsis: Skip the next [celt] elements in the enumeration.
  2118. //
  2119. // Arguments: [celt] -- number of elts to skip
  2120. //
  2121. // Returns: S_OK if skipped [celt] elements
  2122. // S_FALSE if skipped < [celt] elements
  2123. //
  2124. // Notes:
  2125. //
  2126. //--------------------------------------------------------------------
  2127. HRESULT CEnumSTATPROPSTG::Skip(ULONG celt)
  2128. {
  2129. HRESULT hr;
  2130. ULONG celtFetched = celt;
  2131. if (S_OK != (hr = Validate()))
  2132. return(hr);
  2133. _psa->NextAt(_ipropNext, NULL, &celtFetched);
  2134. _ipropNext += celtFetched;
  2135. return celtFetched == celt ? S_OK : S_FALSE;
  2136. }
  2137. //+-------------------------------------------------------------------
  2138. //
  2139. // Member: CEnumSTATPROPSTG::Reset
  2140. //
  2141. // Synopsis: Set cursor to beginnging of enumeration.
  2142. //
  2143. // Returns: S_OK otherwise STG_E_INVALIDHANDLE.
  2144. //
  2145. //--------------------------------------------------------------------
  2146. HRESULT CEnumSTATPROPSTG::Reset()
  2147. {
  2148. HRESULT hr;
  2149. if (S_OK != (hr = Validate()))
  2150. return(hr);
  2151. _ipropNext = 0;
  2152. return(S_OK);
  2153. }
  2154. //+-------------------------------------------------------------------
  2155. //
  2156. // Member: CEnumSTATPROPSTG::Clone
  2157. //
  2158. // Synopsis: Creates an IEnumSTATPROPSTG with same cursor
  2159. // as this.
  2160. //
  2161. // Arguments: S_OK or error.
  2162. //
  2163. //--------------------------------------------------------------------
  2164. HRESULT CEnumSTATPROPSTG::Clone(IEnumSTATPROPSTG ** ppenum)
  2165. {
  2166. HRESULT hr = S_OK;
  2167. // ----------
  2168. // Validation
  2169. // ----------
  2170. // Validate 'this'
  2171. if (S_OK != (hr = Validate()))
  2172. return(hr);
  2173. // Validate the input
  2174. VDATEPTROUT( ppenum, IEnumSTATPROPSTG* );
  2175. *ppenum = NULL;
  2176. // --------------------
  2177. // Clone the enumerator
  2178. // --------------------
  2179. *ppenum = new CEnumSTATPROPSTG( *this );
  2180. if( NULL == *ppenum )
  2181. hr = STG_E_INSUFFICIENTMEMORY;
  2182. return(hr);
  2183. }
  2184. //+----------------------------------------------------------------------------
  2185. //
  2186. // Function: Lock & Unlock
  2187. //
  2188. // Synopsis: This methods take and release the CPropertyStorage's
  2189. // critical section.
  2190. //
  2191. // Inputs: none
  2192. //
  2193. // Returns: Nothing
  2194. //
  2195. //+----------------------------------------------------------------------------
  2196. VOID
  2197. CPropertyStorage::Lock(void)
  2198. {
  2199. #ifndef _MAC
  2200. DfpAssert (_fInitCriticalSection);
  2201. EnterCriticalSection( &_CriticalSection );
  2202. #endif
  2203. #if DBG
  2204. _cLocks++;
  2205. #endif
  2206. }
  2207. VOID
  2208. CPropertyStorage::Unlock()
  2209. {
  2210. #if DBG
  2211. --_cLocks;
  2212. DfpAssert( 0 <= _cLocks );
  2213. #endif
  2214. #ifndef _MAC
  2215. DfpAssert (_fInitCriticalSection);
  2216. LeaveCriticalSection( &_CriticalSection );
  2217. #endif
  2218. }
  2219. //+----------------------------------------------------------------------------
  2220. //
  2221. // Function: CPropertyStorage::ProbeStreamToDetermineIfWriteable
  2222. //
  2223. // Synopsis: Probes the IStream which holds the property set to see if it
  2224. // can be written. Ordinarily we know whether or not a stream
  2225. // is writeable either because we were given the grfMode or
  2226. // because we Stat-ed it out of the stream. But this code
  2227. // was added for the case where IStream::Stat returns zero
  2228. // for the grfMode but it's actually writeable (this happens
  2229. // with CreateStreamOnHGlobal). So a grfMode of zero is a hint
  2230. // that the IStream may not support that value in the Stat.
  2231. //
  2232. // This method should be called lazily the first time a modify
  2233. // operation is called on the property set, because it will
  2234. // cause an update to the last-modify time of the stream.
  2235. //
  2236. // Inputs: none
  2237. //
  2238. // Returns: TRUE if the stream is writeable. Also sets
  2239. // _fExplicitelyProbedForWriteAccess so that we don't call this
  2240. // twice.
  2241. //
  2242. //+----------------------------------------------------------------------------
  2243. BOOL
  2244. CPropertyStorage::ProbeStreamToDetermineIfWriteable()
  2245. {
  2246. HRESULT hr = S_OK;
  2247. BOOL fWriteable = FALSE;
  2248. BYTE FirstByte;
  2249. LARGE_INTEGER liZero = {0};
  2250. propITrace( "CPropertyStorage::ProbeStreamToDetermineIfWriteable" );
  2251. AssertLocked();
  2252. DfpAssert( !_fExplicitelyProbedForWriteAccess );
  2253. // This routine is only called once
  2254. _fExplicitelyProbedForWriteAccess = TRUE;
  2255. // Read then write a byte
  2256. hr = _pstmPropSet->Read( &FirstByte, 1, NULL );
  2257. if( FAILED(hr) ) goto Exit;
  2258. hr = _pstmPropSet->Seek( liZero, STREAM_SEEK_SET, NULL );
  2259. if( FAILED(hr) ) goto Exit;
  2260. hr = _pstmPropSet->Write( &FirstByte, 1, NULL );
  2261. if( FAILED(hr) ) goto Exit;
  2262. // If the write worked, then this stream is really STGM_READWRITE
  2263. fWriteable = TRUE;
  2264. _grfMode |= STGM_READWRITE;
  2265. Exit:
  2266. propDbg((DEB_ITRACE, "Property Set %p %s writeable (hr=%08x)\n",
  2267. this, fWriteable?"is":"isn't", hr ));
  2268. return( fWriteable );
  2269. }
  2270. //+-----------------------------------------------------------------------
  2271. //
  2272. // Member: InitializeOnCreateOrOpen
  2273. //
  2274. // Synopsis: This routine is called during the creation or opening
  2275. // of a Property Storage, and initializes everything
  2276. // it can without being concerned about whether this
  2277. // is a simple or non-simple property set.
  2278. //
  2279. // Inputs: [DWORD] grfFlags (in)
  2280. // From the PROPSETFLAG_* enumeration.
  2281. // [DWORD] grfMode (in)
  2282. // From the STGM_* enumeration.
  2283. // [REFFMTID] rfmtid (in)
  2284. // The ID of the property set.
  2285. // [BOOL] fCreate (in)
  2286. // Distinguishes Create from Open.
  2287. //
  2288. // Returns: [HRESULT]
  2289. //
  2290. // Effects: _grfFlags, _grfMode, _fUserDefinedProperties,
  2291. // and g_ReservedMemory.
  2292. //
  2293. //+-----------------------------------------------------------------------
  2294. HRESULT
  2295. CPropertyStorage::InitializeOnCreateOrOpen(
  2296. DWORD grfFlags,
  2297. DWORD grfMode,
  2298. REFFMTID rfmtid,
  2299. BOOL fCreate )
  2300. {
  2301. HRESULT hr = S_OK;
  2302. propITrace( "CPropertyStorage::InitializeOnCreateOrOpen" );
  2303. AssertLocked();
  2304. // If the caller didn't give us a grfMode, stat for it.
  2305. if( 0 == grfMode )
  2306. {
  2307. STATSTG statstg;
  2308. DfpAssert( NULL != _pstgPropSet || NULL != _pstmPropSet );
  2309. if( NULL != _pstgPropSet )
  2310. hr = _pstgPropSet->Stat( &statstg, STATFLAG_NONAME );
  2311. else
  2312. hr = _pstmPropSet->Stat( &statstg, STATFLAG_NONAME );
  2313. if( FAILED(hr) ) goto Exit;
  2314. grfMode = statstg.grfMode;
  2315. }
  2316. // Validate that grfFlags is within the enumeration.
  2317. if (grfFlags & ~(PROPSETFLAG_ANSI | PROPSETFLAG_NONSIMPLE | PROPSETFLAG_UNBUFFERED | PROPSETFLAG_CASE_SENSITIVE))
  2318. {
  2319. hr = STG_E_INVALIDFLAG;
  2320. goto Exit;
  2321. }
  2322. hr = CheckFlagsOnCreateOrOpen( fCreate, grfMode );
  2323. if (hr != S_OK)
  2324. {
  2325. goto Exit;
  2326. }
  2327. // Store the grfFlags & grfMode.
  2328. _grfFlags = grfFlags;
  2329. _grfMode = grfMode;
  2330. // Is this the special-case second-section property set?
  2331. _fUserDefinedProperties = ( rfmtid == FMTID_UserDefinedProperties ) ? TRUE : FALSE;
  2332. if (fCreate
  2333. &&
  2334. (_grfFlags & PROPSETFLAG_ANSI) )
  2335. {
  2336. _usCodePage = static_cast<USHORT>(GetACP());
  2337. }
  2338. // Initialize the global reserved memory (to prevent problems
  2339. // in low-memory conditions).
  2340. if (S_OK != (hr = g_ReservedMemory.Init()))
  2341. goto Exit;
  2342. // ----
  2343. // Exit
  2344. // ----
  2345. Exit:
  2346. return( hr );
  2347. } // CPropertyStorage::InitializeOnCreate()
  2348. //+-------------------------------------------------------------------
  2349. //
  2350. // Member: CPropertyStorage::Create( IStream * ...
  2351. //
  2352. // Synopsis: This method creates an IPropertyStorage on a
  2353. // given *Stream*. It is therefore a simple property
  2354. // set. The given Stream is addref-ed.
  2355. //
  2356. // Arguments: [IStream*] pstm
  2357. // The Stream which will hold the serialized property set.
  2358. // [REFFMTID] rfmtid
  2359. // The ID of the property set.
  2360. // [const CLSID*]
  2361. // The COM object which can interpret the property set.
  2362. // [DWORD] grfFlags
  2363. // From the PROPSETFLAG_* enumeration.
  2364. // [DWORD] grfMode
  2365. // From the STGM_* enumeration. If 0, we use Stat.
  2366. // [HRESULT*]
  2367. // The return code.
  2368. //
  2369. // Returns: None.
  2370. //
  2371. //--------------------------------------------------------------------
  2372. HRESULT
  2373. CPropertyStorage::Create(
  2374. IStream *pstm,
  2375. REFFMTID rfmtid,
  2376. const CLSID *pclsid,
  2377. DWORD grfFlags,
  2378. DWORD grfMode
  2379. )
  2380. {
  2381. HRESULT hr = S_OK;
  2382. BOOL fCreated = FALSE;
  2383. BOOL fLocked = FALSE;
  2384. propITrace( "CPropertyStorage::Create(IStream*)" );
  2385. propTraceParameters(( "pstm=%p, rfmtid=%s, grfFlags=%s, grfMode=%s, fDelete=%s",
  2386. pstm,
  2387. static_cast<const char*>(CStringize(rfmtid)),
  2388. static_cast<const char*>(CStringize(*pclsid)),
  2389. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  2390. static_cast<const char*>(CStringize(SGrfMode(grfMode))) ));
  2391. // Save and addref the Stream.
  2392. _pstmPropSet = pstm;
  2393. _pstmPropSet->AddRef();
  2394. Lock();
  2395. fLocked = TRUE;
  2396. // Initialize this object
  2397. DfpAssert( !(PROPSETFLAG_NONSIMPLE & grfFlags ));
  2398. hr = InitializeOnCreateOrOpen( grfFlags, grfMode, rfmtid,
  2399. TRUE ); // => Create
  2400. if( FAILED(hr) ) goto Exit;
  2401. DfpAssert( !IsNonSimple() );
  2402. // Initialize the Stream.
  2403. hr = InitializePropertyStream( &rfmtid, pclsid, CREATE_PROPSTREAM );
  2404. if( FAILED(hr) ) goto Exit;
  2405. // If buffering is not desired, flush the property storage
  2406. // to the underlying Stream.
  2407. if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  2408. {
  2409. NTSTATUS Status = PrFlushPropertySet(_np);
  2410. if (!NT_SUCCESS(Status))
  2411. {
  2412. hr = DfpNtStatusToHResult(Status);
  2413. }
  2414. }
  2415. // ----
  2416. // Exit
  2417. // ----
  2418. Exit:
  2419. // On error, remove our reference to the Stream.
  2420. if( FAILED(hr) )
  2421. {
  2422. _pstmPropSet->Release();
  2423. _pstmPropSet = NULL;
  2424. propDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::Create(IStream*)"
  2425. " hr=%08X\n", this, hr));
  2426. }
  2427. if( fLocked )
  2428. Unlock();
  2429. return( hr );
  2430. } // CPropertyStorage::Create( IStream *, ...
  2431. //+-------------------------------------------------------------------
  2432. //
  2433. // Member: CPropertyStorage::Create( IStorage *, ...
  2434. //
  2435. // Synopsis: This method creates an IPropertyStorage on a
  2436. // given *Storage*. It is therefore a non-simple property
  2437. // set. The Storage is addref-ed.
  2438. //
  2439. // Arguments: [IStorage*] pstm
  2440. // The Storage which will hold the serialized property set.
  2441. // [REFFMTID] rfmtid
  2442. // The ID of the property set.
  2443. // [const CLSID*]
  2444. // The COM object which can interpret the property set.
  2445. // [DWORD] grfFlags
  2446. // From the PROPSETFLAG_* enumeration.
  2447. // [HRESULT*]
  2448. // The return code.
  2449. //
  2450. // Returns: None.
  2451. //
  2452. //--------------------------------------------------------------------
  2453. HRESULT
  2454. CPropertyStorage::Create(
  2455. IStorage *pstg,
  2456. REFFMTID rfmtid,
  2457. const CLSID *pclsid,
  2458. DWORD grfFlags,
  2459. DWORD grfMode
  2460. )
  2461. {
  2462. HRESULT hr = S_OK;
  2463. BOOL fCreated = FALSE;
  2464. BOOL fLocked = FALSE;
  2465. STATSTG statstg = { NULL };
  2466. propITrace( "CPropertyStorage::Create(IStorage*)" );
  2467. propTraceParameters(( "pstg=%p, rfmtid=%s, grfFlags=%s, grfMode=%s, fDelete=%s",
  2468. pstg,
  2469. static_cast<const char*>(CStringize(rfmtid)),
  2470. static_cast<const char*>(CStringize(*pclsid)),
  2471. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  2472. static_cast<const char*>(CStringize(SGrfMode(grfMode))) ));
  2473. // Save the given Storage.
  2474. _pstgPropSet = pstg;
  2475. _pstgPropSet->AddRef();
  2476. Lock();
  2477. fLocked = TRUE;
  2478. // Initialize this object.
  2479. DfpAssert( grfFlags & PROPSETFLAG_NONSIMPLE );
  2480. hr = InitializeOnCreateOrOpen( grfFlags, grfMode, rfmtid,
  2481. TRUE ); // => Create
  2482. if( FAILED(hr) ) goto Exit;
  2483. DfpAssert( IsNonSimple() );
  2484. // Create the "CONTENTS" stream. Mask out the STGM_TRANSACTED
  2485. // bit because we don't support it.
  2486. hr = _pstgPropSet->CreateStream(g_oszPropertyContentsStreamName,
  2487. GetChildCreateMode() & ~STGM_TRANSACTED,
  2488. 0, 0, &_pstmPropSet);
  2489. if (FAILED(hr)) goto Exit;
  2490. fCreated = TRUE;
  2491. // Initialize the CONTENTS Stream.
  2492. hr = InitializePropertyStream( &rfmtid, pclsid, CREATE_PROPSTREAM );
  2493. if( FAILED(hr) ) goto Exit;
  2494. // In the transacted case, ensure that the contents
  2495. // stream is actually published right away.
  2496. // The logic is this ... if you have a storage and create a transacted
  2497. // child storage, that child storage is complete and intact to the parent.
  2498. // If you then revert the child, or make no changes to it, the parent still
  2499. // has a valid (albeit empty) storage. Now, say you do the same thing, but
  2500. // the transacted child is a property set. As it stands at this point in this
  2501. // method, the parent can only see an empty storage. For it to see a valid
  2502. // (empty) property set child, it must see the Contents stream, along with its default
  2503. // data (header, codepage, etc.). In order to make this happen, we must
  2504. // commit (not just flush) this storage that holds a property set.
  2505. //
  2506. // There's one more complication. Even if this is a direct mode property
  2507. // set, the _pstgPropSet may be transacted nonetheless, for the purpose of
  2508. // robustness (this happens in NFF). So, we need to commit not if
  2509. // _grfMode is transacted, but if _pstgPropSet says that it's transacted.
  2510. hr = _pstgPropSet->Stat( &statstg, STATFLAG_NONAME );
  2511. if( FAILED(hr) ) goto Exit;
  2512. if( STGM_TRANSACTED & statstg.grfMode )
  2513. {
  2514. hr = Commit(STGC_DEFAULT);
  2515. if( FAILED(hr) ) goto Exit;
  2516. }
  2517. // If buffering is not desired, flush the property storage
  2518. // to the underlying Stream.
  2519. else if( _grfFlags & PROPSETFLAG_UNBUFFERED )
  2520. {
  2521. NTSTATUS Status = PrFlushPropertySet(_np);
  2522. if (!NT_SUCCESS(Status))
  2523. {
  2524. hr = DfpNtStatusToHResult(Status);
  2525. }
  2526. }
  2527. // ----
  2528. // Exit
  2529. // ----
  2530. Exit:
  2531. // On error, remove our reference to the Storage.
  2532. if( FAILED(hr) )
  2533. {
  2534. _pstgPropSet->Release();
  2535. _pstgPropSet = NULL;
  2536. // Also, delete the "CONTENTS" stream.
  2537. if( fCreated )
  2538. pstg->DestroyElement( g_oszPropertyContentsStreamName );
  2539. propDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::Create(IStorage*)"
  2540. " hr=%08X\n", this, hr));
  2541. }
  2542. if( fLocked )
  2543. Unlock();
  2544. return( hr );
  2545. } // CPropertyStorage::Create( IStorage *, ...
  2546. //+-------------------------------------------------------------------
  2547. //
  2548. // Member: CPropertyStorage::Open( IStream * ...
  2549. //
  2550. // Synopsis: This method opens an IPropertyStorage on a
  2551. // given *Stream*. It is therefore a simple property
  2552. // set. The Stream is addref-ed.
  2553. //
  2554. // Arguments: [IStream*] pstm
  2555. // The Stream which will hold the serialized property set.
  2556. // [REFFMTID] rfmtid
  2557. // The ID of the property set.
  2558. // [DWORD] grfFlags
  2559. // From the PROPSETFLAG_ enumeration. Only the
  2560. // _UNBUFFERED flag is relevant _ANSI and
  2561. // _NONSIMPLE are inferred from the property set.
  2562. // [BOOL] fDelete
  2563. // If TRUE, the property set is actually to be deleted,
  2564. // rather than opened (this is used for the special-case
  2565. // "UserDefined" property set).
  2566. // [HRESULT*]
  2567. // The return code.
  2568. //
  2569. // Returns: None.
  2570. //
  2571. //--------------------------------------------------------------------
  2572. HRESULT
  2573. CPropertyStorage::Open(
  2574. IStream *pstm,
  2575. REFFMTID rfmtid,
  2576. DWORD grfFlags,
  2577. DWORD grfMode,
  2578. BOOL fDelete
  2579. )
  2580. {
  2581. HRESULT hr = S_OK;
  2582. BOOL fLocked = FALSE;
  2583. propITrace( "CPropertyStorage::Open(IStream*)" );
  2584. propTraceParameters(( "pstm=%p, rfmtid=%s, grfFlags=%s, grfMode=%s, fDelete=%s",
  2585. pstm,
  2586. static_cast<const char*>(CStringize(rfmtid)),
  2587. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  2588. static_cast<const char*>(CStringize(SGrfMode(grfMode))),
  2589. fDelete ? "True":"False" ));
  2590. // Keep a copy of the Stream.
  2591. _pstmPropSet = pstm;
  2592. _pstmPropSet->AddRef();
  2593. Lock();
  2594. fLocked = TRUE;
  2595. // Initialize this object.
  2596. hr = InitializeOnCreateOrOpen( grfFlags,
  2597. grfMode,
  2598. rfmtid,
  2599. FALSE ); // => Open
  2600. if( FAILED(hr) ) goto Exit;
  2601. // Only simple sections may be deleted (really, only the
  2602. // second section of the DocumentSummaryInformation property
  2603. // set may be deleted in this way).
  2604. DfpAssert( !fDelete || !IsNonSimple() );
  2605. // Initialize the property set Stream.
  2606. if (hr == S_OK)
  2607. {
  2608. // sets up _usCodePage
  2609. hr = InitializePropertyStream(
  2610. &rfmtid,
  2611. NULL,
  2612. fDelete ? DELETE_PROPSTREAM : OPEN_PROPSTREAM );
  2613. }
  2614. if( FAILED(hr) ) goto Exit;
  2615. // ----
  2616. // Exit
  2617. // ----
  2618. Exit:
  2619. // On error, remove our reference to the Stream.
  2620. if( FAILED(hr) )
  2621. {
  2622. _pstmPropSet->Release();
  2623. _pstmPropSet = NULL;
  2624. propDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::Open(IStream*)"
  2625. " hr=%08X\n", this, hr));
  2626. }
  2627. if( fLocked )
  2628. Unlock();
  2629. return( hr );
  2630. } // CPropertyStorage::Open( IStream *, ...
  2631. //+-------------------------------------------------------------------
  2632. //
  2633. // Member: CPropertyStorage::Open( IStorage * ...
  2634. //
  2635. // Synopsis: This method opens an IPropertyStorage on a
  2636. // given *Storage*. It is therefore a non-simple property
  2637. // set. The Storage is addref-ed.
  2638. //
  2639. // Arguments: [IStorage*] pstg
  2640. // The Storage which will hold the serialized property set.
  2641. // [REFFMTID] rfmtid
  2642. // The ID of the property set.
  2643. // [DWORD] grfFlags
  2644. // From the PROPSETFLAG_ enumeration. Only the
  2645. // _UNBUFFERED flag is relevant _ANSI and
  2646. // _NONSIMPLE are inferred from the property set.
  2647. // [HRESULT*]
  2648. // The return code.
  2649. //
  2650. // Returns: None.
  2651. //
  2652. //--------------------------------------------------------------------
  2653. HRESULT
  2654. CPropertyStorage::Open(
  2655. IStorage *pstg,
  2656. REFFMTID rfmtid,
  2657. DWORD grfFlags,
  2658. DWORD grfMode
  2659. )
  2660. {
  2661. HRESULT hr = S_OK;
  2662. CPropSetName psn(rfmtid);
  2663. USHORT createprop = 0L;
  2664. BOOL fLocked = FALSE;
  2665. propITrace( "CPropertyStorage::Open(IStorage*)" );
  2666. propTraceParameters(( "pstg=%p, rfmtid=%s, grfFlags=%s, grfMode=%s",
  2667. pstg,
  2668. static_cast<const char*>(CStringize(rfmtid)),
  2669. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  2670. static_cast<const char*>(CStringize(SGrfMode(grfMode))) ));
  2671. // Keep a copy of the Storage
  2672. _pstgPropSet = pstg;
  2673. _pstgPropSet->AddRef();
  2674. Lock();
  2675. fLocked = TRUE;
  2676. // Initialize this object.
  2677. hr = InitializeOnCreateOrOpen( grfFlags,
  2678. grfMode,
  2679. rfmtid,
  2680. FALSE ); // => Open
  2681. if( FAILED(hr) ) goto Exit;
  2682. _grfFlags |= PROPSETFLAG_NONSIMPLE;
  2683. // Open the CONTENTS stream. Mask out the STGM_TRANSACTED bit
  2684. // because it causes an error on Mac OLE2.
  2685. hr = _pstgPropSet->OpenStream( g_oszPropertyContentsStreamName,
  2686. 0,
  2687. GetChildOpenMode() & ~STGM_TRANSACTED,
  2688. 0,
  2689. &_pstmPropSet );
  2690. if( FAILED(hr) ) goto Exit;
  2691. // Load the property set Stream.
  2692. if (hr == S_OK)
  2693. {
  2694. // sets up _usCodePage
  2695. hr = InitializePropertyStream(
  2696. &rfmtid,
  2697. NULL,
  2698. OPEN_PROPSTREAM );
  2699. }
  2700. if( FAILED(hr) ) goto Exit;
  2701. // ----
  2702. // Exit
  2703. // ----
  2704. Exit:
  2705. // On error, remove our reference to the Storage.
  2706. if( FAILED(hr) )
  2707. {
  2708. _pstgPropSet->Release();
  2709. _pstgPropSet = NULL;
  2710. if( NULL != _pstmPropSet )
  2711. {
  2712. _pstmPropSet->Release();
  2713. _pstmPropSet = NULL;
  2714. }
  2715. propDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::Open(IStorage*)"
  2716. " hr=%08X\n", this, hr));
  2717. }
  2718. if( fLocked )
  2719. Unlock();
  2720. return( hr );
  2721. } // CPropertyStorage::Open( IStorage *, ...
  2722. //+----------------------------------------------------------------
  2723. //
  2724. // Member: CPropertyStorage::CreateMappedStream
  2725. //
  2726. // Synopsis: Create a IMappedStream object on an IStream.
  2727. //
  2728. // Arguments: None.
  2729. //
  2730. // Returns: None.
  2731. //
  2732. // Notes: This method calls QI through the PropSet Stream to see if
  2733. // a mapped stream exists. If it doesn't then this
  2734. // method creates a IMappedStream which maps
  2735. // an IStream.
  2736. //
  2737. //+----------------------------------------------------------------
  2738. HRESULT
  2739. CPropertyStorage::CreateMappedStream()
  2740. {
  2741. HRESULT hr;
  2742. DfpAssert( NULL != _pstmPropSet );
  2743. DfpAssert( NULL == _ms );
  2744. AssertLocked();
  2745. propITrace( "CPropertyStorage::CreateMappedStream" );
  2746. // QI the property set's IStream, if asked to do so, for an IMappedstream.
  2747. if( MAPPED_STREAM_QI == _fMSOpts )
  2748. {
  2749. // We got a mapped stream, so we're done.
  2750. hr = _pstmPropSet->QueryInterface(IID_IMappedStream,(void**)&_ms);
  2751. if (SUCCEEDED(hr))
  2752. {
  2753. propDbg(( DEB_INFO, "Using QI-ed IMappedStream\n" ));
  2754. goto Exit;
  2755. }
  2756. }
  2757. // Either we couldn't get a mapped stream from the IStream, or
  2758. // we were told not to ask for one. In either case, we'll
  2759. // create our own.
  2760. hr = S_OK;
  2761. _ms = (IMappedStream *) new CSSMappedStream( _pstmPropSet );
  2762. if( NULL == _ms )
  2763. hr = E_OUTOFMEMORY;
  2764. else
  2765. propDbg(( DEB_INFO, "Using CSSMappedStream\n" ));
  2766. Exit:
  2767. return( hr );
  2768. }
  2769. VOID
  2770. CPropertyStorage::DeleteMappedStream()
  2771. {
  2772. AssertLocked();
  2773. if (NULL != _ms) {
  2774. _ms->Release();
  2775. }
  2776. _ms = NULL;
  2777. }
  2778. #if DBG
  2779. HRESULT
  2780. CPropertyStorage::UseNTFS4Streams( BOOL fUseNTFS4Streams )
  2781. {
  2782. IStorageTest *pPropStgTest = NULL;
  2783. HRESULT hr = S_OK;
  2784. if( NULL != _pstmPropSet )
  2785. hr = _pstmPropSet->QueryInterface( IID_IStorageTest,
  2786. reinterpret_cast<void**>(&pPropStgTest) );
  2787. else if( NULL != _pstgPropSet )
  2788. hr = _pstgPropSet->QueryInterface( IID_IStorageTest,
  2789. reinterpret_cast<void**>(&pPropStgTest) );
  2790. else
  2791. hr = STG_E_NOMOREFILES;
  2792. if( FAILED(hr) ) goto Exit;
  2793. hr = pPropStgTest->UseNTFS4Streams( fUseNTFS4Streams );
  2794. if( FAILED(hr) ) goto Exit;
  2795. Exit:
  2796. if( NULL != pPropStgTest )
  2797. pPropStgTest->Release();
  2798. return( hr );
  2799. } // CPropertyStorage::UseNTFS4Streams()
  2800. #endif // #if DBG
  2801. //+----------------------------------------------------------------------------
  2802. //
  2803. // CPropertyStorage::GetFormatVersion (IStorageTest) **DBG**
  2804. //
  2805. // Get the property set's wFormatVersion field.
  2806. //
  2807. //+----------------------------------------------------------------------------
  2808. #if DBG
  2809. HRESULT
  2810. CPropertyStorage::GetFormatVersion(WORD *pw)
  2811. {
  2812. HRESULT hr = S_OK;
  2813. NTSTATUS status = STATUS_SUCCESS;
  2814. CPropertySetStream *pPropertySetStream = (CPropertySetStream*) _np;
  2815. status = pPropertySetStream->Lock( TRUE );
  2816. if( !NT_SUCCESS(status) ) goto Exit;
  2817. pPropertySetStream->ReOpen( &status );
  2818. if( !NT_SUCCESS(status) ) goto Exit;
  2819. *pw = pPropertySetStream->GetFormatVersion();
  2820. status = STATUS_SUCCESS;
  2821. Exit:
  2822. if( !NT_SUCCESS(status) )
  2823. hr = DfpNtStatusToHResult(status);
  2824. pPropertySetStream->Unlock();
  2825. return( hr );
  2826. }
  2827. #endif // #if DBG
  2828. //+----------------------------------------------------------------------------
  2829. //
  2830. // CPropertyStorage::SimulateLowMemory (IStorageTest) **DBG**
  2831. //
  2832. // Forcable turn on the low-memory support in the IMappedStream implementation.
  2833. //
  2834. //+----------------------------------------------------------------------------
  2835. #if DBG
  2836. HRESULT
  2837. CPropertyStorage::SimulateLowMemory( BOOL fSimulate )
  2838. {
  2839. IStorageTest *pPropStgTest = NULL;
  2840. HRESULT hr = S_OK;
  2841. if( NULL != _pstmPropSet )
  2842. hr = _pstmPropSet->QueryInterface( IID_IStorageTest,
  2843. reinterpret_cast<void**>(&pPropStgTest) );
  2844. else if( NULL != _pstgPropSet )
  2845. hr = _pstgPropSet->QueryInterface( IID_IStorageTest,
  2846. reinterpret_cast<void**>(&pPropStgTest) );
  2847. else
  2848. hr = STG_E_NOMOREFILES;
  2849. if( FAILED(hr) ) goto Exit;
  2850. hr = pPropStgTest->SimulateLowMemory( fSimulate );
  2851. if( FAILED(hr) ) goto Exit;
  2852. Exit:
  2853. if( NULL != pPropStgTest )
  2854. pPropStgTest->Release();
  2855. return( hr );
  2856. }
  2857. #endif // #if DBG
  2858. #if DBG
  2859. HRESULT
  2860. CPropertyStorage::GetLockCount()
  2861. {
  2862. return( E_NOTIMPL );
  2863. }
  2864. #endif // #if DBG
  2865. //+----------------------------------------------------------------------------
  2866. //
  2867. // CPropertyStorage::IsDirty (IStorageTest) **DBG**
  2868. //
  2869. // Determine if the IMappedStream is dirty.
  2870. //
  2871. //+----------------------------------------------------------------------------
  2872. #if DBG
  2873. HRESULT
  2874. CPropertyStorage::IsDirty()
  2875. {
  2876. HRESULT hr = S_OK;
  2877. IStorageTest *ptest = NULL;
  2878. if( NULL == _ms )
  2879. {
  2880. hr = S_FALSE;
  2881. goto Exit;
  2882. }
  2883. hr = _ms->QueryInterface( IID_IStorageTest, reinterpret_cast<void**>(&ptest) );
  2884. if( FAILED(hr) ) goto Exit;
  2885. hr = ptest->IsDirty();
  2886. Exit:
  2887. RELEASE_INTERFACE(ptest);
  2888. return( hr );
  2889. }
  2890. #endif // #if DBG
  2891. //+----------------------------------------------------------------------------
  2892. //
  2893. // CPropertyStorage::ValidateVTs
  2894. //
  2895. // Validate the VTs in an array of PropVariants. If we see a type we don't
  2896. // understand, return error_not_supported.
  2897. //
  2898. //+----------------------------------------------------------------------------
  2899. HRESULT
  2900. CPropertyStorage::ValidateVTs( ULONG cprops, const PROPVARIANT rgpropvar[] )
  2901. {
  2902. HRESULT hr = S_OK;
  2903. propITrace( "CPropertyStorage::ValidateVTs" );
  2904. propTraceParameters(( "cprops=%d, rgpropvar=%p", cprops, rgpropvar ));
  2905. for( ULONG i = 0; i < cprops; i++ )
  2906. {
  2907. if( !IsSupportedVarType( rgpropvar[i].vt ) )
  2908. {
  2909. propDbg(( DEB_IWARN, "Unsupported VarType in ValidateVTs: 0x%x\n", rgpropvar[i].vt ));
  2910. hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  2911. propSuppressExitErrors();
  2912. goto Exit;
  2913. }
  2914. }
  2915. Exit:
  2916. return( hr );
  2917. }