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.

905 lines
26 KiB

  1. //+==================================================================
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1998.
  5. //
  6. // File: PropAPI.cxx
  7. //
  8. // This file provides the Property Set API routines.
  9. //
  10. // APIs: StgCreatePropSetStg (creates an IPropertySetStorage)
  11. // StgCreatePropStg (creates an IPropertyStorage)
  12. // StgOpenPropStg (opens an IPropertyStorage)
  13. // StgCreateStorageOnHandle (private, not a public API)
  14. // StgOpenStorageOnHandle (private, not a public API)
  15. //
  16. // History:
  17. //
  18. // 3/10/98 MikeHill - Added StgCreate/OpenStorageOnHandle
  19. // 5/6/98 MikeHill - Rewrite StgCreate/OpenStorageOnHandle.
  20. // 5/18/98 MikeHill
  21. // - Use new CPropertySetStorage constructor.
  22. //
  23. //+==================================================================
  24. #include <pch.cxx>
  25. #ifdef _MAC_NODOC
  26. ASSERTDATA // File-specific data for FnAssert
  27. #endif
  28. //+------------------------------------------------------------------
  29. //
  30. // Function: QueryForIStream
  31. //
  32. // Synopsis: This routine queries an IUnknown for
  33. // an IStream interface. This is isolated into
  34. // a separate routine because some workaround code
  35. // is required on the Mac.
  36. //
  37. // Inputs: [IUnknown*] pUnk
  38. // The interface to be queried.
  39. // [IStream**] ppStm
  40. // Location to return the result.
  41. //
  42. // Returns: [HRESULT]
  43. //
  44. // Notes: On older Mac implementations (<=2.08, <=~1996)
  45. // the memory-based IStream implementation
  46. // (created by CreateStreamOnHGlobal) had a bug
  47. // in QueryInterface: when you QI for an
  48. // IStream or IUnknown, an addref is done, but an
  49. // HR of E_NOINTERFACE is returned.
  50. //
  51. // Below, we look for this condition: if we get an
  52. // E_NOINTERFACE on the Mac, we check to see if it's
  53. // an OLE mem-based IStream. If it is, we simply cast
  54. // IUnknown as an IStream. We validate it as an OLE
  55. // the mem-based IStream by creating one of our own, and
  56. // comparing the QueryInterface addresses.
  57. //
  58. // This is some ugly code, but at least it is isolated,
  59. // only runs on the older Macs, and ensures that we
  60. // work on all platforms.
  61. //
  62. //+------------------------------------------------------------------
  63. inline HRESULT QueryForIStream( IUnknown * pUnk, IStream** ppStm )
  64. {
  65. HRESULT hr;
  66. // Attempt to get the interface
  67. hr = pUnk->QueryInterface( IID_IStream, (void**) ppStm );
  68. #ifdef _MAC
  69. // On the Mac, if we get a no-interface error, see if it is really
  70. // a buggy mem-based IStream implementation.
  71. if( E_NOINTERFACE == hr )
  72. {
  73. IStream *pstmMem = NULL;
  74. // Create our own mem-based IStream.
  75. hr = CreateStreamOnHGlobal( NULL, TRUE, &pstmMem );
  76. if( FAILED(hr) ) goto Exit;
  77. // If the mem-based Stream's QI implementation has the same
  78. // address as the Unknown's QI implementation, then the Unknown
  79. // must be an OLE mem-based stream.
  80. if( pUnk->QueryInterface == pstmMem->QueryInterface )
  81. {
  82. // We can just cast the IUnknown* as an IStream* and
  83. // we're done (the original QI, despite returning an
  84. // error, has already done an AddRef).
  85. hr = S_OK;
  86. *ppStm = (IStream*) pUnk;
  87. }
  88. else
  89. {
  90. // This is a real no-interface error, so let's return it.
  91. hr = E_NOINTERFACE;
  92. }
  93. pstmMem->Release();
  94. }
  95. // ----
  96. // Exit
  97. // ----
  98. Exit:
  99. #endif // #ifdef _MAC
  100. return( hr );
  101. } // QueryForIStream()
  102. //+------------------------------------------------------------------
  103. //
  104. // Function: StgCreatePropStg
  105. //
  106. // Synopsis: Given an IStorage or IStream, create an
  107. // IPropertyStorage. This is similar to the
  108. // IPropertySetStorage::Create method. Existing
  109. // contents of the Storage/Stream are removed.
  110. //
  111. // Inputs: [IUnknown*] pUnk
  112. // An IStorage* for non-simple propsets,
  113. // an IStream* for simple. grfFlags is
  114. // used to disambiguate.
  115. // [REFFMTID] fmtid
  116. // The ID of the property set.
  117. // [DWORD] grfFlags
  118. // From the PROPSETFLAG_* enumeration.
  119. // [IPropertySetStorage**] ppPropStg
  120. // The result.
  121. //
  122. // Returns: [HRESULT]
  123. //
  124. // Notes: The caller is responsible for maintaining
  125. // thread-safety between the original
  126. // IStorage/IStream and this IPropertyStorage.
  127. //
  128. //+------------------------------------------------------------------
  129. STDAPI StgCreatePropStg( IUnknown *pUnk,
  130. REFFMTID fmtid,
  131. const CLSID *pclsid,
  132. DWORD grfFlags,
  133. DWORD dwReserved,
  134. IPropertyStorage **ppPropStg)
  135. {
  136. // ------
  137. // Locals
  138. // ------
  139. HRESULT hr;
  140. IStream *pstm = NULL;
  141. IStorage *pstg = NULL;
  142. // ----------
  143. // Validation
  144. // ----------
  145. propXTraceStatic( "StgCreatePropStg" );
  146. GEN_VDATEIFACE_LABEL( pUnk, E_INVALIDARG, Exit, hr );
  147. GEN_VDATEREADPTRIN_LABEL(&fmtid, FMTID, E_INVALIDARG, Exit, hr );
  148. GEN_VDATEPTRIN_LABEL(pclsid, CLSID, E_INVALIDARG, Exit, hr );
  149. // grfFlags is validated by CPropertyStorage
  150. GEN_VDATEPTROUT_LABEL( ppPropStg, IPropertyStorage*, E_INVALIDARG, Exit, hr );
  151. *ppPropStg = NULL;
  152. propTraceParameters(( "pUnk=%p, fmtid=%s, clsid=%s, grfFlags=%s, dwReserved=0x%x, ppPropStg=%p",
  153. pUnk, static_cast<const char*>(CStringize(fmtid)),
  154. static_cast<const char*>(CStringize(*pclsid)),
  155. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  156. dwReserved, ppPropStg ));
  157. // -----------------------
  158. // Non-Simple Property Set
  159. // -----------------------
  160. if( grfFlags & PROPSETFLAG_NONSIMPLE )
  161. {
  162. // Get the IStorage*
  163. hr = pUnk->QueryInterface( IID_IStorage, (void**) &pstg );
  164. if( FAILED(hr) ) goto Exit;
  165. // Create the IPropertyStorage implementation
  166. *ppPropStg = new CPropertyStorage( MAPPED_STREAM_CREATE );
  167. if( NULL== *ppPropStg )
  168. {
  169. hr = E_OUTOFMEMORY;
  170. goto Exit;
  171. }
  172. // Initialize the IPropertyStorage
  173. hr = static_cast<CPropertyStorage*>(*ppPropStg)->Create( pstg, fmtid, pclsid, grfFlags,
  174. 0 ); // We don't know the grfMode
  175. if( FAILED(hr) ) goto Exit;
  176. } // if( grfFlags & PROPSETFLAG_NONSIMPLE )
  177. // -------------------
  178. // Simple Property Set
  179. // -------------------
  180. else
  181. {
  182. // Get the IStream*
  183. hr = QueryForIStream( pUnk, &pstm );
  184. if( FAILED(hr) ) goto Exit;
  185. // Create an IPropertyStorage implementation.
  186. *ppPropStg = new CPropertyStorage( MAPPED_STREAM_CREATE );
  187. if( NULL == *ppPropStg )
  188. {
  189. hr = E_OUTOFMEMORY;
  190. goto Exit;
  191. }
  192. // Initialize the IPropertyStorage (which
  193. // is responsible for sizing and seeking the
  194. // stream).
  195. hr = static_cast<CPropertyStorage*>(*ppPropStg)->Create( pstm, fmtid, pclsid, grfFlags,
  196. 0 ); // We don't know the grfMode
  197. if( FAILED(hr) ) goto Exit;
  198. } // if( grfFlags & PROPSETFLAG_NONSIMPLE ) ... else
  199. // ----
  200. // Exit
  201. // ----
  202. Exit:
  203. // If we created *ppPropStg, and there was an error, delete it.
  204. if( FAILED(hr) )
  205. {
  206. propDbg((DEB_ERROR, "StgCreatePropStg returns %08X\n", hr ));
  207. // Only delete it if the caller gave us valid parameters
  208. // and we created a CPropertyStorage
  209. if( E_INVALIDARG != hr && NULL != *ppPropStg )
  210. {
  211. delete *ppPropStg;
  212. *ppPropStg = NULL;
  213. }
  214. }
  215. if( NULL != pstm )
  216. pstm->Release();
  217. if( NULL != pstg )
  218. pstg->Release();
  219. return( hr );
  220. } // StgCreatePropStg()
  221. //+------------------------------------------------------------------
  222. //
  223. // Function: StgOpenPropStg
  224. //
  225. // Synopsis: Given an IStorage or IStream which hold a
  226. // serialized property set, create an
  227. // IPropertyStorage. This is similar to the
  228. // IPropertySetStorage::Open method.
  229. //
  230. // Inputs: [IUnknown*] pUnk
  231. // An IStorage* for non-simple propsets,
  232. // an IStream* for simple. grfFlags is
  233. // used to disambiguate.
  234. // [REFFMTID] fmtid
  235. // The ID of the property set.
  236. // [DWORD] grfFlags
  237. // From the PROPSETFLAG_* enumeration.
  238. // [IPropertySetStorage**] ppPropStg
  239. // The result.
  240. //
  241. // Returns: [HRESULT]
  242. //
  243. // Notes: The caller is responsible for maintaining
  244. // thread-safety between the original
  245. // IStorage/IStream and this IPropertyStorage.
  246. //
  247. //+------------------------------------------------------------------
  248. STDAPI StgOpenPropStg( IUnknown* pUnk,
  249. REFFMTID fmtid,
  250. DWORD grfFlags,
  251. DWORD dwReserved,
  252. IPropertyStorage **ppPropStg)
  253. {
  254. // ------
  255. // Locals
  256. // ------
  257. HRESULT hr;
  258. IStream *pstm = NULL;
  259. IStorage *pstg = NULL;
  260. // ----------
  261. // Validation
  262. // ----------
  263. propXTraceStatic( "StgOpenPropStg" );
  264. GEN_VDATEIFACE_LABEL( pUnk, E_INVALIDARG, Exit, hr );
  265. GEN_VDATEREADPTRIN_LABEL(&fmtid, FMTID, E_INVALIDARG, Exit, hr);
  266. // grfFlags is validated by CPropertyStorage
  267. GEN_VDATEPTROUT_LABEL( ppPropStg, IPropertyStorage*, E_INVALIDARG, Exit, hr );
  268. propTraceParameters(( "pUnk=%p, fmtid=%s, grfFlags=%s, dwReserved=0x%x, ppPropStg=%p",
  269. pUnk, static_cast<const char*>(CStringize(fmtid)),
  270. static_cast<const char*>(CStringize(SGrfFlags(grfFlags))),
  271. dwReserved, ppPropStg ));
  272. // -----------------------
  273. // Non-Simple Property Set
  274. // -----------------------
  275. *ppPropStg = NULL;
  276. if( grfFlags & PROPSETFLAG_NONSIMPLE )
  277. {
  278. // Get the IStorage*
  279. hr = pUnk->QueryInterface( IID_IStorage, (void**) &pstg );
  280. if( FAILED(hr) ) goto Exit;
  281. // Create an IPropertyStorage* implementation.
  282. *ppPropStg = new CPropertyStorage( MAPPED_STREAM_CREATE );
  283. if( NULL == *ppPropStg )
  284. {
  285. hr = E_OUTOFMEMORY;
  286. goto Exit;
  287. }
  288. // Initialize the IPropertyStorage by reading
  289. // the serialized property set.
  290. hr = static_cast<CPropertyStorage*>(*ppPropStg)->Open( pstg, fmtid, grfFlags,
  291. 0 ); // We don't know the grfMode
  292. if( FAILED(hr) ) goto Exit;
  293. } // if( grfFlags & PROPSETFLAG_NONSIMPLE )
  294. // -------------------
  295. // Simple Property Set
  296. // -------------------
  297. else
  298. {
  299. // Get the IStream*
  300. hr = QueryForIStream( pUnk, &pstm );
  301. if( FAILED(hr) ) goto Exit;
  302. // Create an IPropertyStorage* implementation.
  303. *ppPropStg = new CPropertyStorage(MAPPED_STREAM_CREATE );
  304. if( NULL == *ppPropStg )
  305. {
  306. hr = E_OUTOFMEMORY;
  307. goto Exit;
  308. }
  309. // Initialize the IPropertyStorage by reading
  310. // the serialized property set (the CPropertyStorage
  311. // is responsible for seeking to the stream start).
  312. hr = static_cast<CPropertyStorage*>(*ppPropStg)->Open( pstm, fmtid, grfFlags,
  313. 0, // We don't know the grfMode
  314. FALSE ); // Not deleting
  315. if( FAILED(hr) ) goto Exit;
  316. } // if( grfFlags & PROPSETFLAG_NONSIMPLE ) ... else
  317. // ----
  318. // Exit
  319. // ----
  320. Exit:
  321. // If we created *ppPropStg, and there was an error, delete it.
  322. if( FAILED(hr) )
  323. {
  324. propDbg((DEB_ERROR, "StgOpenPropStg returns %08X\n", hr ));
  325. // Only delete it if the caller gave us a valid ppPropStg
  326. // and we created a CPropertyStorage
  327. if( E_INVALIDARG != hr && NULL != *ppPropStg )
  328. {
  329. delete *ppPropStg;
  330. *ppPropStg = NULL;
  331. }
  332. }
  333. if( NULL != pstm )
  334. pstm->Release();
  335. if( NULL != pstg )
  336. pstg->Release();
  337. return( hr );
  338. } // StgOpenPropStg()
  339. //+------------------------------------------------------------------
  340. //
  341. // Function: StgCreatePropSetStg
  342. //
  343. // Synopsis: Given an IStorage, create an IPropertySetStorage.
  344. // This is similar to QI-ing a DocFile IStorage for
  345. // the IPropertySetStorage interface.
  346. //
  347. // Inputs: [IStorage*] pStorage
  348. // Will be held by the propsetstg and used
  349. // for create/open.
  350. // [IPropertySetStorage**] ppPropSetStg
  351. // Receives the result.
  352. //
  353. // Returns: [HRESULT]
  354. //
  355. // Notes: The caller is responsible for maintaining
  356. // thread-safety between the original
  357. // IStorage and this IPropertySetStorage.
  358. //
  359. //+------------------------------------------------------------------
  360. STDAPI
  361. StgCreatePropSetStg( IStorage *pStorage,
  362. DWORD dwReserved,
  363. IPropertySetStorage **ppPropSetStg)
  364. {
  365. HRESULT hr = S_OK;
  366. CPropertySetStorage *pPropSetStg = NULL;
  367. // Validation
  368. propXTraceStatic( "StgCreatePropSetStg" );
  369. GEN_VDATEIFACE_LABEL( pStorage, E_INVALIDARG, Exit, hr );
  370. GEN_VDATEPTROUT_LABEL( ppPropSetStg, IPropertySetStorage*, E_INVALIDARG, Exit, hr );
  371. propTraceParameters(( "pStorage=%p, dwReserved=0x%x, ppPropSetStg=%p",
  372. pStorage, dwReserved, ppPropSetStg ));
  373. // Create the IPropertySetStorage implementation.
  374. pPropSetStg = new CPropertySetStorage( MAPPED_STREAM_CREATE );
  375. if( NULL == pPropSetStg )
  376. {
  377. hr = E_OUTOFMEMORY;
  378. goto Exit;
  379. }
  380. // Pass the caller-provided storage into the CPropertySetStorage
  381. pPropSetStg->Init( pStorage, /*IBlockingLock*/ NULL,
  382. TRUE ); // fControlLifetime (=> addref)
  383. // ----
  384. // Exit
  385. // ----
  386. hr = S_OK;
  387. *ppPropSetStg = static_cast<IPropertySetStorage*>(pPropSetStg);
  388. pPropSetStg = NULL;
  389. Exit:
  390. RELEASE_INTERFACE(pPropSetStg);
  391. if( FAILED(hr) )
  392. propDbg((DEB_ERROR, "StgCreatePropSetStg() returns %08X\n", hr ));
  393. return( hr );
  394. } // StgCreatePropSetStg()
  395. //+----------------------------------------------------------------------------
  396. //
  397. // Function: FmtIdToPropStgName
  398. //
  399. // Synopsis: This function maps a property set's FMTID to the name of
  400. // the Stream or Storage which contains it. This name
  401. // is 27 characters (including the terminator).
  402. //
  403. // Inputs: [const FMTID*] pfmtid (in)
  404. // The FMTID of the property set.
  405. // [LPOLESTR] oszName (out)
  406. // The name of the Property Set's Stream/Storage
  407. //
  408. // Returns: [HRESULT] S_OK or E_INVALIDARG
  409. //
  410. //+----------------------------------------------------------------------------
  411. STDAPI
  412. FmtIdToPropStgName( const FMTID *pfmtid, LPOLESTR oszName )
  413. {
  414. HRESULT hr = S_OK;
  415. // Validate Inputs
  416. propXTraceStatic( "FmtIdToPropStgName" );
  417. GEN_VDATEREADPTRIN_LABEL(pfmtid, FMTID, E_INVALIDARG, Exit, hr);
  418. VDATESIZEPTROUT_LABEL(oszName,
  419. sizeof(OLECHAR) * (CCH_MAX_PROPSTG_NAME+1),
  420. Exit, hr);
  421. propTraceParameters(( "fmtid=%s, oszName=%p",
  422. static_cast<const char*>(CStringize(*pfmtid)), oszName ));
  423. // Make the Conversion
  424. PrGuidToPropertySetName( pfmtid, oszName );
  425. // Exit
  426. Exit:
  427. if( FAILED(hr) )
  428. {
  429. propDbg((DEB_ERROR, "FmtIdToPropStgName returns %08X\n", hr ));
  430. }
  431. return( hr );
  432. } // FmtIdToPropStgName()
  433. //+----------------------------------------------------------------------------
  434. //
  435. // Function: PropStgNameToFmtId
  436. //
  437. // Synopsis: This function maps a property set's Stream/Storage name
  438. // to its FMTID.
  439. //
  440. // Inputs: [const LPOLESTR] oszName (in)
  441. // The name of the Property Set's Stream/Storage
  442. // [FMTID*] pfmtid (out)
  443. // The FMTID of the property set.
  444. //
  445. //
  446. // Returns: [HRESULT] S_OK or E_INVALIDARG
  447. //
  448. //+----------------------------------------------------------------------------
  449. STDAPI
  450. PropStgNameToFmtId( const LPOLESTR oszName, FMTID *pfmtid )
  451. {
  452. HRESULT hr = S_OK;
  453. // Validate Inputs
  454. propXTraceStatic( "PropStgNameToFmtId" );
  455. GEN_VDATEPTROUT_LABEL(pfmtid, FMTID, E_INVALIDARG, Exit, hr);
  456. propTraceParameters(( "oszName=%p, *pfmtid=%s", oszName,
  457. static_cast<const char*>(CStringize(*pfmtid)) ));
  458. #ifdef OLE2ANSI
  459. if( FAILED(hr = ValidateNameA(oszName, CCH_MAX_PROPSTG_NAME )))
  460. goto Exit;
  461. #else
  462. if( FAILED(hr = ValidateNameW(oszName, CCH_MAX_PROPSTG_NAME )))
  463. goto Exit;
  464. #endif
  465. // Make the Conversion, passing in the name and its character-length
  466. // (not including the null-terminator).
  467. PrPropertySetNameToGuid( ocslen(oszName), oszName, pfmtid );
  468. // Exit
  469. Exit:
  470. propDbg(( DbgFlag(hr,DEB_TRACE), "PropStgNameToFmtId returns %08x", hr ));
  471. return( hr );
  472. } // PropStgNameToFmtId()
  473. //+----------------------------------------------------------------------------
  474. //
  475. // Function: CreateOrOpenDocfileOnHandle
  476. //
  477. // Create or open a Docfile IStorage (or QI-able interface) on a given
  478. // handle.
  479. //
  480. //+----------------------------------------------------------------------------
  481. CreateOrOpenDocfileOnHandle( IN BOOL fCreate,
  482. IN DWORD grfMode,
  483. IN HANDLE *phStream,
  484. IN REFIID riid,
  485. OUT void ** ppObjectOpen)
  486. {
  487. HRESULT hr = S_OK;
  488. NTSTATUS status = STATUS_SUCCESS;
  489. CNtfsStream *pnffstm = NULL;
  490. CNFFTreeMutex *pmutex = NULL;
  491. IStorage *pstg = NULL;
  492. propITraceStatic( "CreateOrOpenDocfileOnHandle" );
  493. // --------------------
  494. // Create an ILockBytes
  495. // --------------------
  496. // Instantiate a mutex
  497. pmutex = new CNFFTreeMutex();
  498. if( NULL == pmutex )
  499. {
  500. hr = E_OUTOFMEMORY;
  501. goto Exit;
  502. }
  503. hr = pmutex->Init();
  504. if ( FAILED(hr) ) goto Exit;
  505. // Use the mutex to instantiate an NFF stream object
  506. pnffstm = new CNtfsStream( NULL, pmutex );
  507. if( NULL == pnffstm )
  508. {
  509. hr = E_OUTOFMEMORY;
  510. goto Exit;
  511. }
  512. // Put the stream handle and grfMode into the NFF stream object.
  513. // We now have our ILockBytes implementation for the given handle.
  514. hr = pnffstm->Init( *phStream, grfMode, NULL, NULL );
  515. if( FAILED(hr) ) goto Exit;
  516. *phStream = INVALID_HANDLE_VALUE;
  517. // ----------------
  518. // Open the Storage
  519. // ----------------
  520. /*
  521. hr = CNtfsStorageForPropSetStg::CreateOrOpenStorageOnILockBytes( pnffstm, NULL,
  522. grfMode, NULL, fCreate,
  523. &pstg );
  524. if( FAILED(hr) ) goto Exit;
  525. */
  526. if( fCreate )
  527. {
  528. hr = StgCreateDocfileOnILockBytes( pnffstm, grfMode, 0, &pstg );
  529. }
  530. else
  531. {
  532. hr = StgOpenStorageOnILockBytes( pnffstm, NULL, grfMode, NULL, 0, &pstg );
  533. // STG_E_INVALIDHEADER in some paths of the above call gets converted into
  534. // STG_E_FILEALREADYEXISTS, which doesn't make a whole lot of sense from
  535. // from our point of view (we already knew it existed, we wanted to open it). So,
  536. // translate it back.
  537. if( STG_E_FILEALREADYEXISTS == hr )
  538. hr = STG_E_INVALIDHEADER;
  539. }
  540. if( FAILED(hr) ) goto Exit;
  541. // QI for the caller-requested IID
  542. hr = pstg->QueryInterface( riid, ppObjectOpen );
  543. if( FAILED(hr) ) goto Exit;
  544. hr = S_OK;
  545. Exit:
  546. RELEASE_INTERFACE(pnffstm);
  547. RELEASE_INTERFACE(pstg);
  548. RELEASE_INTERFACE(pmutex);
  549. return( hr );
  550. }
  551. //+----------------------------------------------------------------------------
  552. //
  553. // CreateOrOpenStorageOnHandle
  554. // StgCreateStorageOnHandle
  555. // StgOpenStorageOnHandle
  556. //
  557. // Given a handle, create or open a storage.
  558. // The caller-provided handle is duplicated.
  559. //
  560. //+----------------------------------------------------------------------------
  561. CreateOrOpenStorageOnHandle( IN BOOL fCreate,
  562. IN DWORD grfMode,
  563. IN DWORD stgfmt,
  564. IN HANDLE hStream,
  565. IN REFIID riid,
  566. OUT void ** ppObjectOpen)
  567. {
  568. HRESULT hr = S_OK;
  569. HANDLE hStreamInternal = INVALID_HANDLE_VALUE;
  570. NTSTATUS status = STATUS_SUCCESS;
  571. BOOL fIsStorageFile = FALSE;
  572. OVERLAPPED olpTemp;
  573. propXTraceStatic( "CreateOrOpenStorageOnHandle" );
  574. ZeroMemory( &olpTemp, sizeof(OVERLAPPED) );
  575. propTraceParameters(( "fCreate=%s, grfMode=%s, stgfmt=0x%x, hStream=%p, riid=%s, ppObjectOpen=%p",
  576. fCreate?"TRUE":"FALSE",
  577. static_cast<const char*>(CStringize(SGrfMode(grfMode))),
  578. stgfmt, hStream,
  579. static_cast<const char*>(CStringize(riid)), ppObjectOpen ));
  580. hr = VerifyPerms (grfMode, TRUE);
  581. if (FAILED(hr))
  582. return hr;
  583. // Make a copy of the handle so that the caller can still call
  584. // CloseHandle.
  585. if( !DuplicateHandle( GetCurrentProcess(), hStream,
  586. GetCurrentProcess(), &hStreamInternal,
  587. 0, // dwDesiredAccess, ignored because of DUPLICATE_SAME_ACCESS below
  588. FALSE, // bInheritHandle
  589. DUPLICATE_SAME_ACCESS ))
  590. {
  591. hr = HRESULT_FROM_WIN32(GetLastError());
  592. hStreamInternal = INVALID_HANDLE_VALUE;
  593. goto Exit;
  594. }
  595. // Set up an overlapped structure in preparation to call
  596. // StgIsStorageFileHandle
  597. olpTemp.hEvent = CreateEvent( NULL, // Security Attributes.
  598. TRUE, // Manual Reset Flag.
  599. FALSE, // Inital State = Signaled, Flag.
  600. NULL ); // Name
  601. if( NULL == olpTemp.hEvent )
  602. {
  603. hr = HRESULT_FROM_WIN32( GetLastError() );
  604. goto Exit;
  605. }
  606. // Does this handle represent a docfile?
  607. hr = StgIsStorageFileHandle( hStreamInternal, &olpTemp );
  608. if( HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION) == hr )
  609. {
  610. // This is the error we get when the handle is to a directory.
  611. // See if that's really the case, and if so assume that this isn't
  612. // a docfile.
  613. // Do not move this in StgIsStorageFileHandle for compatibility
  614. BY_HANDLE_FILE_INFORMATION ByHandleFileInformation;
  615. if( GetFileInformationByHandle( hStreamInternal, &ByHandleFileInformation ))
  616. {
  617. if( FILE_ATTRIBUTE_DIRECTORY & ByHandleFileInformation.dwFileAttributes )
  618. hr = S_FALSE;
  619. }
  620. }
  621. if( FAILED(hr) ) goto Exit;
  622. if( S_OK == hr )
  623. fIsStorageFile = TRUE;
  624. else
  625. DfpAssert( S_FALSE == hr );
  626. // Is this the create of a docfile/storage, or the open of an
  627. // existing docfile?
  628. if( fCreate && ( STGFMT_DOCFILE == stgfmt || STGFMT_STORAGE == stgfmt )
  629. ||
  630. !fCreate && fIsStorageFile )
  631. {
  632. // In the open path, the caller must request
  633. // either any, docfile, or storage.
  634. if( !fCreate
  635. &&
  636. STGFMT_ANY != stgfmt
  637. &&
  638. STGFMT_DOCFILE != stgfmt
  639. &&
  640. STGFMT_STORAGE != stgfmt )
  641. {
  642. hr = STG_E_INVALIDPARAMETER;
  643. goto Exit;
  644. }
  645. // Create/Open the docfile. hStreamInternal may be changed
  646. // to INVALID_HANDLE_VALUE.
  647. hr = CreateOrOpenDocfileOnHandle( fCreate, grfMode, &hStreamInternal,
  648. riid, ppObjectOpen );
  649. if( FAILED(hr) ) goto Exit;
  650. }
  651. // Otherwise, this should be the create/open of an NFF
  652. else if( fCreate && STGFMT_FILE == stgfmt
  653. ||
  654. !fCreate && !fIsStorageFile )
  655. {
  656. // In the open path, the caller must request either any or file.
  657. if( !fCreate && STGFMT_ANY != stgfmt && STGFMT_FILE != stgfmt )
  658. {
  659. hr = STG_E_INVALIDPARAMETER;
  660. goto Exit;
  661. }
  662. // Instantiate the NFF IStorage.
  663. hr = NFFOpenOnHandle( fCreate, grfMode, STGFMT_FILE,
  664. &hStreamInternal, riid, ppObjectOpen );
  665. if( FAILED(hr) ) goto Exit;
  666. }
  667. else
  668. {
  669. hr = STG_E_INVALIDPARAMETER;
  670. goto Exit;
  671. }
  672. hr = S_OK;
  673. Exit:
  674. if( INVALID_HANDLE_VALUE != hStreamInternal )
  675. CloseHandle( hStreamInternal );
  676. if( NULL != olpTemp.hEvent )
  677. CloseHandle( olpTemp.hEvent );
  678. if( STG_E_INVALIDFUNCTION == hr // This happens e.g. when we try to get NFF propsets on FAT
  679. || // This happens when we try to read a FAT directory file
  680. HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == hr )
  681. {
  682. propSuppressExitErrors();
  683. }
  684. return( hr );
  685. } // CreateOrOpenStorageOnHandle
  686. STDAPI
  687. StgCreateStorageOnHandle( IN HANDLE hStream,
  688. IN DWORD grfMode,
  689. IN DWORD stgfmt,
  690. IN void *reserved1,
  691. IN void *reserved2,
  692. IN REFIID riid,
  693. OUT void **ppObjectOpen )
  694. {
  695. return( CreateOrOpenStorageOnHandle( TRUE, grfMode, stgfmt, hStream, riid, ppObjectOpen ));
  696. }
  697. STDAPI
  698. StgOpenStorageOnHandle( IN HANDLE hStream,
  699. IN DWORD grfMode,
  700. IN void *reserved1,
  701. IN void *reserved2,
  702. IN REFIID riid,
  703. OUT void **ppObjectOpen )
  704. {
  705. return( CreateOrOpenStorageOnHandle( FALSE, grfMode, STGFMT_ANY, hStream, riid, ppObjectOpen ));
  706. }