Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2039 lines
51 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. //--------------------------------------------------------------------------
  24. #include "pch.cxx"
  25. DECLARE_INFOLEVEL(prop, DEB_ERROR)
  26. //+-------------------------------------------------------------------
  27. //
  28. // Member: CCoTaskAllocator::Allocate, Free.
  29. //
  30. // Synopsis: Allocation routines called by RtlQueryProperties.
  31. //
  32. // Notes:
  33. //
  34. //--------------------------------------------------------------------
  35. CCoTaskAllocator g_CoTaskAllocator;
  36. void *
  37. CCoTaskAllocator::Allocate(ULONG cbSize)
  38. {
  39. return(CoTaskMemAlloc(cbSize));
  40. }
  41. void
  42. CCoTaskAllocator::Free(void *pv)
  43. {
  44. CoTaskMemFree(pv);
  45. }
  46. //+-------------------------------------------------------------------
  47. //
  48. // Member: CPropertyStorage::CPropertyStorage
  49. //
  50. // Synopsis: Constructor used to create a property storage on disk.
  51. //
  52. // Arguments: [pstg] -- storage object to be parent
  53. // [rfmtid] -- format id for new property set.
  54. // [pclsid] -- pointer to class id
  55. // [grfFlags] -- flags
  56. // [grfMode] -- mode
  57. // [phr] -- HRESULT assumed to be STG_E_INSUFFICIENTMEMORY
  58. // on entry. Will be HRESULT reflecting result on exit.
  59. //
  60. // Notes: Get a CPropertySetStream initialized with the correct
  61. // type of map (i.e. docfile or native.)
  62. // If non-simple mode, create a storage with name derived
  63. // from rfmtid and then a contents sub-stream.
  64. // If simple mode, create a stream of a name derived from
  65. // rfmtid.
  66. //
  67. // Does not clean up on failure: this is done by the
  68. // destructor.
  69. //
  70. //--------------------------------------------------------------------
  71. CPropertyStorage::CPropertyStorage(
  72. IPrivateStorage *pprivstg,
  73. REFFMTID rfmtid,
  74. const CLSID *pclsid,
  75. DWORD grfFlags,
  76. DWORD grfMode,
  77. HRESULT *phr)
  78. {
  79. HRESULT & hr = *phr;
  80. CPropSetName psn(rfmtid); // acts as Probe(&rfmtid, sizeof(rfmtid));
  81. BOOL fCreated = FALSE;
  82. IStorage *pstg = pprivstg->GetStorage();
  83. Initialize();
  84. if (grfFlags & PROPSETFLAG_NONSIMPLE)
  85. {
  86. hr = STG_E_UNIMPLEMENTEDFUNCTION;
  87. PROPASSERT(FALSE && "Unsupported function in reference called!\n" );
  88. return;
  89. }
  90. if (grfFlags & ~PROPSETFLAG_ANSI)
  91. {
  92. hr = STG_E_INVALIDFLAG;
  93. return;
  94. }
  95. // check for any mode flags disallowed in Create.
  96. if (grfMode & (STGM_PRIORITY | STGM_CONVERT |
  97. STGM_SIMPLE | STGM_DELETEONRELEASE))
  98. {
  99. hr = STG_E_INVALIDFLAG;
  100. return;
  101. }
  102. _grfFlags = grfFlags;
  103. _grfAccess = 3 & grfMode;
  104. _grfShare = 0xF0 & grfMode;
  105. // Is this the special-case second-section property set?
  106. _fUserDefinedProperties = ( rfmtid == FMTID_UserDefinedProperties ) ? TRUE : FALSE;
  107. if (_grfAccess != STGM_READWRITE)
  108. {
  109. hr = STG_E_INVALIDFLAG;
  110. return;
  111. }
  112. if (_grfFlags & PROPSETFLAG_ANSI)
  113. {
  114. _usCodePage = GetACP();
  115. }
  116. int i=0;
  117. while (i<=1)
  118. {
  119. // Create the property set stream in pstg.
  120. // The second section of the DocumentSummaryInformation Property Set
  121. // is a special-case.
  122. if( IsEqualGUID( rfmtid, FMTID_UserDefinedProperties ))
  123. {
  124. hr = _CreateDocumentSummary2Stream( pstg, psn, grfMode, &fCreated );
  125. }
  126. else
  127. {
  128. hr = pstg->CreateStream(psn.GetPropSetName(), grfMode, 0, 0, &_pstmPropSet);
  129. if( hr == S_OK )
  130. fCreated = TRUE;
  131. }
  132. if (hr == S_OK)
  133. {
  134. break;
  135. }
  136. else
  137. {
  138. PropDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::CPropertyStorage"
  139. " - CreateStream(%ls) attempt %d, hr=%08X\n", this, psn.GetPropSetName(), i+1, hr));
  140. if (hr != STG_E_FILEALREADYEXISTS)
  141. {
  142. break;
  143. }
  144. else
  145. if (i == 0 && (grfMode & STGM_CREATE) == STGM_CREATE)
  146. {
  147. pstg->DestroyElement(psn.GetPropSetName());
  148. }
  149. } // if (hr == S_OK) ... else
  150. i++;
  151. }
  152. if (hr == S_OK)
  153. {
  154. hr = InitializePropertyStream(CREATEPROP_CREATE,
  155. &rfmtid,
  156. pclsid);
  157. }
  158. if (hr != S_OK && fCreated)
  159. {
  160. //
  161. // if we fail after creating the property set in storage, cleanup.
  162. //
  163. pstg->DestroyElement(psn.GetPropSetName());
  164. }
  165. }
  166. //+-------------------------------------------------------------------
  167. //
  168. // Member: CPropertyStorage::_CreateDocumentSummary2Stream
  169. //
  170. // Synopsis: Open the "DocumentSummaryInformation" stream, creating
  171. // it if necessary.
  172. //
  173. // Arguments: [pstg] -- container storage
  174. // [psn] -- the property set name
  175. // [grfMode] -- mode of the property set
  176. // [fCreated] -- TRUE if Stream is created, FALSE if opened.
  177. //
  178. // Notes: This special case is necessary because this property set
  179. // is the only one in which we support more than one section.
  180. // For this property set, if the caller Creates the second
  181. // Section, we must not *Create* the Stream, because that would
  182. // lost the first Section. So, we must open it.
  183. //
  184. // This routine is only called when creating the second
  185. // Section. The first Section is created normally (note
  186. // that if the client creates the first section, the second
  187. // section is lost).
  188. //
  189. // Also note that it may not be possible to open the Stream,
  190. // since it may already be opened. This is significant
  191. // because it may not be obvious to the caller. I.e.,
  192. // to a client of IPropertyStorage, the 2 sections are
  193. // distinct property sets, and you would think that you could
  194. // open them for simultaneous write.
  195. //
  196. //--------------------------------------------------------------------
  197. HRESULT
  198. CPropertyStorage::_CreateDocumentSummary2Stream( IStorage * pstg,
  199. CPropSetName & psn,
  200. DWORD grfMode,
  201. BOOL * pfCreated )
  202. {
  203. HRESULT hr;
  204. DWORD grfOpenMode = grfMode & ~(STGM_CREATE | STGM_CONVERT);
  205. *pfCreated = FALSE;
  206. hr = pstg->OpenStream( psn.GetPropSetName(), NULL, grfOpenMode, 0L, &_pstmPropSet );
  207. // If the file wasn't there, try a create.
  208. if( hr == STG_E_FILENOTFOUND )
  209. {
  210. hr = pstg->CreateStream(psn.GetPropSetName(), grfMode, 0, 0, &_pstmPropSet);
  211. if( SUCCEEDED( hr ))
  212. {
  213. *pfCreated = TRUE;
  214. }
  215. }
  216. return( hr );
  217. } // CPropertyStorage::_CreateDocumentSummary2Stream()
  218. //+-------------------------------------------------------------------
  219. //
  220. // Member: CPropertyStorage::CPropertyStorage
  221. //
  222. // Synopsis: Constructor used to open a property storage on disk.
  223. //
  224. // Arguments: [pstg] -- container storage
  225. // [rfmtid] -- FMTID of property set to open
  226. // [grfMode] -- mode of the property set
  227. // [fDelete] -- Delete this property set from its stream
  228. // [phr] -- HRESULT returned here.
  229. //
  230. // Notes: Does not clean up on failure: this is done by the
  231. // destructor.
  232. //
  233. //--------------------------------------------------------------------
  234. CPropertyStorage::CPropertyStorage(
  235. IPrivateStorage *pprivstg,
  236. REFFMTID rfmtid,
  237. DWORD grfMode,
  238. BOOL fDelete,
  239. HRESULT *phr)
  240. {
  241. HRESULT &hr = *phr;
  242. CPropSetName psn(rfmtid);
  243. IStorage *pstgParent;
  244. IStorage *pstg = pprivstg->GetStorage();
  245. USHORT createprop = 0L;
  246. Initialize();
  247. _grfAccess = 3 & grfMode;
  248. _grfShare = 0xF0 & grfMode;
  249. // Is this the special-case second-section property set?
  250. _fUserDefinedProperties = ( rfmtid == FMTID_UserDefinedProperties ) ? TRUE : FALSE;
  251. // check for any mode flags disallowed in Open.
  252. if (grfMode & (STGM_CREATE | STGM_PRIORITY | STGM_CONVERT | STGM_TRANSACTED |
  253. STGM_SIMPLE | STGM_DELETEONRELEASE))
  254. {
  255. hr = STG_E_INVALIDFLAG;
  256. return;
  257. }
  258. hr = pstg->OpenStream(psn.GetPropSetName(), NULL, _grfAccess | _grfShare,
  259. 0, &_pstmPropSet);
  260. if (hr == S_OK)
  261. {
  262. pstgParent = pstg;
  263. }
  264. // Determine the CREATEPROP flags.
  265. if( fDelete )
  266. {
  267. createprop = CREATEPROP_DELETE;
  268. }
  269. else
  270. {
  271. createprop = (S_OK == IsWriteable() ?
  272. CREATEPROP_WRITE : CREATEPROP_READ);
  273. }
  274. if (hr == S_OK)
  275. {
  276. // sets up _usCodePage
  277. hr = InitializePropertyStream(
  278. createprop,
  279. &rfmtid,
  280. NULL);
  281. }
  282. }
  283. //+-------------------------------------------------------------------
  284. //
  285. // Member: CPropertyStorage::Initialize
  286. //
  287. // Synopsis: Initialize members to known values.
  288. //
  289. //--------------------------------------------------------------------
  290. VOID CPropertyStorage::Initialize(VOID)
  291. {
  292. _ulSig = PROPERTYSTORAGE_SIG;
  293. _cRefs = 1;
  294. _pstgPropSet = NULL;
  295. _pstmPropSet = NULL;
  296. _dwOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  297. _np = NULL;
  298. _ms = NULL;
  299. _usCodePage = CP_WINUNICODE;
  300. _grfFlags = 0;
  301. _grfAccess = 0;
  302. _grfShare = 0;
  303. _fUserDefinedProperties = FALSE;
  304. }
  305. //+-------------------------------------------------------------------
  306. //
  307. // Member: CPropertyStorage::InitializePropertyStream.
  308. //
  309. // Synopsis: Initialize the storage-type specific members.
  310. //
  311. // Arguments: [Flags] -- Flags for RtlCreatePropertySet: CREATEPROP_*
  312. // [pguid] -- FMTID, in for create only.
  313. // [pclsid] -- Class id, in for create only.
  314. //
  315. // Returns: HRESULT
  316. //
  317. // Requires:
  318. // _pstmPropSet -- The IStream of the main property set stream.
  319. //
  320. // Modifies: _ms (NTMAPPEDSTREAM)
  321. //
  322. // (assumed NULL on entry) will be NULL or valid on exit
  323. //
  324. // if _fNative, then _ms is CNtMappedStream*
  325. // if !_fNative, then _ms is CMappedStream* of CExposedStream
  326. //
  327. // _np (NTPROP) aka CPropertySetStream
  328. //
  329. // (assumed NULL on entry) will be NULL or valid on exit
  330. //
  331. // Notes:
  332. //
  333. //--------------------------------------------------------------------
  334. HRESULT
  335. CPropertyStorage::InitializePropertyStream(
  336. USHORT Flags,
  337. const GUID *pguid,
  338. GUID const *pclsid)
  339. {
  340. HRESULT hr;
  341. CExposedStream *pexpstm = (CExposedStream*)_pstmPropSet;
  342. PROPASSERT(pexpstm->Validate() != STG_E_INVALIDHANDLE );
  343. _ms = (CMappedStream*)pexpstm;
  344. hr = S_OK;
  345. PropDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::InitializePropertyStream"
  346. " - using CExposedDocfile as CMappedStream\n", this));
  347. NTSTATUS Status;
  348. Status = RtlCreatePropertySet(
  349. _ms,
  350. Flags,
  351. pguid,
  352. pclsid,
  353. (NTMEMORYALLOCATOR) & g_CoTaskAllocator,
  354. GetUserDefaultLCID(),
  355. &_dwOSVersion,
  356. &_usCodePage,
  357. &_np);
  358. if (!NT_SUCCESS(Status))
  359. {
  360. PropDbg((DEB_PROP_TRACE_CREATE, "CPropertyStorage(%08X)::InitializePropertyStream"
  361. " - RtlCreatePropertySet Status=%08X\n", this, Status));
  362. }
  363. if (NT_SUCCESS(Status))
  364. {
  365. if (_usCodePage != CP_WINUNICODE)
  366. _grfFlags |= PROPSETFLAG_ANSI; // for Stat
  367. }
  368. else
  369. {
  370. hr = DfpNtStatusToHResult(Status);
  371. }
  372. return(hr);
  373. }
  374. //+-------------------------------------------------------------------
  375. //
  376. // Member: CPropertyStorage::~CPropertyStorage
  377. //
  378. // Synopsis: Free up object resources.
  379. //
  380. // Notes: Cleans up even from partial construction.
  381. //
  382. //--------------------------------------------------------------------
  383. CPropertyStorage::~CPropertyStorage()
  384. {
  385. _ulSig = PROPERTYSTORAGE_SIGDEL; // prevent someone else deleting it
  386. if (_np != NULL)
  387. {
  388. // RtlFlushPropertySet(_np);
  389. RtlClosePropertySet(_np);
  390. }
  391. if (_pstmPropSet != NULL)
  392. _pstmPropSet->Release();
  393. if (_pstgPropSet != NULL)
  394. _pstgPropSet->Release();
  395. }
  396. //+-------------------------------------------------------------------
  397. //
  398. // Member: CPropertyStorage::QueryInterface, AddRef, Release
  399. //
  400. // Synopsis: IUnknown members
  401. //
  402. // Notes: IPropertyStorage supports IPropertyStorage and IUnknown
  403. //
  404. //--------------------------------------------------------------------
  405. HRESULT CPropertyStorage::QueryInterface( REFIID riid, void **ppvObject)
  406. {
  407. HRESULT hr;
  408. // ----------
  409. // Validation
  410. // ----------
  411. // Validate 'this'
  412. if (S_OK != (hr = ValidateRef()))
  413. return(hr);
  414. // Validate the inputs
  415. VDATEREADPTRIN( &riid, IID );
  416. VDATEPTROUT( ppvObject, void* );
  417. // -----------------
  418. // Perform the Query
  419. // -----------------
  420. *ppvObject = NULL;
  421. if (IsEqualIID(riid,IID_IPropertyStorage) || IsEqualIID(riid,IID_IUnknown))
  422. {
  423. *ppvObject = (IPropertyStorage *)this;
  424. CPropertyStorage::AddRef();
  425. }
  426. else
  427. {
  428. hr = E_NOINTERFACE;
  429. }
  430. return(hr);
  431. }
  432. ULONG CPropertyStorage::AddRef(void)
  433. {
  434. if (S_OK != ValidateRef())
  435. return(0);
  436. InterlockedIncrement(&_cRefs);
  437. return(_cRefs);
  438. }
  439. ULONG CPropertyStorage::Release(void)
  440. {
  441. LONG lRet;
  442. if (S_OK != ValidateRef())
  443. return(0);
  444. lRet = InterlockedDecrement(&_cRefs);
  445. if (lRet == 0)
  446. {
  447. delete this; // this will do a flush if dirty
  448. }
  449. else
  450. if (lRet <0)
  451. {
  452. lRet = 0;
  453. }
  454. return(lRet);
  455. }
  456. //+-------------------------------------------------------------------
  457. //
  458. // Member: CPropertyStorage::ReadMultiple
  459. //
  460. // Synopsis: Read properties from the property set.
  461. //
  462. // Arguments: [cpspec] -- Count of PROPSPECs in [rgpspec]
  463. // [rgpspec] -- Array of PROPSPECs
  464. // [rgpropvar] -- Array of PROPVARIANTs to be filled in
  465. // with callee allocated data.
  466. //
  467. // Returns: S_FALSE if none found
  468. // S_OK if >=1 found
  469. // FAILED(hr) otherwise.
  470. //
  471. //--------------------------------------------------------------------
  472. HRESULT CPropertyStorage::ReadMultiple(
  473. ULONG cpspec,
  474. const PROPSPEC rgpspec[],
  475. PROPVARIANT rgpropvar[])
  476. {
  477. NTSTATUS Status;
  478. HRESULT hr;
  479. ULONG cpropFound;
  480. // ----------
  481. // Validation
  482. // ----------
  483. // Validate 'this'
  484. if (S_OK != (hr = Validate()))
  485. goto errRet;
  486. if (S_OK != (hr = IsReverted()))
  487. goto errRet;
  488. if (S_OK != (hr = IsReadable()))
  489. goto errRet;
  490. // Validate inputs
  491. if (0 == cpspec)
  492. {
  493. hr = S_FALSE;
  494. goto errRet;
  495. }
  496. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  497. goto errRet;
  498. if (S_OK != (hr = ValidateOutRGPROPVARIANT( cpspec, rgpropvar )))
  499. goto errRet;
  500. // -------------------
  501. // Read the Properties
  502. // -------------------
  503. Status = RtlQueryProperties(
  504. _np,
  505. cpspec,
  506. rgpspec,
  507. NULL, // don't want PROPID's
  508. rgpropvar,
  509. &cpropFound);
  510. if (NT_SUCCESS(Status))
  511. {
  512. if (cpropFound == 0)
  513. {
  514. hr = S_FALSE;
  515. }
  516. }
  517. else
  518. {
  519. hr = DfpNtStatusToHResult(Status);
  520. }
  521. // ----
  522. // Exit
  523. // ----
  524. errRet:
  525. PropDbg((DEB_PROP_EXIT,
  526. "CPropertyStorage(%08X)::ReadMultiple(cpspec=%d, rgpspec=%08X, "
  527. "rgpropvar=%08X) returns %08X\n",
  528. this, cpspec, rgpspec, rgpropvar, hr));
  529. return(hr);
  530. }
  531. //+-------------------------------------------------------------------
  532. //
  533. // Member: CPropertyStorage::_WriteMultiple, private
  534. //
  535. // Synopsis: Write the properties to the property set. Allows
  536. // a NULL rgpropvar pointer for deletion case.
  537. //
  538. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  539. // [rgpspec] and [rgpropvar]
  540. //
  541. // [rgpspec] -- pointer to array of PROPSPECs
  542. //
  543. // [rgpropvar] -- pointer to array of PROPVARIANTs with
  544. // the values to write.
  545. //
  546. // [propidNameFirst] -- id below which not to assign
  547. // ids for named properties.
  548. //
  549. //
  550. // Returns: S_OK, -- all requested data was written.
  551. // Errors --
  552. //
  553. // Modifies:
  554. //
  555. // Derivation:
  556. //
  557. // Notes:
  558. // This routine assumes the object has been validated
  559. // and is writeable.
  560. //
  561. //--------------------------------------------------------------------
  562. HRESULT CPropertyStorage::_WriteMultiple(
  563. ULONG cpspec,
  564. const PROPSPEC rgpspec[],
  565. const PROPVARIANT rgpropvar[],
  566. PROPID propidNameFirst)
  567. {
  568. HRESULT hr;
  569. NTSTATUS Status;
  570. CStackPropIdArray spia;
  571. if (S_OK != (hr = spia.Init(cpspec)))
  572. return(hr);
  573. Status = RtlSetProperties(_np, // property set context
  574. cpspec, // property count
  575. propidNameFirst, // first propid for new named props
  576. rgpspec, // array of property specifiers
  577. spia.GetBuf(), // buffer for array of propids
  578. rgpropvar);
  579. if (!NT_SUCCESS(Status))
  580. {
  581. hr = DfpNtStatusToHResult(Status);
  582. }
  583. return(hr);
  584. }
  585. //+-------------------------------------------------------------------
  586. //
  587. // Member: CPropertyStorage::WriteMultiple
  588. //
  589. // Synopsis: Write properties.
  590. //
  591. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  592. // [rgpspec] and [rgpropvar]
  593. // [rgpspec] -- pointer to array of PROPSPECs
  594. // [rgpropvar] -- pointer to array of PROPVARIANTs with
  595. // the values to write.
  596. // [propidNameFirst] -- id below which not to assign
  597. // ids for named properties.
  598. //
  599. // Returns: S_OK, -- all requested data was written.
  600. // Errors -- accordingly
  601. //
  602. // Notes: Checks that rgpropvar is not NULL, then calls
  603. // _WriteMultiple.
  604. //
  605. //--------------------------------------------------------------------
  606. HRESULT CPropertyStorage::WriteMultiple(
  607. ULONG cpspec,
  608. const PROPSPEC rgpspec[],
  609. const PROPVARIANT rgpropvar[],
  610. PROPID propidNameFirst)
  611. {
  612. HRESULT hr;
  613. // ----------
  614. // Validation
  615. // ----------
  616. // Validate 'this'
  617. if (S_OK != (hr = Validate()))
  618. goto errRet;
  619. if (S_OK != (hr = IsReverted()))
  620. goto errRet;
  621. if (S_OK != (hr = IsWriteable()))
  622. goto errRet;
  623. // Validate the inputs
  624. if (0 == cpspec)
  625. {
  626. hr = S_OK;
  627. goto errRet;
  628. }
  629. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  630. goto errRet;
  631. if (S_OK != (hr = ValidateInRGPROPVARIANT( cpspec, rgpropvar )))
  632. goto errRet;
  633. // --------------------
  634. // Write the Properties
  635. // --------------------
  636. hr = _WriteMultiple(cpspec, rgpspec, rgpropvar, propidNameFirst);
  637. if (hr == STG_E_INSUFFICIENTMEMORY)
  638. {
  639. hr = S_OK;
  640. for (ULONG i=0; hr == S_OK && i < cpspec; i++)
  641. {
  642. hr = _WriteMultiple(1, rgpspec+i, rgpropvar+i, propidNameFirst);
  643. }
  644. }
  645. // ----
  646. // Exit
  647. // ----
  648. errRet:
  649. PropDbg((DEB_PROP_EXIT,
  650. "CPropertyStorage(%08X)::WriteMultiple(cpspec=%d, rgpspec=%08X, "
  651. "rgpropvar=%08X, propidNameFirst=%d) returns %08X\n",
  652. this, cpspec, rgpspec, rgpropvar, propidNameFirst, hr));
  653. return(hr);
  654. }
  655. //+-------------------------------------------------------------------
  656. //
  657. // Member: CPropertyStorage::DeleteMultiple
  658. //
  659. // Synopsis: Delete properties.
  660. //
  661. // Arguments: [cpspec] -- count of PROPSPECs and PROPVARIANTs in
  662. // [rgpspec] and [rgpropvar]
  663. // [rgpspec] -- pointer to array of PROPSPECs
  664. //
  665. // Returns: S_OK, -- all requested data was deleted.
  666. // Errors --
  667. //
  668. // Notes: Checks that rgpropvar is not NULL, then calls
  669. // _WriteMultiple.
  670. //
  671. //--------------------------------------------------------------------
  672. HRESULT CPropertyStorage::DeleteMultiple(
  673. ULONG cpspec,
  674. const PROPSPEC rgpspec[])
  675. {
  676. HRESULT hr;
  677. // ----------
  678. // Validation
  679. // ----------
  680. // Validate 'this'
  681. if (S_OK != (hr = Validate()))
  682. goto errRet;
  683. if (S_OK != (hr = IsReverted()))
  684. goto errRet;
  685. if (S_OK != (hr = IsWriteable()))
  686. goto errRet;
  687. // Validate the inputs
  688. if (0 == cpspec)
  689. {
  690. hr = S_OK;
  691. goto errRet;
  692. }
  693. if (S_OK != (hr = ValidateRGPROPSPEC( cpspec, rgpspec )))
  694. goto errRet;
  695. // ---------------------
  696. // Delete the Properties
  697. // ---------------------
  698. hr = _WriteMultiple(cpspec, rgpspec, NULL, 2);
  699. if (hr == STG_E_INSUFFICIENTMEMORY)
  700. {
  701. hr = S_OK;
  702. for (ULONG i=0; hr == S_OK && i < cpspec; i++)
  703. {
  704. hr = _WriteMultiple(1, rgpspec+i, NULL, 2);
  705. }
  706. }
  707. // ----
  708. // Exit
  709. // ----
  710. errRet:
  711. PropDbg((DEB_PROP_EXIT,
  712. "CPropertyStorage(%08X)::DeleteMultiple(cpspec=%d, rgpspec=%08X) "
  713. "returns %08X\n",
  714. this, cpspec, rgpspec, hr));
  715. return hr;
  716. }
  717. //+-------------------------------------------------------------------
  718. //
  719. // Member: CPropertyStorage::ReadPropertyNames
  720. //
  721. // Synopsis: Attempt to read names for all identified properties.
  722. //
  723. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  724. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  725. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  726. //
  727. // Returns: S_OK -- success, one or more names returned
  728. // S_FALSE -- success, no names returned
  729. // STG_E_INVALIDHEADER -- no propid->name mapping property
  730. // other errors -- STG_E_INSUFFICIENTMEMORY etc
  731. //
  732. //--------------------------------------------------------------------
  733. HRESULT CPropertyStorage::ReadPropertyNames(
  734. ULONG cpropid,
  735. const PROPID rgpropid[],
  736. LPOLESTR rglpwstrName[])
  737. {
  738. HRESULT hr;
  739. NTSTATUS Status;
  740. // --------
  741. // Validate
  742. // --------
  743. // Validate 'this'
  744. if (S_OK != (hr = Validate()))
  745. goto errRet;
  746. if (S_OK != (hr = IsReverted()))
  747. goto errRet;
  748. if (S_OK != (hr = IsReadable()))
  749. goto errRet;
  750. // Validate the inputs
  751. if (0 == cpropid)
  752. {
  753. hr = S_FALSE;
  754. goto errRet;
  755. }
  756. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  757. goto errRet;
  758. if (S_OK != (hr = ValidateOutRGLPOLESTR( cpropid, rglpwstrName )))
  759. goto errRet;
  760. // --------------
  761. // Read the Names
  762. // --------------
  763. Status = RtlQueryPropertyNames(_np, cpropid, rgpropid, rglpwstrName);
  764. if (Status == STATUS_NOT_FOUND)
  765. hr = STG_E_INVALIDHEADER;
  766. else
  767. if (Status == STATUS_BUFFER_ALL_ZEROS)
  768. hr = S_FALSE;
  769. else
  770. if (!NT_SUCCESS(Status))
  771. hr = DfpNtStatusToHResult(Status);
  772. // ----
  773. // Exit
  774. // ----
  775. errRet:
  776. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::ReadPropertyNames(cpropid=%d, rgpropid=%08X, "
  777. "rglpwstrName=%08X) returns %08X\n",
  778. this, cpropid, rgpropid, rglpwstrName, hr));
  779. return hr;
  780. }
  781. //+-------------------------------------------------------------------
  782. //
  783. // Member: CPropertyStorage::_WritePropertyNames
  784. //
  785. // Synopsis: Internal function used by WritePropertyNames and
  786. // DeletePropertyNames.
  787. //
  788. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  789. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  790. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  791. //
  792. // Returns: S_OK if successful, otherwise error code.
  793. //
  794. //--------------------------------------------------------------------
  795. HRESULT CPropertyStorage::_WritePropertyNames(
  796. ULONG cpropid,
  797. const PROPID rgpropid[],
  798. const LPOLESTR rglpwstrName[])
  799. {
  800. NTSTATUS Status;
  801. Status = RtlSetPropertyNames(_np, cpropid, rgpropid,
  802. (OLECHAR const* const*) rglpwstrName);
  803. return NT_SUCCESS(Status) ? S_OK : DfpNtStatusToHResult(Status);
  804. }
  805. //+-------------------------------------------------------------------
  806. //
  807. // Member: CPropertyStorage::WritePropertyNames
  808. //
  809. // Synopsis: Attempt to write names for all identified properties.
  810. //
  811. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  812. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  813. // [rglpstrName] -- Pointer to array of [cpropid] LPOLESTRs
  814. //
  815. // Returns: S_OK -- success, otherwise error code.
  816. //
  817. //--------------------------------------------------------------------
  818. HRESULT CPropertyStorage::WritePropertyNames(
  819. ULONG cpropid,
  820. const PROPID rgpropid[],
  821. const LPOLESTR rglpwstrName[])
  822. {
  823. HRESULT hr;
  824. // ----------
  825. // Validation
  826. // ----------
  827. // Validate 'this'
  828. if (S_OK != (hr = Validate()))
  829. goto errRet;
  830. if (S_OK != (hr = IsReverted()))
  831. goto errRet;
  832. if (S_OK != (hr = IsWriteable()))
  833. goto errRet;
  834. // Validate inputs
  835. if (0 == cpropid)
  836. {
  837. hr = S_OK;
  838. goto errRet;
  839. }
  840. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  841. goto errRet;
  842. if (S_OK != (hr = ValidateInRGLPOLESTR( cpropid, rglpwstrName )))
  843. goto errRet;
  844. // ---------------
  845. // Write the Names
  846. // ---------------
  847. hr = _WritePropertyNames(cpropid, rgpropid, rglpwstrName);
  848. if (hr == STG_E_INSUFFICIENTMEMORY)
  849. {
  850. hr = S_OK;
  851. for (ULONG i=0; hr == S_OK && i < cpropid; i++)
  852. {
  853. hr = _WritePropertyNames(1, rgpropid+i, rglpwstrName+i);
  854. }
  855. }
  856. // ----
  857. // Exit
  858. // ----
  859. errRet:
  860. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::WritePropertyNames(cpropid=%d, rgpropid=%08X, "
  861. "rglpwstrName=%08X) returns %08X\n",
  862. this, cpropid, rgpropid, rglpwstrName, hr));
  863. return hr;
  864. }
  865. //+-------------------------------------------------------------------
  866. //
  867. // Member: CPropertyStorage::DeletePropertyNames
  868. //
  869. // Synopsis: Attempt to delete names for all identified properties.
  870. //
  871. // Arguments: [cpropid] -- Count of PROPIDs in [rgpropid]
  872. // [rgpropid] -- Pointer to array of [cpropid] PROPIDs
  873. //
  874. // Returns: S_OK -- success, otherwise error.
  875. //
  876. //--------------------------------------------------------------------
  877. HRESULT CPropertyStorage::DeletePropertyNames(
  878. ULONG cpropid,
  879. const PROPID rgpropid[])
  880. {
  881. HRESULT hr;
  882. // ----------
  883. // Validation
  884. // ----------
  885. // Validate 'this'
  886. if (S_OK != (hr = Validate()))
  887. goto errRet;
  888. if (S_OK != (hr = IsReverted()))
  889. goto errRet;
  890. if (S_OK != (hr = IsWriteable()))
  891. goto errRet;
  892. // Validate the inputs
  893. if( 0 == cpropid )
  894. {
  895. hr = S_OK;
  896. goto errRet;
  897. }
  898. if (S_OK != (hr = ValidateRGPROPID( cpropid, rgpropid )))
  899. goto errRet;
  900. // ----------------
  901. // Delete the Names
  902. // ----------------
  903. hr = _WritePropertyNames(cpropid, rgpropid, NULL);
  904. if (hr == STG_E_INSUFFICIENTMEMORY)
  905. {
  906. hr = S_OK;
  907. for (ULONG i=0; hr == S_OK && i < cpropid; i++)
  908. {
  909. hr = _WritePropertyNames(1, rgpropid+i, NULL);
  910. }
  911. }
  912. // ----
  913. // Exit
  914. // ----
  915. errRet:
  916. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::DeletePropertyNames(cpropid=%d, rgpropid=%08X) "
  917. "returns %08X\n",
  918. this, cpropid, rgpropid, hr));
  919. return hr;
  920. }
  921. //+-------------------------------------------------------------------
  922. //
  923. // Member: CPropertyStorage::Commit
  924. //
  925. // Synopsis: Flush and/or commit the property set
  926. //
  927. // Arguments: [grfCommittFlags] -- Commit flags.
  928. //
  929. // Returns: S_OK -- success, otherwise error.
  930. //
  931. // Notes: For both simple and non-simple, this flushes the
  932. // memory image to disk subsystem. In addition,
  933. // for non-simple transacted-mode property sets, this
  934. // performs a commit on the property set.
  935. //
  936. //--------------------------------------------------------------------
  937. HRESULT CPropertyStorage::Commit(DWORD grfCommitFlags)
  938. {
  939. HRESULT hr;
  940. NTSTATUS Status;
  941. // ----------
  942. // Validation
  943. // ----------
  944. // Validate 'this'
  945. if (S_OK != (hr = Validate()))
  946. goto errRet;
  947. if (S_OK != (hr = IsReverted()))
  948. goto errRet;
  949. if (S_OK != (hr = IsWriteable()))
  950. goto errRet;
  951. // Validate the inputs
  952. if (S_OK != (hr = VerifyCommitFlags(grfCommitFlags)))
  953. goto errRet;
  954. // --------------------------
  955. // Commit the PropertyStorage
  956. // --------------------------
  957. Status = RtlFlushPropertySet(_np);
  958. if (!NT_SUCCESS(Status))
  959. {
  960. hr = DfpNtStatusToHResult(Status);
  961. }
  962. // ----
  963. // Exit
  964. // ----
  965. errRet:
  966. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::Commit(grfCommitFlags=%08X) "
  967. "returns %08X\n",
  968. this, grfCommitFlags, hr));
  969. return(hr);
  970. }
  971. //+-------------------------------------------------------------------
  972. //
  973. // Member: CPropertyStorage::Revert
  974. //
  975. // Synopsis: For non-simple property sets, revert it.
  976. //
  977. // Returns: S_OK if successful. STG_E_UNIMPLEMENTEDFUNCTION for
  978. // simple property sets.
  979. //
  980. // Notes: For non-simple property sets, call the underlying
  981. // storage's Revert and re-open the 'contents' stream.
  982. //
  983. //--------------------------------------------------------------------
  984. HRESULT CPropertyStorage::Revert()
  985. {
  986. HRESULT hr;
  987. hr = Validate();
  988. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::Revert() "
  989. "returns %08X\n",
  990. this, hr));
  991. return(hr);
  992. }
  993. //+-------------------------------------------------------------------
  994. //
  995. // Member: CPropertyStorage::Enum
  996. //
  997. // Synopsis: Create an enumerator over the property set.
  998. //
  999. // Arguments: [ppenum] -- where to return the IEnumSTATPROPSTG *
  1000. //
  1001. // Returns: S_OK or error.
  1002. //
  1003. // Notes: The constructor of CEnumSTATPROPSTG creates a
  1004. // CStatArray which reads the entire property set and
  1005. // which can be shared when IEnumSTATPROPSTG::Clone is
  1006. // used.
  1007. //
  1008. //--------------------------------------------------------------------
  1009. HRESULT CPropertyStorage::Enum(IEnumSTATPROPSTG ** ppenum)
  1010. {
  1011. HRESULT hr;
  1012. // ----------
  1013. // Validation
  1014. // ----------
  1015. // Validate 'this'
  1016. if (S_OK != (hr = Validate()))
  1017. return(hr);
  1018. if (S_OK != (hr = IsReadable()))
  1019. return(hr);
  1020. if (S_OK != (hr = IsReverted()))
  1021. return(hr);
  1022. // Validate the inputs
  1023. VDATEPTROUT( ppenum, IEnumSTATPROPSTG* );
  1024. // ----------------------
  1025. // Create the Enumeration
  1026. // ----------------------
  1027. *ppenum = NULL;
  1028. hr = STG_E_INSUFFICIENTMEMORY;
  1029. *ppenum = new CEnumSTATPROPSTG(_np, &hr);
  1030. if (FAILED(hr))
  1031. {
  1032. delete (CEnumSTATPROPSTG*) *ppenum;
  1033. *ppenum = NULL;
  1034. }
  1035. // ----
  1036. // Exit
  1037. // ----
  1038. return(hr);
  1039. }
  1040. //+-------------------------------------------------------------------
  1041. //
  1042. // Member: CPropertyStorage::SetTimes
  1043. //
  1044. // Synopsis: Set the given times on the underlying storage
  1045. //
  1046. // Arguments: [pctime] -- creation time
  1047. // [patime[ -- access time
  1048. // [pmtime] -- modify time
  1049. //
  1050. // Returns: S_OK or error.
  1051. //
  1052. // Notes:
  1053. // (non-simple only) Only the times supported by the
  1054. // underlying docfile implementation are
  1055. // supported.
  1056. //
  1057. //--------------------------------------------------------------------
  1058. HRESULT CPropertyStorage::SetTimes(
  1059. FILETIME const * pctime,
  1060. FILETIME const * patime,
  1061. FILETIME const * pmtime)
  1062. {
  1063. HRESULT hr;
  1064. // ----------
  1065. // Validation
  1066. // ----------
  1067. // Validate 'this'
  1068. if (S_OK != (hr = Validate()))
  1069. goto errRet;
  1070. if (S_OK != (hr = IsReverted()))
  1071. goto errRet;
  1072. if (S_OK != (hr = IsWriteable()))
  1073. goto errRet;
  1074. // Validate the inputs
  1075. VDATEPTRIN_LABEL( pctime, FILETIME, errRet, hr );
  1076. VDATEPTRIN_LABEL( patime, FILETIME, errRet, hr );
  1077. VDATEPTRIN_LABEL( pmtime, FILETIME, errRet, hr );
  1078. // since we only support non-simple, this function does not
  1079. // do anything
  1080. // ----
  1081. // Exit
  1082. // ----
  1083. errRet:
  1084. PropDbg((DEB_PROP_EXIT,
  1085. "CPropertyStorage(%08X)::SetTimes("
  1086. "pctime=%08X, patime=%08X, pmtime=%08X) returns %08X\n",
  1087. this, pctime, patime, pmtime, hr));
  1088. return(hr);
  1089. }
  1090. //+-------------------------------------------------------------------
  1091. //
  1092. // Member: CPropertyStorage::SetClass
  1093. //
  1094. // Synopsis: Sets the class of the property set.
  1095. //
  1096. // Arguments: [clsid] -- class id to set.
  1097. //
  1098. // Returns: S_OK or error.
  1099. //
  1100. // Notes: Have clsid set into the property set stream.
  1101. //
  1102. //--------------------------------------------------------------------
  1103. HRESULT CPropertyStorage::SetClass(REFCLSID clsid)
  1104. {
  1105. HRESULT hr;
  1106. NTSTATUS Status;
  1107. DBGBUF(buf);
  1108. // ----------
  1109. // Validation
  1110. // ----------
  1111. // Validate 'this'
  1112. if (S_OK != (hr = Validate()))
  1113. goto errRet;
  1114. if (S_OK != (hr = IsReverted()))
  1115. goto errRet;
  1116. if (S_OK != (hr = IsWriteable()))
  1117. goto errRet;
  1118. // Validate the inputs
  1119. GEN_VDATEREADPTRIN_LABEL(&clsid, CLSID, E_INVALIDARG, errRet, hr);
  1120. // -------------
  1121. // Set the CLSID
  1122. // -------------
  1123. // Set it in the property set header
  1124. Status = RtlSetPropertySetClassId(_np, &clsid);
  1125. if (!NT_SUCCESS(Status))
  1126. hr = DfpNtStatusToHResult(Status);
  1127. // ----
  1128. // Exit
  1129. // ----
  1130. errRet:
  1131. if( E_INVALIDARG != hr )
  1132. {
  1133. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::SetClass(clsid=%s) "
  1134. "returns %08X\n",
  1135. this, DbgFmtId(clsid, buf), hr));
  1136. }
  1137. else
  1138. {
  1139. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::SetClass(clsid@%08X) "
  1140. "returns %08X\n",
  1141. this, &clsid, hr));
  1142. }
  1143. return(hr);
  1144. }
  1145. //+-------------------------------------------------------------------
  1146. //
  1147. // Member: CPropertyStorage::Stat
  1148. //
  1149. // Synopsis: Get STATPROPSETSTG about the property set.
  1150. //
  1151. // Arguments: [p] -- STATPROPSETSTG *
  1152. //
  1153. // Returns: S_OK if successful, error otherwise. On failure,
  1154. // *p is all zeros.
  1155. //
  1156. // Notes: See spec. Gets times from underlying storage or stream
  1157. // using IStorage or IStream ::Stat.
  1158. //
  1159. //--------------------------------------------------------------------
  1160. HRESULT CPropertyStorage::Stat(STATPROPSETSTG * p)
  1161. {
  1162. HRESULT hr;
  1163. NTSTATUS Status;
  1164. // ----------
  1165. // Validation
  1166. // ----------
  1167. // Validate 'this'
  1168. if (S_OK != (hr = Validate()))
  1169. goto errRet;
  1170. if (S_OK != (hr = IsReverted()))
  1171. goto errRet;
  1172. if (S_OK != (hr = IsReadable()))
  1173. goto errRet;
  1174. // Validate inputs
  1175. VDATEPTROUT_LABEL(p, STATPROPSETSTG, errRet, hr);
  1176. // ------------
  1177. // Get the Stat
  1178. // ------------
  1179. ZeroMemory(p, sizeof(*p));
  1180. // returns mtime, ansi flag, clsid, fmtid
  1181. Status = RtlQueryPropertySet(_np, p);
  1182. if (NT_SUCCESS(Status))
  1183. {
  1184. STATSTG statstg;
  1185. hr = S_OK;
  1186. hr = _pstmPropSet->Stat(&statstg, STATFLAG_NONAME);
  1187. if (hr == S_OK)
  1188. {
  1189. p->mtime = statstg.mtime;
  1190. p->ctime = statstg.ctime;
  1191. p->atime = statstg.atime;
  1192. p->grfFlags = _grfFlags;
  1193. p->dwOSVersion = _dwOSVersion;
  1194. }
  1195. }
  1196. else
  1197. {
  1198. hr = DfpNtStatusToHResult(Status);
  1199. }
  1200. if (FAILED(hr))
  1201. {
  1202. ZeroMemory(p, sizeof(*p));
  1203. }
  1204. // ----
  1205. // Exit
  1206. // ----
  1207. errRet:
  1208. PropDbg((DEB_PROP_EXIT, "CPropertyStorage(%08X)::Stat(STATPROPSETSTG *p = %08X) "
  1209. "returns %08X\n",
  1210. this, p, hr));
  1211. return(hr);
  1212. }
  1213. //+-------------------------------------------------------------------
  1214. //
  1215. // Member: CStatArray::CStatArray
  1216. //
  1217. // Synopsis: Read in the enumeration using RtlEnumerateProperties
  1218. //
  1219. // Arguments: [np] -- the NTPROP to use
  1220. // [phr] -- S_OK on success, error otherwise.
  1221. //
  1222. // Notes: Retry getting number of properties and reading all of
  1223. // them into a caller-allocated buffer until it fits.
  1224. //
  1225. //--------------------------------------------------------------------
  1226. CStatArray::CStatArray(NTPROP np, HRESULT *phr)
  1227. {
  1228. NTSTATUS Status;
  1229. ULONG ulKeyZero;
  1230. ULONG cpropAllocated;
  1231. _cRefs = 1;
  1232. _psps = NULL;
  1233. do
  1234. {
  1235. // when *pkey == 0, *pcprop == MAXULONG, aprs == NULL and asps == NULL on input,
  1236. // *pcprop will be the total count of properties in the enumeration set. OLE needs to
  1237. // allocate memory and enumerate out of the cached PROPID+propname list.
  1238. ulKeyZero = 0;
  1239. _cpropActual = MAX_ULONG;
  1240. delete [] _psps;
  1241. _psps = NULL;
  1242. Status = RtlEnumerateProperties(
  1243. np,
  1244. ENUMPROP_NONAMES,
  1245. &ulKeyZero,
  1246. &_cpropActual,
  1247. NULL, // aprs
  1248. NULL);
  1249. if (!NT_SUCCESS(Status))
  1250. break;
  1251. cpropAllocated = _cpropActual + 1;
  1252. _psps = new STATPROPSTG [ cpropAllocated ];
  1253. if (_psps == NULL)
  1254. {
  1255. Status = STATUS_INSUFFICIENT_RESOURCES;
  1256. break;
  1257. }
  1258. ulKeyZero = 0;
  1259. Status = RtlEnumerateProperties(
  1260. np,
  1261. 0,
  1262. &ulKeyZero,
  1263. &cpropAllocated,
  1264. NULL, // aprs
  1265. _psps);
  1266. } while (NT_SUCCESS(Status) && cpropAllocated != _cpropActual);
  1267. *phr = NT_SUCCESS(Status) ? S_OK : DfpNtStatusToHResult(Status);
  1268. }
  1269. //+-------------------------------------------------------------------
  1270. //
  1271. // Member: CStatArray::~CStatArray
  1272. //
  1273. // Synopsis: Deallocated the object's data.
  1274. //
  1275. //--------------------------------------------------------------------
  1276. CStatArray::~CStatArray()
  1277. {
  1278. if (_psps != NULL)
  1279. {
  1280. CleanupSTATPROPSTG(_cpropActual, _psps);
  1281. }
  1282. delete [] _psps;
  1283. }
  1284. //+-------------------------------------------------------------------
  1285. //
  1286. // Member: CStatArray::NextAt
  1287. //
  1288. // Synopsis: Read from the internal STATPROPSTG array.
  1289. //
  1290. // Effects: The cursor is passed in, and this function acts
  1291. // as a IEnumXX::Next would behave if the current cursor
  1292. // was [ipropNext].
  1293. //
  1294. // Arguments: [ipropNext] -- index of cursor to use
  1295. // [pspsDest] -- if NULL, emulate read's effect on cursor.
  1296. // if non-NULL, return data with cursor effect.
  1297. // [pceltFetched] -- buffer for count fetched
  1298. //
  1299. // Returns: STATUS_SUCCESS if successful, otherwise
  1300. // STATUS_INSUFFICIENT_RESOURCES.
  1301. //
  1302. // Notes:
  1303. //
  1304. //--------------------------------------------------------------------
  1305. NTSTATUS
  1306. CStatArray::NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched)
  1307. {
  1308. ULONG ipropLastPlus1;
  1309. //
  1310. // Copy the requested number of elements from the cache
  1311. // (including strings, the allocation of which may fail.)
  1312. //
  1313. ipropLastPlus1 = ipropNext + *pceltFetched;
  1314. if (ipropLastPlus1 > _cpropActual)
  1315. {
  1316. ipropLastPlus1 = _cpropActual;
  1317. }
  1318. *pceltFetched = ipropLastPlus1 - ipropNext;
  1319. if (pspsDest != NULL)
  1320. return CopySTATPROPSTG(*pceltFetched, pspsDest, _psps + ipropNext);
  1321. else
  1322. return(STATUS_SUCCESS);
  1323. }
  1324. //+-------------------------------------------------------------------
  1325. //
  1326. // Member: CEnumSTATPROPSTG::CEnumSTATPROPSTG
  1327. //
  1328. // Synopsis: Constructor for object that has cursor over CStatArray
  1329. // and implements IEnumSTATPROPSTG, used by
  1330. // CPropertyStorage::Enum.
  1331. //
  1332. // Arguments: [np] -- the NTPROP to use
  1333. // [phr] -- where to put the HRESULT
  1334. //
  1335. //--------------------------------------------------------------------
  1336. CEnumSTATPROPSTG::CEnumSTATPROPSTG(NTPROP np, HRESULT *phr)
  1337. {
  1338. _ulSig = ENUMSTATPROPSTG_SIG;
  1339. _cRefs = 1;
  1340. _psa = new CStatArray(np, phr);
  1341. _ipropNext = 0;
  1342. }
  1343. //+-------------------------------------------------------------------
  1344. //
  1345. // Member: CEnumSTATPROPSTG::CEnumSTATPROPSTG
  1346. //
  1347. // Synopsis: Constructor which is used by IEnumSTATPROPSTG::Clone.
  1348. //
  1349. // Arguments: [other] -- the CEnumSTATPROPSTG to copy
  1350. // [phr] -- the error code.
  1351. //
  1352. // Notes: Since the CStatArray actually contains the object this
  1353. // just adds to the ref count.
  1354. //
  1355. //--------------------------------------------------------------------
  1356. CEnumSTATPROPSTG::CEnumSTATPROPSTG(const CEnumSTATPROPSTG & other, HRESULT *phr)
  1357. {
  1358. _ulSig = ENUMSTATPROPSTG_SIG;
  1359. _cRefs = 1;
  1360. _psa = other._psa;
  1361. _psa->AddRef();
  1362. _ipropNext = other._ipropNext;
  1363. *phr = S_OK;
  1364. }
  1365. //+-------------------------------------------------------------------
  1366. //
  1367. // Member: CEnumSTATPROPSTG::~CEnumSTATPROPSTG
  1368. //
  1369. // Synopsis: Deallocated storage.
  1370. //
  1371. // Arguments:
  1372. //
  1373. // Returns:
  1374. //
  1375. // Notes:
  1376. //
  1377. //--------------------------------------------------------------------
  1378. CEnumSTATPROPSTG::~CEnumSTATPROPSTG()
  1379. {
  1380. _ulSig = ENUMSTATPROPSTG_SIGDEL; // prevent another thread doing it - kinda
  1381. if (_psa != NULL)
  1382. _psa->Release();
  1383. }
  1384. //+-------------------------------------------------------------------
  1385. //
  1386. // Member: CEnumSTATPROPSTG::QueryInterface
  1387. //
  1388. // Synopsis: Respond to IEnumSTATPROPSTG and IUnknown.
  1389. //
  1390. // Returns: S_OK or E_NOINTERFACE
  1391. //
  1392. //--------------------------------------------------------------------
  1393. HRESULT CEnumSTATPROPSTG::QueryInterface( REFIID riid, void **ppvObject)
  1394. {
  1395. HRESULT hr;
  1396. *ppvObject = NULL;
  1397. if (S_OK != (hr = Validate()))
  1398. return(hr);
  1399. if (IsEqualIID(riid, IID_IEnumSTATPROPSTG))
  1400. {
  1401. *ppvObject = (IEnumSTATPROPSTG *)this;
  1402. AddRef();
  1403. }
  1404. else
  1405. if (IsEqualIID(riid, IID_IUnknown))
  1406. {
  1407. *ppvObject = (IUnknown *)this;
  1408. AddRef();
  1409. }
  1410. else
  1411. {
  1412. hr = E_NOINTERFACE;
  1413. }
  1414. return(hr);
  1415. }
  1416. //+-------------------------------------------------------------------
  1417. //
  1418. // Member: CEnumSTATPROPSTG::AddRef
  1419. //
  1420. // Synopsis: Add 1 to ref count.
  1421. //
  1422. //--------------------------------------------------------------------
  1423. ULONG CEnumSTATPROPSTG::AddRef(void)
  1424. {
  1425. if (S_OK != Validate())
  1426. return(0);
  1427. InterlockedIncrement(&_cRefs);
  1428. return(_cRefs);
  1429. }
  1430. //+-------------------------------------------------------------------
  1431. //
  1432. // Member: CEnumSTATPROPSTG::Release
  1433. //
  1434. // Synopsis: Subtract 1 from ref count and delete if 0.
  1435. //
  1436. //--------------------------------------------------------------------
  1437. ULONG CEnumSTATPROPSTG::Release(void)
  1438. {
  1439. LONG lRet;
  1440. if (S_OK != Validate())
  1441. return(0);
  1442. lRet = InterlockedDecrement(&_cRefs);
  1443. if (lRet == 0)
  1444. {
  1445. delete this;
  1446. }
  1447. else
  1448. if (lRet <0)
  1449. {
  1450. lRet = 0;
  1451. }
  1452. return(lRet);
  1453. }
  1454. //+-------------------------------------------------------------------
  1455. //
  1456. // Function: CopySTATPROPSTG
  1457. //
  1458. // Synopsis: Copy out the range of elements from [pspsSrc] to
  1459. // [pspsDest].
  1460. //
  1461. // Arguments: [celt] -- count of elements to copy
  1462. // [pspsDest] -- where to copy to, always filled with
  1463. // zeros before anything else (helps cleanup
  1464. // case.)
  1465. //
  1466. // [pspsSrc] -- where to copy from
  1467. //
  1468. // Returns: STATUS_SUCCESS if ok, otherwise
  1469. // STATUS_INSUFFICIENT_RESOURCES in which case there
  1470. // may be pointers that need deallocating. Use
  1471. // CleanupSTATPROPSTG to do that.
  1472. //
  1473. //--------------------------------------------------------------------
  1474. NTSTATUS
  1475. CopySTATPROPSTG(ULONG celt,
  1476. STATPROPSTG * pspsDest,
  1477. const STATPROPSTG * pspsSrc)
  1478. {
  1479. memset(pspsDest, 0, sizeof(*pspsDest) * celt);
  1480. while (celt)
  1481. {
  1482. *pspsDest = *pspsSrc;
  1483. if (pspsSrc->lpwstrName != NULL)
  1484. {
  1485. pspsDest->lpwstrName = (LPOLESTR)CoTaskMemAlloc(
  1486. sizeof(OLECHAR)*(1+ocslen(pspsSrc->lpwstrName)));
  1487. if (pspsDest->lpwstrName != NULL)
  1488. {
  1489. ocscpy(pspsDest->lpwstrName,
  1490. pspsSrc->lpwstrName);
  1491. }
  1492. else
  1493. {
  1494. return STATUS_INSUFFICIENT_RESOURCES;
  1495. }
  1496. }
  1497. celt--;
  1498. pspsDest++;
  1499. pspsSrc++;
  1500. }
  1501. return(STATUS_SUCCESS);
  1502. }
  1503. //+-------------------------------------------------------------------
  1504. //
  1505. // Member: CleanupSTATPROPSTG
  1506. //
  1507. // Synopsis: Free any elements in the passed array.
  1508. //
  1509. // Arguments: [celt] -- number of elements to examine.
  1510. // [psps] -- array of STATPROPSTG to examine.
  1511. //
  1512. // Notes: Zeros them out too.
  1513. //
  1514. //--------------------------------------------------------------------
  1515. VOID
  1516. CleanupSTATPROPSTG(ULONG celt, STATPROPSTG * psps)
  1517. {
  1518. while (celt)
  1519. {
  1520. CoTaskMemFree(psps->lpwstrName);
  1521. memset(psps, 0, sizeof(*psps));
  1522. celt--;
  1523. psps++;
  1524. }
  1525. }
  1526. //+-------------------------------------------------------------------
  1527. //
  1528. // Member: CEnumSTATPROPSTG::Next
  1529. //
  1530. // Synopsis: Get the next [celt] STATPROPSTGs from the enumerator.
  1531. //
  1532. // Arguments: [celt] -- count requested.
  1533. // [rgelt] -- where to return them
  1534. // [pceltFetched] -- buffer for returned-count.
  1535. // if pceltFetched==NULL && celt != 1 -> STG_E_INVALIDPARAMETER
  1536. // if pceltFetched!=NULL && celt == 0 -> S_OK
  1537. //
  1538. // Returns: S_OK if successful, otherwise error.
  1539. //
  1540. //--------------------------------------------------------------------
  1541. HRESULT CEnumSTATPROPSTG::Next(
  1542. ULONG celt,
  1543. STATPROPSTG * rgelt,
  1544. ULONG * pceltFetched)
  1545. {
  1546. HRESULT hr;
  1547. NTSTATUS Status;
  1548. ULONG celtFetched = celt;
  1549. // ----------
  1550. // Validation
  1551. // ----------
  1552. // Validate 'this'
  1553. if (S_OK != (hr = Validate()))
  1554. return(hr);
  1555. // Validate the inputs
  1556. if (NULL == pceltFetched)
  1557. {
  1558. if (celt != 1)
  1559. return(STG_E_INVALIDPARAMETER);
  1560. }
  1561. else
  1562. {
  1563. VDATEPTROUT( pceltFetched, ULONG );
  1564. *pceltFetched = 0;
  1565. }
  1566. if( 0 == celt )
  1567. return( S_OK );
  1568. if( !IsValidPtrOut(rgelt, celt * sizeof(rgelt[0])) )
  1569. return( E_INVALIDARG );
  1570. // -----------------------
  1571. // Perform the enumeration
  1572. // -----------------------
  1573. if (celt == 0)
  1574. return(hr);
  1575. Status = _psa->NextAt(_ipropNext, rgelt, &celtFetched);
  1576. if (NT_SUCCESS(Status))
  1577. {
  1578. _ipropNext += celtFetched;
  1579. if (pceltFetched != NULL)
  1580. *pceltFetched = celtFetched;
  1581. hr = celtFetched == celt ? S_OK : S_FALSE;
  1582. }
  1583. else
  1584. {
  1585. CleanupSTATPROPSTG(celt, rgelt);
  1586. hr = DfpNtStatusToHResult(Status);
  1587. }
  1588. return(hr);
  1589. }
  1590. //+-------------------------------------------------------------------
  1591. //
  1592. // Member: CEnumSTATPROPSTG::Skip
  1593. //
  1594. // Synopsis: Skip the next [celt] elements in the enumeration.
  1595. //
  1596. // Arguments: [celt] -- number of elts to skip
  1597. //
  1598. // Returns: S_OK if skipped [celt] elements
  1599. // S_FALSE if skipped < [celt] elements
  1600. //
  1601. // Notes:
  1602. //
  1603. //--------------------------------------------------------------------
  1604. HRESULT CEnumSTATPROPSTG::Skip(ULONG celt)
  1605. {
  1606. HRESULT hr;
  1607. ULONG celtFetched = celt;
  1608. if (S_OK != (hr = Validate()))
  1609. return(hr);
  1610. _psa->NextAt(_ipropNext, NULL, &celtFetched);
  1611. _ipropNext += celtFetched;
  1612. return celtFetched == celt ? S_OK : S_FALSE;
  1613. }
  1614. //+-------------------------------------------------------------------
  1615. //
  1616. // Member: CEnumSTATPROPSTG::Reset
  1617. //
  1618. // Synopsis: Set cursor to beginnging of enumeration.
  1619. //
  1620. // Returns: S_OK otherwise STG_E_INVALIDHANDLE.
  1621. //
  1622. //--------------------------------------------------------------------
  1623. HRESULT CEnumSTATPROPSTG::Reset()
  1624. {
  1625. HRESULT hr;
  1626. if (S_OK != (hr = Validate()))
  1627. return(hr);
  1628. _ipropNext = 0;
  1629. return(S_OK);
  1630. }
  1631. //+-------------------------------------------------------------------
  1632. //
  1633. // Member: CEnumSTATPROPSTG::Clone
  1634. //
  1635. // Synopsis: Creates an IEnumSTATPROPSTG with same cursor
  1636. // as this.
  1637. //
  1638. // Arguments: S_OK or error.
  1639. //
  1640. //--------------------------------------------------------------------
  1641. HRESULT CEnumSTATPROPSTG::Clone(IEnumSTATPROPSTG ** ppenum)
  1642. {
  1643. HRESULT hr;
  1644. // ----------
  1645. // Validation
  1646. // ----------
  1647. // Validate 'this'
  1648. if (S_OK != (hr = Validate()))
  1649. return(hr);
  1650. // Validate the input
  1651. VDATEPTROUT( ppenum, IEnumSTATPROPSTG* );
  1652. // --------------------
  1653. // Clone the enumerator
  1654. // --------------------
  1655. *ppenum = NULL;
  1656. hr = STG_E_INSUFFICIENTMEMORY;
  1657. *ppenum = new CEnumSTATPROPSTG(*this, &hr);
  1658. if (FAILED(hr))
  1659. {
  1660. delete (CEnumSTATPROPSTG*)*ppenum;
  1661. *ppenum = NULL;
  1662. }
  1663. return(hr);
  1664. }