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.

820 lines
22 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. HRESULT Lock();
  211. HRESULT 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 if (_ulSig == PROPERTYSTORAGE_SIGZOMBIE)
  287. return STG_E_INSUFFICIENTMEMORY;
  288. else
  289. return STG_E_INVALIDHANDLE;
  290. }
  291. //+-------------------------------------------------------------------
  292. //
  293. // Member: CPropertyStorage::ValidateRef
  294. //
  295. // Synopsis: S_OK if signature valid.
  296. //
  297. //--------------------------------------------------------------------
  298. inline HRESULT CPropertyStorage::ValidateRef()
  299. {
  300. if (_ulSig == PROPERTYSTORAGE_SIG || _ulSig == PROPERTYSTORAGE_SIGZOMBIE)
  301. return(S_OK);
  302. else
  303. return(STG_E_INVALIDHANDLE);
  304. }
  305. //+-------------------------------------------------------------------
  306. //
  307. // Member: CPropertyStorage::AssertLocked
  308. //
  309. // Synopsis: Asserts if _cLocks is <= zero.
  310. //
  311. //--------------------------------------------------------------------
  312. inline VOID CPropertyStorage::AssertLocked()
  313. {
  314. DfpAssert( 0 < _cLocks );
  315. }
  316. //+-------------------------------------------------------------------
  317. //
  318. // Member: CPropertyStorage::ValidateRGPROPSPEC
  319. //
  320. // Synopsis: S_OK if PROPSPEC[] is valid
  321. // E_INVALIDARG otherwise.
  322. //
  323. //--------------------------------------------------------------------
  324. inline HRESULT CPropertyStorage::ValidateRGPROPSPEC( ULONG cpspec,
  325. const PROPSPEC rgpropspec[] )
  326. {
  327. HRESULT hr = E_INVALIDARG;
  328. // Validate the array itself.
  329. VDATESIZEREADPTRIN_LABEL(rgpropspec, cpspec * sizeof(PROPSPEC), errRet, hr);
  330. // Validate the elements of the array.
  331. for( ; cpspec > 0; cpspec-- )
  332. {
  333. // Is this an LPWSTR?
  334. if( PRSPEC_LPWSTR == rgpropspec[cpspec-1].ulKind )
  335. {
  336. // We better at least be able to read the first
  337. // character.
  338. VDATEREADPTRIN_LABEL(rgpropspec[cpspec-1].lpwstr, WCHAR, errRet, hr);
  339. }
  340. // Otherwise, this better be a PROPID.
  341. else if( PRSPEC_PROPID != rgpropspec[cpspec-1].ulKind )
  342. {
  343. goto errRet;
  344. }
  345. }
  346. hr = S_OK;
  347. // ----
  348. // Exit
  349. // ----
  350. errRet:
  351. return( hr );
  352. }
  353. //+-------------------------------------------------------------------
  354. //
  355. // Member: CPropertyStorage::ValidateRGPROPID
  356. //
  357. // Synopsis: S_OK if RGPROPID[] is valid for Read.
  358. // E_INVALIDARG otherwise.
  359. //
  360. //--------------------------------------------------------------------
  361. inline HRESULT CPropertyStorage::ValidateRGPROPID( ULONG cpropid,
  362. const PROPID rgpropid[] )
  363. {
  364. HRESULT hr;
  365. VDATESIZEREADPTRIN_LABEL( rgpropid, cpropid * sizeof(PROPID), errRet, hr );
  366. hr = S_OK;
  367. errRet:
  368. return( hr );
  369. }
  370. //+-------------------------------------------------------------------
  371. //
  372. // Member: CPropertyStorage::IsNonSimple
  373. //
  374. // Synopsis: true if non-simple
  375. //
  376. //--------------------------------------------------------------------
  377. inline BOOL CPropertyStorage::IsNonSimple()
  378. {
  379. AssertLocked();
  380. return (_grfFlags & PROPSETFLAG_NONSIMPLE) != 0;
  381. }
  382. //+-------------------------------------------------------------------
  383. //
  384. // Member: CPropertyStorage::IsSimple
  385. //
  386. // Synopsis: true if simple
  387. //
  388. //--------------------------------------------------------------------
  389. inline BOOL CPropertyStorage::IsSimple()
  390. {
  391. AssertLocked();
  392. return !IsNonSimple();
  393. }
  394. //+-------------------------------------------------------------------
  395. //
  396. // Member: CPropertyStorage::IsWriteable
  397. //
  398. // Synopsis: Returns TRUE if writeable, FALSE otherwise.
  399. //
  400. // If _grfMode is zero, we may actually have a writeable
  401. // stream, but _grfMode wasn't returned in IStream::Stat.
  402. // So unless explicitely told not to, we'll probe for
  403. // write access. If explicitely told not to
  404. // (by passing DO_NOT_PROBE), we'll assume that it's
  405. // read-only.
  406. //
  407. //--------------------------------------------------------------------
  408. inline BOOL CPropertyStorage::IsWriteable( EIsWriteable ProbeEnum )
  409. {
  410. AssertLocked();
  411. if( ::GrfModeIsWriteable(_grfMode) )
  412. return( TRUE );
  413. if( 0 != _grfMode || _fExplicitelyProbedForWriteAccess )
  414. // It's explicitely not writeable
  415. return( FALSE );
  416. else
  417. {
  418. // It's either STGM_READ|STGM_DENYNONE, or _grfMode
  419. // wasn't set.
  420. if( PROBE_IF_NECESSARY == ProbeEnum )
  421. return( ProbeStreamToDetermineIfWriteable() );
  422. else
  423. return( FALSE ); // Play it safe and assume read-only.
  424. }
  425. }
  426. //+-------------------------------------------------------------------
  427. //
  428. // Member: CPropertyStorage::IsReadable
  429. //
  430. // Synopsis: S_OK if readable otherwise STG_E_ACCESSDENIED
  431. //
  432. //--------------------------------------------------------------------
  433. inline BOOL CPropertyStorage::IsReadable()
  434. {
  435. AssertLocked();
  436. return( ::GrfModeIsReadable(_grfMode) );
  437. }
  438. //+-------------------------------------------------------------------
  439. //
  440. // Member: CPropertyStorage::IsReverted
  441. //
  442. // Synopsis: TRUE if reverted, FALSE otherwise.
  443. //
  444. //--------------------------------------------------------------------
  445. inline BOOL CPropertyStorage::IsReverted()
  446. {
  447. IUnknown *punk = NULL;
  448. HRESULT hr = S_OK;
  449. BOOL fReverted = FALSE;
  450. AssertLocked();
  451. if( (NULL == _pstgPropSet) && (NULL == _pstmPropSet) )
  452. return( TRUE );
  453. hr = (IsNonSimple() ? (IUnknown*)_pstgPropSet : (IUnknown*)_pstmPropSet) ->
  454. QueryInterface(IID_IUnknown, (void**)&punk);
  455. // Note: On older Mac implementations, memory-based streams will
  456. // return E_NOINTERFACE here, due to a bug in the QueryInterface
  457. // implementation.
  458. if( STG_E_REVERTED == hr )
  459. fReverted = TRUE;
  460. else
  461. fReverted = FALSE;;
  462. if( SUCCEEDED(hr) )
  463. punk->Release();
  464. return( fReverted );
  465. }
  466. inline DWORD
  467. CPropertyStorage::GetChildCreateMode()
  468. {
  469. DWORD dwMode;
  470. AssertLocked();
  471. dwMode = _grfMode & ~(STGM_SHARE_MASK|STGM_TRANSACTED);
  472. dwMode |= STGM_SHARE_EXCLUSIVE | STGM_CREATE;
  473. return( dwMode );
  474. }
  475. inline DWORD
  476. CPropertyStorage::GetChildOpenMode()
  477. {
  478. AssertLocked();
  479. return( GetChildCreateMode() & ~STGM_CREATE );
  480. }
  481. //+-------------------------------------------------------------------------
  482. //
  483. // Class: IStatArray
  484. //
  485. //--------------------------------------------------------------------------
  486. interface IStatArray : public IUnknown
  487. {
  488. public:
  489. virtual NTSTATUS NextAt( ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched )=0;
  490. };
  491. //+-------------------------------------------------------------------------
  492. //
  493. // Class: CStatArray
  494. //
  495. // Purpose: Class to allow sharing of enumeration STATPROPSTG state.
  496. //
  497. // Interface: CStatArray -- Enumerate entire NTPROP np.
  498. // NextAt -- Perform an OLE-type Next operation starting at
  499. // specified offset.
  500. // AddRef -- for sharing of this by CEnumSTATPROPSTG
  501. // Release -- ditto
  502. //
  503. // Notes: Each IEnumSTATPROPSTG instance has a reference to a
  504. // CStatArray. When IEnumSTATPROPSTG::Clone is called, a
  505. // new reference to the extant CStatArray is used: no copying.
  506. //
  507. // The CEnumSTATPROPSTG has a cursor into the CStatArray.
  508. //
  509. //--------------------------------------------------------------------------
  510. class CStatArray : public IStatArray
  511. {
  512. public:
  513. CStatArray( NTPROP np, HRESULT *phr );
  514. private:
  515. ~CStatArray();
  516. public:
  517. STDMETHODIMP QueryInterface ( REFIID riid, void **ppvObject);
  518. STDMETHODIMP_(ULONG) AddRef(void);
  519. STDMETHODIMP_(ULONG) Release(void);
  520. public:
  521. NTSTATUS NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched);
  522. private:
  523. LONG _cRefs;
  524. STATPROPSTG * _psps;
  525. ULONG _cpropActual;
  526. };
  527. //+-------------------------------------------------------------------------
  528. //
  529. // Class: CEnumSTATPROPSTG
  530. //
  531. // Purpose: Implement IEnumSTATPROPSTG
  532. //
  533. // Notes: Just holds a reference to a CStatArray that contains
  534. // a static copy of the enumeration when the original
  535. // Enum call was made. This object contains the cursor
  536. // into the CStatArray.
  537. //
  538. //--------------------------------------------------------------------------
  539. NTSTATUS CopySTATPROPSTG( ULONG celt, STATPROPSTG * pspsDest, const STATPROPSTG * pspsSrc);
  540. class CEnumSTATPROPSTG : public IEnumSTATPROPSTG
  541. {
  542. // ------------
  543. // Construction
  544. // ------------
  545. public:
  546. CEnumSTATPROPSTG( IStatArray *psa ): _ulSig(ENUMSTATPROPSTG_SIG),
  547. _ipropNext(0),
  548. _psa(psa),
  549. _cRefs(1)
  550. {
  551. _psa->AddRef();
  552. }
  553. CEnumSTATPROPSTG(const CEnumSTATPROPSTG &other );
  554. // -----------
  555. // Destruction
  556. // -----------
  557. private:
  558. ~CEnumSTATPROPSTG();
  559. // ----------------
  560. // IUnknown Methods
  561. // ----------------
  562. public:
  563. STDMETHOD(QueryInterface)( REFIID riid, void **ppvObject);
  564. STDMETHOD_(ULONG, AddRef)(void);
  565. STDMETHOD_(ULONG, Release)(void);
  566. // -------------
  567. // IEnum Methods
  568. // -------------
  569. public:
  570. STDMETHOD(Skip)(ULONG celt);
  571. STDMETHOD(Reset)();
  572. STDMETHOD(Clone)(IEnumSTATPROPSTG ** ppenum);
  573. // We don't need RemoteNext.
  574. STDMETHOD(Next)(ULONG celt, STATPROPSTG * rgelt, ULONG * pceltFetched);
  575. // ----------------
  576. // Internal Methods
  577. // ----------------
  578. private:
  579. HRESULT Validate();
  580. // --------------
  581. // Internal State
  582. // --------------
  583. private:
  584. ULONG _ulSig;
  585. LONG _cRefs;
  586. IStatArray * _psa;
  587. ULONG _ipropNext;
  588. };
  589. //+-------------------------------------------------------------------
  590. //
  591. // Member: CEnumSTATPROPSTG::Validate
  592. //
  593. // Synopsis: S_OK if signature is valid, otherwise error
  594. //
  595. //--------------------------------------------------------------------
  596. inline HRESULT CEnumSTATPROPSTG::Validate()
  597. {
  598. return _ulSig == ENUMSTATPROPSTG_SIG ? S_OK : STG_E_INVALIDHANDLE;
  599. }
  600. //+-------------------------------------------------------------------
  601. //
  602. // Member: CheckFlagsOnCreateOrOpen
  603. //
  604. // Synopsis:
  605. //
  606. // Notes:
  607. //
  608. //
  609. //--------------------------------------------------------------------
  610. inline HRESULT CheckFlagsOnCreateOrOpen(
  611. BOOL fCreate,
  612. DWORD grfMode
  613. )
  614. {
  615. // Check for any mode disallowed flags
  616. if (grfMode & ( (fCreate ? 0 : STGM_CREATE)
  617. |
  618. STGM_PRIORITY | STGM_CONVERT
  619. |
  620. STGM_DELETEONRELEASE ))
  621. {
  622. return (STG_E_INVALIDFLAG);
  623. }
  624. // Ensure that we'll have read/write access to any storage/stream we create.
  625. // If grfMode is zero, assume that it's uninitialized and that we'll have
  626. // read/write access. If we don't, the client will still get an error
  627. // at some point, just not in the open path.
  628. if( fCreate
  629. &&
  630. (grfMode & STGM_READWRITE) != STGM_READWRITE
  631. &&
  632. 0 != grfMode )
  633. {
  634. return (STG_E_INVALIDFLAG);
  635. }
  636. return(S_OK);
  637. }