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.

821 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: propstg.hxx
  7. //
  8. // Contents: Class that directly implements IPropertyStorage
  9. //
  10. // Classes: CCoTaskAllocator
  11. // CPropertyStorage
  12. // CEnumSTATPROPSTG
  13. //
  14. // Functions:
  15. //
  16. //
  17. //
  18. // History: 1-Mar-95 BillMo Created.
  19. // 25-Jan-96 MikeHill Added _fmtidSection.
  20. // 22-May-96 MikeHill Added _dwOSVersion to CPropertyStorage.
  21. // 06-Jun-96 MikeHill Added support for input validation.
  22. // 18-Aug-96 MikeHill - Added CDocFilePropertyStorage.
  23. // 07-Feb-97 Danl - Removed CDocFilePropertyStorage.
  24. // 18-Aug-98 MikeHill Probe stream in IsWriteable.
  25. //
  26. // Notes:
  27. //
  28. //--------------------------------------------------------------------------
  29. //+-------------------------------------------------------------------------
  30. //
  31. // Class: CCoTaskAllocator
  32. //
  33. // Purpose: Class used by PrQueryProperties to allocate memory.
  34. //
  35. //--------------------------------------------------------------------------
  36. class CCoTaskAllocator : public PMemoryAllocator
  37. {
  38. public:
  39. virtual void *Allocate(ULONG cbSize);
  40. virtual void Free(void *pv);
  41. };
  42. extern const OLECHAR g_oszPropertyContentsStreamName[];
  43. //+-------------------------------------------------------------------------
  44. //
  45. // Class: CPropertyStorage
  46. //
  47. // Purpose: Implements IPropertyStorage.
  48. //
  49. // Notes: This class uses the functionality provided by
  50. // PrCreatePropertySet, PrSetProperties, PrQueryProperties etc
  51. // to manipulate the property set stream.
  52. //
  53. //--------------------------------------------------------------------------
  54. #define PROPERTYSTORAGE_SIG LONGSIG('P','R','P','S')
  55. #define PROPERTYSTORAGE_SIGDEL LONGSIG('P','R','P','s')
  56. #define PROPERTYSTORAGE_SIGZOMBIE LONGSIG('P','R','P','z')
  57. #define ENUMSTATPROPSTG_SIG LONGSIG('E','P','S','S')
  58. #define ENUMSTATPROPSTG_SIGDEL LONGSIG('E','P','S','s')
  59. // Prototype for test function
  60. WORD GetFormatVersion( IPropertyStorage *ppropstg );
  61. class CPropertyStorage : public IPropertyStorage
  62. #if DBG
  63. , public IStorageTest
  64. #endif
  65. {
  66. friend WORD GetFormatVersion(IPropertyStorage *ppropstg); // Used for test only
  67. // ------------
  68. // Constructors
  69. // ------------
  70. public:
  71. // The destructor must be virtual so that derivative destructors
  72. // will execute.
  73. virtual ~CPropertyStorage();
  74. CPropertyStorage(MAPPED_STREAM_OPTS fMSOpts)
  75. {
  76. _fInitCriticalSection = FALSE;
  77. _fMSOpts = fMSOpts;
  78. Initialize();
  79. #ifndef _MAC
  80. __try
  81. {
  82. InitializeCriticalSection( &_CriticalSection );
  83. _fInitCriticalSection = TRUE;
  84. }
  85. __except( EXCEPTION_EXECUTE_HANDLER )
  86. {
  87. }
  88. #endif
  89. }
  90. // --------
  91. // IUnknown
  92. // --------
  93. public:
  94. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
  95. STDMETHOD_(ULONG, AddRef)(void);
  96. STDMETHOD_(ULONG, Release)(void);
  97. // ----------------
  98. // IPropertyStorage
  99. // ----------------
  100. public:
  101. STDMETHOD(ReadMultiple)(
  102. ULONG cpspec,
  103. const PROPSPEC rgpspec[],
  104. PROPVARIANT rgpropvar[]);
  105. STDMETHOD(WriteMultiple)(
  106. ULONG cpspec,
  107. const PROPSPEC rgpspec[],
  108. const PROPVARIANT rgpropvar[],
  109. PROPID propidNameFirst);
  110. STDMETHOD(DeleteMultiple)(
  111. ULONG cpspec,
  112. const PROPSPEC rgpspec[]);
  113. STDMETHOD(ReadPropertyNames)(
  114. ULONG cpropid,
  115. const PROPID rgpropid[],
  116. LPOLESTR rglpwstrName[]);
  117. STDMETHOD(WritePropertyNames)(
  118. ULONG cpropid,
  119. const PROPID rgpropid[],
  120. const LPOLESTR rglpwstrName[]);
  121. STDMETHOD(DeletePropertyNames)(
  122. ULONG cpropid,
  123. const PROPID rgpropid[]);
  124. STDMETHOD(Commit)(DWORD grfCommitFlags);
  125. STDMETHOD(Revert)();
  126. STDMETHOD(Enum)(IEnumSTATPROPSTG ** ppenum);
  127. STDMETHOD(SetTimes)(
  128. FILETIME const * pctime,
  129. FILETIME const * patime,
  130. FILETIME const * pmtime);
  131. STDMETHOD(SetClass)(REFCLSID clsid);
  132. STDMETHOD(Stat)(STATPROPSETSTG * pstatpsstg);
  133. // ------------
  134. // IStorageTest
  135. // ------------
  136. public:
  137. #if DBG
  138. STDMETHOD(UseNTFS4Streams)( BOOL fUseNTFS4Streams );
  139. STDMETHOD(GetFormatVersion)(WORD *pw);
  140. STDMETHOD(SimulateLowMemory)( BOOL fSimulate );
  141. STDMETHOD(GetLockCount)();
  142. STDMETHOD(IsDirty)();
  143. #endif
  144. // -----------------------------
  145. // Exposed non-interface methods
  146. // -----------------------------
  147. public:
  148. HRESULT Create(
  149. IStream *stm,
  150. REFFMTID rfmtid,
  151. const CLSID *pclsid,
  152. DWORD grfFlags,
  153. DWORD grfMode );
  154. HRESULT Create(
  155. IStorage *pstg,
  156. REFFMTID rfmtid,
  157. const CLSID *pclsid,
  158. DWORD grfFlags,
  159. DWORD grfMode );
  160. HRESULT Open(
  161. IStorage *pstg,
  162. REFFMTID rfmtid,
  163. DWORD grfFlags,
  164. DWORD grfMode );
  165. HRESULT Open(
  166. IStream *pstm,
  167. REFFMTID rfmtid,
  168. DWORD grfFlags,
  169. DWORD grfMode,
  170. BOOL fDelete );
  171. // used by implementation helper classes
  172. inline NTPROP GetNtPropSetHandle(void) { return _np; }
  173. // ----------------
  174. // Internal Methods
  175. // ----------------
  176. private:
  177. void Initialize();
  178. HRESULT InitializeOnCreateOrOpen(
  179. DWORD grfFlags,
  180. DWORD grfMode,
  181. REFFMTID rfmtid,
  182. BOOL fCreate );
  183. VOID CleanupOpenedObjects(
  184. PROPVARIANT avar[],
  185. INDIRECTPROPERTY * pip,
  186. ULONG cpspec,
  187. ULONG iFailIndex);
  188. enum EInitializePropertyStream
  189. {
  190. OPEN_PROPSTREAM,
  191. CREATE_PROPSTREAM,
  192. DELETE_PROPSTREAM
  193. };
  194. HRESULT InitializePropertyStream(
  195. const GUID * pguid,
  196. GUID const * pclsid,
  197. EInitializePropertyStream CreateOpenDelete );
  198. HRESULT _WriteMultiple(
  199. ULONG cpspec,
  200. const PROPSPEC rgpspec[],
  201. const PROPVARIANT rgpropvar[],
  202. PROPID propidNameFirst);
  203. HRESULT _WritePropertyNames(
  204. ULONG cpropid,
  205. const PROPID rgpropid[],
  206. const LPOLESTR rglpwstrName[]);
  207. BOOL ProbeStreamToDetermineIfWriteable();
  208. virtual HRESULT CreateMappedStream( );
  209. virtual void DeleteMappedStream( );
  210. VOID Lock();
  211. VOID Unlock();
  212. VOID AssertLocked();
  213. inline HRESULT Validate();
  214. inline HRESULT ValidateRef();
  215. inline HRESULT ValidateRGPROPSPEC( ULONG cpspec, const PROPSPEC rgpropspec[] );
  216. inline HRESULT ValidateRGPROPID( ULONG cpropid, const PROPID rgpropid[] );
  217. HRESULT ValidateVTs( ULONG cprops, const PROPVARIANT rgpropvar[] );
  218. enum EIsWriteable
  219. {
  220. PROBE_IF_NECESSARY,
  221. DO_NOT_PROBE
  222. };
  223. inline BOOL IsNonSimple();
  224. inline BOOL IsSimple();
  225. inline BOOL IsWriteable( EIsWriteable ProbeEnum = PROBE_IF_NECESSARY );
  226. inline BOOL IsReadable();
  227. inline BOOL IsReverted();
  228. inline DWORD GetChildCreateMode();
  229. inline DWORD GetChildOpenMode();
  230. // -------------
  231. // Internal Data
  232. // -------------
  233. private:
  234. ULONG _ulSig;
  235. LONG _cRefs;
  236. IStorage * _pstgPropSet;
  237. IStream * _pstmPropSet;
  238. NTPROP _np;
  239. IMappedStream * _ms;
  240. MAPPED_STREAM_OPTS _fMSOpts;
  241. #ifndef _MAC
  242. BOOL _fInitCriticalSection;
  243. CRITICAL_SECTION _CriticalSection;
  244. #endif
  245. #if DBG
  246. LONG _cLocks;
  247. #endif
  248. // We need to remember if the property set is the second section
  249. // of the DocumentSummaryInformation property set used by Office. This
  250. // is the only case where we support a multiple-section property set, and
  251. // requires special handling in ::Revert().
  252. BOOL _fUserDefinedProperties:1;
  253. // If _grfMode is zero, maybe it's valid and really zero, or maybe
  254. // we're dealing with a stream that doesn't return the grfMode in the
  255. // Stat (such as is the case with CreateStreamFromHGlobal). So if we
  256. // get a zero _grfMode, we probe the stream to determine if it's writeable.
  257. // This flag ensures we only do it once.
  258. BOOL _fExplicitelyProbedForWriteAccess:1;
  259. USHORT _usCodePage; // Ansi Codepage or Mac Script
  260. // (disambiguate with _dwOSVersion)
  261. ULONG _dwOSVersion; // Shows the OS Kind, major/minor version
  262. DWORD _grfFlags; // PROPSETFLAG_NONSIMPLE and PROPSETFLAG_ANSI
  263. DWORD _grfMode; // STGM_ flags
  264. // The following is a PMemoryAllocator for the Rtl property
  265. // set routines. This instantiation was formerly a file-global
  266. // in propstg.cxx. However, on the Mac, the object was not
  267. // being instantiated.
  268. CCoTaskAllocator _cCoTaskAllocator;
  269. };
  270. //+-------------------------------------------------------------------
  271. //
  272. // Member: CPropertyStorage::Validate
  273. //
  274. // Synopsis: S_OK if signature valid and not zombie.
  275. //
  276. // Notes: If the Revert calls fails due to low memory, then
  277. // the object becomes a zombie.
  278. //
  279. //--------------------------------------------------------------------
  280. inline HRESULT CPropertyStorage::Validate()
  281. {
  282. if(!_fInitCriticalSection)
  283. return E_OUTOFMEMORY;
  284. if (_ulSig == PROPERTYSTORAGE_SIG)
  285. return S_OK;
  286. else
  287. if (_ulSig == PROPERTYSTORAGE_SIGZOMBIE)
  288. return STG_E_INSUFFICIENTMEMORY;
  289. else
  290. return STG_E_INVALIDHANDLE;
  291. }
  292. //+-------------------------------------------------------------------
  293. //
  294. // Member: CPropertyStorage::ValidateRef
  295. //
  296. // Synopsis: S_OK if signature valid.
  297. //
  298. //--------------------------------------------------------------------
  299. inline HRESULT CPropertyStorage::ValidateRef()
  300. {
  301. if (_ulSig == PROPERTYSTORAGE_SIG || _ulSig == PROPERTYSTORAGE_SIGZOMBIE)
  302. return(S_OK);
  303. else
  304. return(STG_E_INVALIDHANDLE);
  305. }
  306. //+-------------------------------------------------------------------
  307. //
  308. // Member: CPropertyStorage::AssertLocked
  309. //
  310. // Synopsis: Asserts if _cLocks is <= zero.
  311. //
  312. //--------------------------------------------------------------------
  313. inline VOID CPropertyStorage::AssertLocked()
  314. {
  315. DfpAssert( 0 < _cLocks );
  316. }
  317. //+-------------------------------------------------------------------
  318. //
  319. // Member: CPropertyStorage::ValidateRGPROPSPEC
  320. //
  321. // Synopsis: S_OK if PROPSPEC[] is valid
  322. // E_INVALIDARG otherwise.
  323. //
  324. //--------------------------------------------------------------------
  325. inline HRESULT CPropertyStorage::ValidateRGPROPSPEC( ULONG cpspec,
  326. const PROPSPEC rgpropspec[] )
  327. {
  328. HRESULT hr = E_INVALIDARG;
  329. // Validate the array itself.
  330. VDATESIZEREADPTRIN_LABEL(rgpropspec, cpspec * sizeof(PROPSPEC), errRet, hr);
  331. // Validate the elements of the array.
  332. for( ; cpspec > 0; cpspec-- )
  333. {
  334. // Is this an LPWSTR?
  335. if( PRSPEC_LPWSTR == rgpropspec[cpspec-1].ulKind )
  336. {
  337. // We better at least be able to read the first
  338. // character.
  339. VDATEREADPTRIN_LABEL(rgpropspec[cpspec-1].lpwstr, WCHAR, errRet, hr);
  340. }
  341. // Otherwise, this better be a PROPID.
  342. else if( PRSPEC_PROPID != rgpropspec[cpspec-1].ulKind )
  343. {
  344. goto errRet;
  345. }
  346. }
  347. hr = S_OK;
  348. // ----
  349. // Exit
  350. // ----
  351. errRet:
  352. return( hr );
  353. }
  354. //+-------------------------------------------------------------------
  355. //
  356. // Member: CPropertyStorage::ValidateRGPROPID
  357. //
  358. // Synopsis: S_OK if RGPROPID[] is valid for Read.
  359. // E_INVALIDARG otherwise.
  360. //
  361. //--------------------------------------------------------------------
  362. inline HRESULT CPropertyStorage::ValidateRGPROPID( ULONG cpropid,
  363. const PROPID rgpropid[] )
  364. {
  365. HRESULT hr;
  366. VDATESIZEREADPTRIN_LABEL( rgpropid, cpropid * sizeof(PROPID), errRet, hr );
  367. hr = S_OK;
  368. errRet:
  369. return( hr );
  370. }
  371. //+-------------------------------------------------------------------
  372. //
  373. // Member: CPropertyStorage::IsNonSimple
  374. //
  375. // Synopsis: true if non-simple
  376. //
  377. //--------------------------------------------------------------------
  378. inline BOOL CPropertyStorage::IsNonSimple()
  379. {
  380. AssertLocked();
  381. return (_grfFlags & PROPSETFLAG_NONSIMPLE) != 0;
  382. }
  383. //+-------------------------------------------------------------------
  384. //
  385. // Member: CPropertyStorage::IsSimple
  386. //
  387. // Synopsis: true if simple
  388. //
  389. //--------------------------------------------------------------------
  390. inline BOOL CPropertyStorage::IsSimple()
  391. {
  392. AssertLocked();
  393. return !IsNonSimple();
  394. }
  395. //+-------------------------------------------------------------------
  396. //
  397. // Member: CPropertyStorage::IsWriteable
  398. //
  399. // Synopsis: Returns TRUE if writeable, FALSE otherwise.
  400. //
  401. // If _grfMode is zero, we may actually have a writeable
  402. // stream, but _grfMode wasn't returned in IStream::Stat.
  403. // So unless explicitely told not to, we'll probe for
  404. // write access. If explicitely told not to
  405. // (by passing DO_NOT_PROBE), we'll assume that it's
  406. // read-only.
  407. //
  408. //--------------------------------------------------------------------
  409. inline BOOL CPropertyStorage::IsWriteable( EIsWriteable ProbeEnum )
  410. {
  411. AssertLocked();
  412. if( ::GrfModeIsWriteable(_grfMode) )
  413. return( TRUE );
  414. if( 0 != _grfMode || _fExplicitelyProbedForWriteAccess )
  415. // It's explicitely not writeable
  416. return( FALSE );
  417. else
  418. {
  419. // It's either STGM_READ|STGM_DENYNONE, or _grfMode
  420. // wasn't set.
  421. if( PROBE_IF_NECESSARY == ProbeEnum )
  422. return( ProbeStreamToDetermineIfWriteable() );
  423. else
  424. return( FALSE ); // Play it safe and assume read-only.
  425. }
  426. }
  427. //+-------------------------------------------------------------------
  428. //
  429. // Member: CPropertyStorage::IsReadable
  430. //
  431. // Synopsis: S_OK if readable otherwise STG_E_ACCESSDENIED
  432. //
  433. //--------------------------------------------------------------------
  434. inline BOOL CPropertyStorage::IsReadable()
  435. {
  436. AssertLocked();
  437. return( ::GrfModeIsReadable(_grfMode) );
  438. }
  439. //+-------------------------------------------------------------------
  440. //
  441. // Member: CPropertyStorage::IsReverted
  442. //
  443. // Synopsis: TRUE if reverted, FALSE otherwise.
  444. //
  445. //--------------------------------------------------------------------
  446. inline BOOL CPropertyStorage::IsReverted()
  447. {
  448. IUnknown *punk = NULL;
  449. HRESULT hr = S_OK;
  450. BOOL fReverted = FALSE;
  451. AssertLocked();
  452. if( (NULL == _pstgPropSet) && (NULL == _pstmPropSet) )
  453. return( TRUE );
  454. hr = (IsNonSimple() ? (IUnknown*)_pstgPropSet : (IUnknown*)_pstmPropSet) ->
  455. QueryInterface(IID_IUnknown, (void**)&punk);
  456. // Note: On older Mac implementations, memory-based streams will
  457. // return E_NOINTERFACE here, due to a bug in the QueryInterface
  458. // implementation.
  459. if( STG_E_REVERTED == hr )
  460. fReverted = TRUE;
  461. else
  462. fReverted = FALSE;;
  463. if( SUCCEEDED(hr) )
  464. punk->Release();
  465. return( fReverted );
  466. }
  467. inline DWORD
  468. CPropertyStorage::GetChildCreateMode()
  469. {
  470. DWORD dwMode;
  471. AssertLocked();
  472. dwMode = _grfMode & ~(STGM_SHARE_MASK|STGM_TRANSACTED);
  473. dwMode |= STGM_SHARE_EXCLUSIVE | STGM_CREATE;
  474. return( dwMode );
  475. }
  476. inline DWORD
  477. CPropertyStorage::GetChildOpenMode()
  478. {
  479. AssertLocked();
  480. return( GetChildCreateMode() & ~STGM_CREATE );
  481. }
  482. //+-------------------------------------------------------------------------
  483. //
  484. // Class: IStatArray
  485. //
  486. //--------------------------------------------------------------------------
  487. interface IStatArray : public IUnknown
  488. {
  489. public:
  490. virtual NTSTATUS NextAt( ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched )=0;
  491. };
  492. //+-------------------------------------------------------------------------
  493. //
  494. // Class: CStatArray
  495. //
  496. // Purpose: Class to allow sharing of enumeration STATPROPSTG state.
  497. //
  498. // Interface: CStatArray -- Enumerate entire NTPROP np.
  499. // NextAt -- Perform an OLE-type Next operation starting at
  500. // specified offset.
  501. // AddRef -- for sharing of this by CEnumSTATPROPSTG
  502. // Release -- ditto
  503. //
  504. // Notes: Each IEnumSTATPROPSTG instance has a reference to a
  505. // CStatArray. When IEnumSTATPROPSTG::Clone is called, a
  506. // new reference to the extant CStatArray is used: no copying.
  507. //
  508. // The CEnumSTATPROPSTG has a cursor into the CStatArray.
  509. //
  510. //--------------------------------------------------------------------------
  511. class CStatArray : public IStatArray
  512. {
  513. public:
  514. CStatArray( NTPROP np, HRESULT *phr );
  515. private:
  516. ~CStatArray();
  517. public:
  518. STDMETHODIMP QueryInterface ( REFIID riid, void **ppvObject);
  519. STDMETHODIMP_(ULONG) AddRef(void);
  520. STDMETHODIMP_(ULONG) Release(void);
  521. public:
  522. NTSTATUS NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched);
  523. private:
  524. LONG _cRefs;
  525. STATPROPSTG * _psps;
  526. ULONG _cpropActual;
  527. };
  528. //+-------------------------------------------------------------------------
  529. //
  530. // Class: CEnumSTATPROPSTG
  531. //
  532. // Purpose: Implement IEnumSTATPROPSTG
  533. //
  534. // Notes: Just holds a reference to a CStatArray that contains
  535. // a static copy of the enumeration when the original
  536. // Enum call was made. This object contains the cursor
  537. // into the CStatArray.
  538. //
  539. //--------------------------------------------------------------------------
  540. NTSTATUS CopySTATPROPSTG( ULONG celt, STATPROPSTG * pspsDest, const STATPROPSTG * pspsSrc);
  541. class CEnumSTATPROPSTG : public IEnumSTATPROPSTG
  542. {
  543. // ------------
  544. // Construction
  545. // ------------
  546. public:
  547. CEnumSTATPROPSTG( IStatArray *psa ): _ulSig(ENUMSTATPROPSTG_SIG),
  548. _ipropNext(0),
  549. _psa(psa),
  550. _cRefs(1)
  551. {
  552. _psa->AddRef();
  553. }
  554. CEnumSTATPROPSTG(const CEnumSTATPROPSTG &other );
  555. // -----------
  556. // Destruction
  557. // -----------
  558. private:
  559. ~CEnumSTATPROPSTG();
  560. // ----------------
  561. // IUnknown Methods
  562. // ----------------
  563. public:
  564. STDMETHOD(QueryInterface)( REFIID riid, void **ppvObject);
  565. STDMETHOD_(ULONG, AddRef)(void);
  566. STDMETHOD_(ULONG, Release)(void);
  567. // -------------
  568. // IEnum Methods
  569. // -------------
  570. public:
  571. STDMETHOD(Skip)(ULONG celt);
  572. STDMETHOD(Reset)();
  573. STDMETHOD(Clone)(IEnumSTATPROPSTG ** ppenum);
  574. // We don't need RemoteNext.
  575. STDMETHOD(Next)(ULONG celt, STATPROPSTG * rgelt, ULONG * pceltFetched);
  576. // ----------------
  577. // Internal Methods
  578. // ----------------
  579. private:
  580. HRESULT Validate();
  581. // --------------
  582. // Internal State
  583. // --------------
  584. private:
  585. ULONG _ulSig;
  586. LONG _cRefs;
  587. IStatArray * _psa;
  588. ULONG _ipropNext;
  589. };
  590. //+-------------------------------------------------------------------
  591. //
  592. // Member: CEnumSTATPROPSTG::Validate
  593. //
  594. // Synopsis: S_OK if signature is valid, otherwise error
  595. //
  596. //--------------------------------------------------------------------
  597. inline HRESULT CEnumSTATPROPSTG::Validate()
  598. {
  599. return _ulSig == ENUMSTATPROPSTG_SIG ? S_OK : STG_E_INVALIDHANDLE;
  600. }
  601. //+-------------------------------------------------------------------
  602. //
  603. // Member: CheckFlagsOnCreateOrOpen
  604. //
  605. // Synopsis:
  606. //
  607. // Notes:
  608. //
  609. //
  610. //--------------------------------------------------------------------
  611. inline HRESULT CheckFlagsOnCreateOrOpen(
  612. BOOL fCreate,
  613. DWORD grfMode
  614. )
  615. {
  616. // Check for any mode disallowed flags
  617. if (grfMode & ( (fCreate ? 0 : STGM_CREATE)
  618. |
  619. STGM_PRIORITY | STGM_CONVERT
  620. |
  621. STGM_DELETEONRELEASE ))
  622. {
  623. return (STG_E_INVALIDFLAG);
  624. }
  625. // Ensure that we'll have read/write access to any storage/stream we create.
  626. // If grfMode is zero, assume that it's uninitialized and that we'll have
  627. // read/write access. If we don't, the client will still get an error
  628. // at some point, just not in the open path.
  629. if( fCreate
  630. &&
  631. (grfMode & STGM_READWRITE) != STGM_READWRITE
  632. &&
  633. 0 != grfMode )
  634. {
  635. return (STG_E_INVALIDFLAG);
  636. }
  637. return(S_OK);
  638. }