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

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