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.

1207 lines
36 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995-2000.
  5. //
  6. // File: oleprop.cxx
  7. //
  8. // Contents: OLE Property Manager.
  9. //
  10. // Classes: COLEPropManager
  11. //
  12. // History: 13-Dec-95 dlee Created from KyleP's FCB Manager
  13. //
  14. //-------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <shlobj.h>
  18. #include <nserror.h>
  19. #include <propstm.hxx>
  20. #include <oleprop.hxx>
  21. #include <propvar.h>
  22. #include <pmalloc.hxx>
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Function: FunnyToNormalPath
  26. //
  27. // Synopsis: Gets an interface over a file using the shell
  28. //
  29. // Arguments: [pwcPath] -- Path of the file to be opened
  30. // [riid] -- Interface being requested
  31. // [ppv] -- Where the interface is returned
  32. //
  33. // Returns: SCODE result of the open
  34. //
  35. // History: 1-Feb-01 dlee Created
  36. //
  37. //----------------------------------------------------------------------------
  38. void FunnyToNormalPath( const CFunnyPath & funnyPath,
  39. WCHAR * awcPath )
  40. {
  41. WCHAR const * pwcPath = funnyPath.GetPath();
  42. #if CIDBG == 1
  43. unsigned cwc = wcslen( pwcPath );
  44. Win4Assert( cwc <= MAX_PATH );
  45. #endif // CIDBG
  46. // The shell doesn't understand the \\?\ syntax
  47. // Local: \\?\c:\foo
  48. // Remote: \\?\UNC\server\share
  49. if ( !wcsncmp( pwcPath, L"\\\\?\\", 4 ) )
  50. {
  51. pwcPath += 4;
  52. if ( !wcsncmp( pwcPath, L"UNC\\", 4 ) )
  53. pwcPath += 2;
  54. }
  55. wcscpy( awcPath, pwcPath );
  56. if ( awcPath[1] == L'\\' )
  57. awcPath[0] = L'\\';
  58. } //FunnyToNormalPath
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Function: ShellBindToItemByName
  62. //
  63. // Synopsis: Gets an interface over a file using the shell
  64. //
  65. // Arguments: [pwcPath] -- Path of the file to be opened
  66. // [riid] -- Interface being requested
  67. // [ppv] -- Where the interface is returned
  68. //
  69. // Returns: SCODE result of the open
  70. //
  71. // History: 1-Feb-01 dlee Created
  72. //
  73. //----------------------------------------------------------------------------
  74. SCODE ShellBindToItemByName(
  75. WCHAR const * pwcPath,
  76. REFIID riid,
  77. void ** ppv )
  78. {
  79. Win4Assert( wcsncmp( pwcPath, L"\\\\?\\", 4 ) );
  80. XInterface<IShellFolder> xDesktop;
  81. SCODE sc = SHGetDesktopFolder( xDesktop.GetPPointer() );
  82. if ( SUCCEEDED( sc ) )
  83. {
  84. XInterface<IBindCtx> xBindCtx;
  85. sc = CreateBindCtx( 0, xBindCtx.GetPPointer() );
  86. if ( FAILED( sc ) )
  87. return sc;
  88. BIND_OPTS bo = {sizeof(bo), 0};
  89. bo.grfFlags = BIND_JUSTTESTEXISTENCE; // skip all junctions
  90. sc = xBindCtx->SetBindOptions( &bo );
  91. if ( FAILED( sc ) )
  92. return sc;
  93. LPITEMIDLIST pidl;
  94. // cast needed for bad interface def
  95. sc = xDesktop->ParseDisplayName( 0,
  96. xBindCtx.GetPointer(),
  97. (LPWSTR) pwcPath,
  98. 0,
  99. &pidl,
  100. 0 );
  101. if ( SUCCEEDED( sc ) )
  102. {
  103. XInterface<IShellFolder> xSF;
  104. LPCITEMIDLIST pidlChild;
  105. // Note: apparently pidlChild isn't leaked here
  106. sc = SHBindToParent( pidl,
  107. IID_IShellFolder,
  108. xSF.GetQIPointer(),
  109. &pidlChild );
  110. if (SUCCEEDED(sc))
  111. sc = xSF->BindToObject( pidlChild, 0, riid, ppv );
  112. CoTaskMemFree( pidl );
  113. }
  114. }
  115. return sc;
  116. } //ShellBindToItemByName
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Member: COLEPropManager::Open, public
  120. //
  121. // Synopsis: Open object corresponding to a path.
  122. //
  123. // Arguments: [pwcPath] - path of the file to be opened
  124. //
  125. // Returns: TRUE if failed due to sharing violation, FALSE otherwise
  126. //
  127. // History: 13-Dec-95 dlee Created
  128. //
  129. //----------------------------------------------------------------------------
  130. BOOL COLEPropManager::Open( const CFunnyPath & funnyPath )
  131. {
  132. Win4Assert( 0 == _ppsstg );
  133. // if we've tried to open this file before, don't try again.
  134. if ( _fStgOpenAttempted )
  135. return _fSharingViolation;
  136. _fStgOpenAttempted = TRUE;
  137. // NTRAID#DB-NTBUG9-84131-2000/07/31-dlee Indexing Service contains workarounds for StgOpenStorage AV on > MAX_PATH paths
  138. if ( funnyPath.GetLength() >= MAX_PATH )
  139. {
  140. ciDebugOut(( DEB_WARN, "Not calling StgOpenStorage in COLEPropManager::Open for paths > MAX_PATH: \n(%ws)\n",
  141. funnyPath.GetPath() ));
  142. return FALSE;
  143. }
  144. //
  145. // Make sure the file isn't offline.
  146. //
  147. ULONG ulAttributes = GetFileAttributes( funnyPath.GetPath() );
  148. SCODE sc;
  149. if ( 0 == (ulAttributes & FILE_ATTRIBUTE_OFFLINE) ) // Note: attrib is also *on* in the error return
  150. {
  151. //
  152. // Get an IPropertSetStorage.
  153. //
  154. #if 0
  155. sc = StgOpenStorageEx( funnyPath.GetPath(), // Path
  156. STGM_DIRECT |
  157. STGM_READ |
  158. STGM_SHARE_DENY_WRITE, // Flags (BChapman said use these)
  159. STGFMT_ANY, // Format
  160. 0, // Reserved
  161. 0, // Reserved
  162. 0, // Reserved
  163. IID_IPropertySetStorage, // IID
  164. (void **)&_ppsstg );
  165. #else
  166. //
  167. // Note: Because of the above MAX_PATH check, we can copy into a fixed-length buffer
  168. // We need to hold onto the path because the shell open function expects the path to
  169. // remain valid for the life of the IPropertySetStorage we get back.
  170. //
  171. FunnyToNormalPath( funnyPath, _awcPath );
  172. // Use the shell's open to get additional properties from .mp3 files and others
  173. sc = ShellBindToItemByName( _awcPath,
  174. IID_IPropertySetStorage,
  175. (void **) &_ppsstg );
  176. #endif
  177. }
  178. else
  179. sc = HRESULT_FROM_WIN32(ERROR_FILE_OFFLINE);
  180. if ( FAILED( sc ) )
  181. {
  182. vqDebugOut(( DEB_IWARN, "StgOpenStorage %ws returned 0x%x\n",
  183. funnyPath.GetPath(), sc ));
  184. // For these nonfatal errors, fail silently.
  185. // Assuming STG_E_INVALIDNAME means the file didn't exist, but
  186. // even if it means the string is malformed it's ok to ignore.
  187. if ( STG_E_LOCKVIOLATION == sc ||
  188. STG_E_SHAREVIOLATION == sc )
  189. {
  190. _fSharingViolation = TRUE;
  191. return TRUE;
  192. }
  193. if ( STG_E_INVALIDFUNCTION == sc || // Common StgOpenStorageEx error (FAT volumes)
  194. STG_E_FILEALREADYEXISTS == sc || // Common StgOpenStorage error (FAT volumes)
  195. STG_E_ACCESSDENIED == sc ||
  196. STG_E_OLDFORMAT == sc ||
  197. STG_E_OLDDLL == sc ||
  198. STG_E_PATHNOTFOUND == sc ||
  199. STG_E_FILENOTFOUND == sc ||
  200. STG_E_INVALIDHEADER == sc ||
  201. STG_E_INVALIDNAME == sc ||
  202. HRESULT_FROM_WIN32(ERROR_FILE_OFFLINE) == sc )
  203. return FALSE;
  204. // these errors would mean a CI coding bug
  205. Win4Assert( STG_E_INVALIDPOINTER != sc );
  206. Win4Assert( STG_E_INVALIDFLAG != sc );
  207. // Almost any error code can be returned from StgOpenStorage.
  208. // The doc has little relation to the set of return codes.
  209. // This assert is just here so we know when we hit it whether
  210. // to put the new error in the ignore list (above) or the throw
  211. // list (here).
  212. Win4Assert( E_UNEXPECTED == sc ||
  213. E_OUTOFMEMORY == sc ||
  214. ERROR_NO_SYSTEM_RESOURCES ||
  215. STG_E_TOOMANYOPENFILES == sc ||
  216. STG_E_INSUFFICIENTMEMORY == sc ||
  217. ( HRESULT_FROM_WIN32( ERROR_NOT_READY ) == sc ) );
  218. THROW( CException( sc ) );
  219. }
  220. return FALSE;
  221. } //Open
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Member: COLEPropManager::PropSetToOrdinal, public
  225. //
  226. // Synopsis: Find property set for specified GUID.
  227. //
  228. // Arguments: [guidPS] -- GUID of property set.
  229. //
  230. // Returns: Ordinal of property set.
  231. //
  232. // History: 13-Dec-95 dlee Created
  233. //
  234. //----------------------------------------------------------------------------
  235. unsigned COLEPropManager::PropSetToOrdinal(
  236. GUID const & guidPS )
  237. {
  238. //
  239. // This is likely to be a very small array. Just go for a linear search.
  240. //
  241. for ( unsigned i = 0; i < _aPropSets.Count(); i++ )
  242. {
  243. if ( _aPropSets[ i ].GetGuid() == guidPS )
  244. return i;
  245. }
  246. //
  247. // New property set. Need to add entry.
  248. //
  249. _aPropSets[ i ] = COLEPropManager::CPropSetMap( guidPS );
  250. return i;
  251. } //PropSetToOrdinal
  252. //+---------------------------------------------------------------------------
  253. //
  254. // Function: IsNullPointerVariant
  255. //
  256. // Synopsis: Determines if a variant looks like it should have a
  257. // pointer but doesn't.
  258. //
  259. // Arguments: [ppv] -- the variant to test
  260. //
  261. // Returns: TRUE if a variant with a 0 pointer, FALSE otherwise
  262. //
  263. // History: 04-Mar-96 dlee Created
  264. //
  265. //----------------------------------------------------------------------------
  266. BOOL IsNullPointerVariant(
  267. PROPVARIANT *ppv )
  268. {
  269. if ( (VT_VECTOR & ppv->vt) &&
  270. 0 != ppv->cal.cElems &&
  271. 0 == ppv->cal.pElems )
  272. return TRUE;
  273. switch (ppv->vt)
  274. {
  275. case VT_CLSID:
  276. return ( 0 == ppv->puuid );
  277. case VT_BLOB:
  278. case VT_BLOB_OBJECT:
  279. return ( ( 0 != ppv->blob.cbSize ) &&
  280. ( 0 == ppv->blob.pBlobData ) );
  281. case VT_CF:
  282. return ( ( 0 == ppv->pclipdata ) ||
  283. ( 0 == ppv->pclipdata->pClipData ) );
  284. case VT_BSTR:
  285. case VT_LPSTR:
  286. case VT_LPWSTR:
  287. return ( 0 == ppv->pszVal );
  288. case VT_VECTOR | VT_BSTR:
  289. case VT_VECTOR | VT_LPSTR:
  290. case VT_VECTOR | VT_LPWSTR:
  291. {
  292. for (unsigned i = 0; i < ppv->calpstr.cElems; i++)
  293. {
  294. if ( 0 == ppv->calpstr.pElems[i] )
  295. return TRUE;
  296. }
  297. break;
  298. }
  299. case VT_VECTOR | VT_VARIANT:
  300. {
  301. for (unsigned i = 0; i < ppv->capropvar.cElems; i++)
  302. {
  303. if ( IsNullPointerVariant( & (ppv->capropvar.pElems[i]) ) )
  304. return TRUE;
  305. }
  306. break;
  307. }
  308. }
  309. return FALSE;
  310. } //IsNullPointerVariant
  311. //+---------------------------------------------------------------------------
  312. //
  313. // Member: COLEPropManager::FetchProperty, public
  314. //
  315. // Synopsis: Retrieve a property from a property set.
  316. //
  317. // Arguments: [guidPS] -- property set to read from
  318. // [psProperty] -- PROPSPEC for property.
  319. // [pbData] -- Property stored here.
  320. // [pcb] -- Size in bytes of [pbData]. On output, size
  321. // actually required. An output <= input
  322. // implies property successfully retrieved.
  323. //
  324. // History: 13-Dec-95 dlee Created
  325. // 27-Aug-97 kylep Convert Ole summary info to Unicode
  326. //
  327. //----------------------------------------------------------------------------
  328. inline BYTE * PastHeader(
  329. PROPVARIANT * ppv )
  330. {
  331. return( (BYTE *)ppv + sizeof( PROPVARIANT ) );
  332. }
  333. #define VCASE( vvar, type ) \
  334. cb += var[0].vvar.cElems * sizeof(var[0].vvar.pElems[0]); \
  335. if ( cb <= *pcb ) \
  336. { \
  337. pbData->vvar.pElems = (type *)PastHeader(pbData); \
  338. memcpy( pbData->vvar.pElems, \
  339. var[0].vvar.pElems, \
  340. var[0].vvar.cElems * sizeof(var[0].vvar.pElems[0]) ); \
  341. }
  342. void COLEPropManager::FetchProperty(
  343. GUID const & guidPS,
  344. PROPSPEC const & psProperty,
  345. PROPVARIANT * pbData,
  346. unsigned * pcb )
  347. {
  348. if ( 0 == _ppsstg )
  349. {
  350. pbData->vt = VT_EMPTY;
  351. *pcb = sizeof( *pbData );
  352. return;
  353. }
  354. //
  355. // The Office custom property set may not be opened when any other
  356. // property set is opened, so treat this as a special case.
  357. // Close all other property sets when opening it, and close it
  358. // when opening any other property set.
  359. //
  360. if ( FMTID_UserDefinedProperties == guidPS )
  361. {
  362. if ( !_fOfficeCustomPropsetOpen )
  363. {
  364. _aPropSets.Clear();
  365. _fOfficeCustomPropsetOpen = TRUE;
  366. }
  367. }
  368. else if ( _fOfficeCustomPropsetOpen )
  369. {
  370. _aPropSets.Clear();
  371. _fOfficeCustomPropsetOpen = FALSE;
  372. }
  373. unsigned iPropSet = PropSetToOrdinal( guidPS );
  374. Win4Assert( iPropSet < _aPropSets.Count() );
  375. COLEPropManager::CPropSetMap & sm = _aPropSets[ iPropSet ];
  376. //
  377. // May have to open the set.
  378. //
  379. if ( !sm.isOpen( _ppsstg ) )
  380. {
  381. pbData->vt = VT_EMPTY;
  382. *pcb = sizeof( *pbData );
  383. return;
  384. }
  385. PROPVARIANT var[2];
  386. PropVariantInit( &var[0] );
  387. PropVariantInit( &var[1] );
  388. PROPSPEC aps[2];
  389. aps[0] = psProperty;
  390. aps[1].ulKind = PRSPEC_PROPID;
  391. aps[1].propid = PID_CODEPAGE;
  392. SCODE sc = sm.GetPS().ReadMultiple( 2,
  393. aps,
  394. var );
  395. // A few specific failures should throw and and cause the
  396. // entire query to fail.
  397. if ( E_OUTOFMEMORY == sc ||
  398. STG_E_INSUFFICIENTMEMORY == sc ||
  399. E_UNEXPECTED == sc )
  400. THROW( CException( sc ) );
  401. if ( FAILED( sc ) )
  402. {
  403. // the first three would be due to invalid parameters, which
  404. // would be a programming bug.
  405. Win4Assert( STG_E_INVALIDPARAMETER != sc );
  406. Win4Assert( STG_E_INVALIDPOINTER != sc );
  407. Win4Assert( HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION) != sc );
  408. // access-denied is the only legal error that maps to VT_EMPTY
  409. Win4Assert( STG_E_ACCESSDENIED == sc );
  410. pbData->vt = VT_EMPTY;
  411. *pcb = sizeof( *pbData );
  412. return;
  413. }
  414. // The rest of the query code doesn't understand variants that
  415. // require a pointer but don't have one. Such variants are legal,
  416. // but we map them to VT_EMPTY.
  417. if ( IsNullPointerVariant( &var[0] ) )
  418. {
  419. FreePropVariantArray( 1, &var[0] );
  420. pbData->vt = VT_EMPTY;
  421. *pcb = sizeof( *pbData );
  422. return;
  423. }
  424. //
  425. // Maybe we didn't get a codepage?
  426. //
  427. DWORD dwCodepage = ( var[1].vt == VT_I2 && CP_WINUNICODE != var[1].iVal ) ?
  428. (unsigned short) var[1].iVal :
  429. CP_ACP;
  430. *pbData = var[0];
  431. unsigned cb = sizeof PROPVARIANT;
  432. //
  433. // Deal with variable length portion.
  434. //
  435. switch ( var[0].vt )
  436. {
  437. case VT_EMPTY:
  438. case VT_NULL:
  439. case VT_I1:
  440. case VT_UI1:
  441. case VT_I2:
  442. case VT_UI2:
  443. case VT_I4:
  444. case VT_UI4:
  445. case VT_INT:
  446. case VT_UINT:
  447. case VT_DECIMAL:
  448. case VT_I8:
  449. case VT_UI8:
  450. case VT_R4:
  451. case VT_R8:
  452. case VT_BOOL:
  453. case VT_ILLEGAL:
  454. case VT_ERROR:
  455. case VT_CY:
  456. case VT_DATE:
  457. case VT_FILETIME:
  458. break; // fixed length types -- nothing to do
  459. case VT_BSTR:
  460. cb += BSTRLEN( var[0].bstrVal ) + sizeof(OLECHAR) + sizeof(DWORD);
  461. if (cb <= *pcb)
  462. {
  463. BSTR bstr = (BSTR) PastHeader(pbData);
  464. memcpy( bstr, &BSTRLEN(var[0].bstrVal), cb - sizeof(PROPVARIANT) );
  465. pbData->bstrVal = (BSTR) (((DWORD *)bstr) + 1);
  466. }
  467. break;
  468. case VT_LPSTR:
  469. //
  470. // HACK #274: Translate the Ole summary information LPSTR in LPWSTR
  471. // Makes these properties compatible with HTML filter
  472. // equivalents.
  473. //
  474. if ( FMTID_SummaryInformation == guidPS )
  475. {
  476. unsigned cc = strlen( var[0].pszVal ) + 1;
  477. unsigned ccT = MultiByteToWideChar( dwCodepage,
  478. 0, // precomposed used if the codepage supports it
  479. var[0].pszVal,
  480. cc,
  481. (WCHAR *)PastHeader(pbData),
  482. (*pcb - sizeof(PROPVARIANT)) / sizeof(WCHAR) );
  483. if ( 0 == ccT )
  484. {
  485. if ( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  486. {
  487. unsigned ccNeeded = MultiByteToWideChar( dwCodepage,
  488. 0, // precomposed used if the codepage supports it
  489. var[0].pszVal,
  490. cc,
  491. 0,
  492. 0 );
  493. Win4Assert( ccNeeded > 0 );
  494. cb += ccNeeded * sizeof(WCHAR);
  495. }
  496. else
  497. {
  498. ciDebugOut(( DEB_ERROR, "Error %d converting \"%s\" to codepage 0x%x\n",
  499. GetLastError(), var[0].pszVal, dwCodepage ));
  500. cb += strlen( var[0].pszVal ) + 1;
  501. if (cb <= *pcb)
  502. {
  503. pbData->pszVal = (char *)PastHeader(pbData);
  504. memcpy( pbData->pszVal, var[0].pszVal, cb - sizeof(PROPVARIANT) );
  505. }
  506. }
  507. }
  508. if ( ccT != 0 )
  509. {
  510. pbData->vt = VT_LPWSTR;
  511. pbData->pwszVal = (WCHAR *)PastHeader(pbData);
  512. cb += ccT * sizeof(WCHAR);
  513. }
  514. }
  515. else
  516. {
  517. cb += strlen( var[0].pszVal ) + 1;
  518. if (cb <= *pcb)
  519. {
  520. pbData->pszVal = (char *)PastHeader(pbData);
  521. memcpy( pbData->pszVal, var[0].pszVal, cb - sizeof(PROPVARIANT) );
  522. }
  523. }
  524. break;
  525. case VT_LPWSTR:
  526. cb += (wcslen( var[0].pwszVal ) + 1) * sizeof(WCHAR);
  527. if (cb <= *pcb)
  528. {
  529. pbData->pwszVal = (WCHAR *)PastHeader(pbData);
  530. memcpy( pbData->pwszVal, var[0].pwszVal, cb - sizeof(PROPVARIANT) );
  531. }
  532. break;
  533. case VT_CLSID:
  534. cb += sizeof(GUID);
  535. if (cb <= *pcb)
  536. {
  537. pbData->puuid = (GUID *)PastHeader(pbData);
  538. memcpy( pbData->puuid, var[0].puuid, cb - sizeof(PROPVARIANT) );
  539. }
  540. break;
  541. case VT_BLOB:
  542. cb += var[0].blob.cbSize;
  543. if (cb <= *pcb)
  544. {
  545. pbData->blob.pBlobData = PastHeader(pbData);
  546. memcpy( pbData->blob.pBlobData, var[0].blob.pBlobData, cb - sizeof(PROPVARIANT) );
  547. }
  548. break;
  549. case VT_CF:
  550. cb += sizeof(*(var[0].pclipdata)) + CBPCLIPDATA(*var[0].pclipdata);
  551. if ( cb <= *pcb )
  552. {
  553. pbData->pclipdata = (CLIPDATA *)PastHeader(pbData);
  554. memcpy( pbData->pclipdata, var[0].pclipdata, sizeof(*(var[0].pclipdata)) );
  555. pbData->pclipdata->pClipData = PastHeader(pbData) + sizeof(*(var[0].pclipdata));
  556. memcpy( pbData->pclipdata->pClipData,
  557. var[0].pclipdata->pClipData,
  558. CBPCLIPDATA(*var[0].pclipdata) );
  559. }
  560. break;
  561. //
  562. // Vectors (ugh!)
  563. //
  564. case VT_I1|VT_VECTOR:
  565. case VT_UI1|VT_VECTOR:
  566. VCASE( caub, BYTE );
  567. break;
  568. case VT_I2|VT_VECTOR:
  569. VCASE( cai, short );
  570. break;
  571. case VT_UI2|VT_VECTOR:
  572. VCASE( caui, USHORT );
  573. break;
  574. case VT_BOOL|VT_VECTOR:
  575. VCASE( cabool, VARIANT_BOOL );
  576. break;
  577. case VT_I4|VT_VECTOR:
  578. case VT_INT|VT_VECTOR:
  579. VCASE( cal, long );
  580. break;
  581. case VT_UI4|VT_VECTOR:
  582. case VT_UINT|VT_VECTOR:
  583. VCASE( caul, ULONG );
  584. break;
  585. case VT_R4|VT_VECTOR:
  586. VCASE( caflt, float );
  587. break;
  588. case VT_ERROR|VT_VECTOR:
  589. VCASE( cascode, SCODE );
  590. break;
  591. case VT_I8|VT_VECTOR:
  592. VCASE( cah, LARGE_INTEGER );
  593. break;
  594. case VT_UI8|VT_VECTOR:
  595. VCASE( cauh, ULARGE_INTEGER );
  596. break;
  597. case VT_R8|VT_VECTOR:
  598. VCASE( cadbl, double );
  599. break;
  600. case VT_CY|VT_VECTOR:
  601. VCASE( cacy, CY );
  602. break;
  603. case VT_DATE|VT_VECTOR:
  604. VCASE( cadate, DATE );
  605. break;
  606. case VT_FILETIME|VT_VECTOR:
  607. VCASE( cafiletime, FILETIME );
  608. break;
  609. case VT_CLSID|VT_VECTOR:
  610. VCASE( cauuid, CLSID );
  611. break;
  612. case VT_CF|VT_VECTOR:
  613. {
  614. cb += var[0].caclipdata.cElems * sizeof(var[0].caclipdata.pElems[0]);
  615. for ( unsigned i = 0; i < var[0].caclipdata.cElems; i++ )
  616. {
  617. cb += CBPCLIPDATA(var[0].caclipdata.pElems[i]);
  618. }
  619. if ( cb <= *pcb )
  620. {
  621. pbData->caclipdata.pElems = (CLIPDATA *)PastHeader(pbData);
  622. memcpy( pbData->caclipdata.pElems,
  623. var[0].caclipdata.pElems,
  624. var[0].caclipdata.cElems * sizeof(var[0].caclipdata.pElems[0]) );
  625. BYTE * pb = PastHeader(pbData) + var[0].caclipdata.cElems * sizeof(var[0].caclipdata.pElems[0]);
  626. for ( i = 0; i < var[0].caclipdata.cElems; i++ )
  627. {
  628. pbData->caclipdata.pElems[i].pClipData = pb;
  629. memcpy( pbData->caclipdata.pElems[i].pClipData,
  630. var[0].caclipdata.pElems[i].pClipData,
  631. CBPCLIPDATA(var[0].caclipdata.pElems[i]) );
  632. pb += CBPCLIPDATA(var[0].caclipdata.pElems[i]);
  633. }
  634. }
  635. break;
  636. }
  637. case VT_LPSTR|VT_VECTOR:
  638. {
  639. cb += var[0].calpstr.cElems * sizeof( var[0].calpstr.pElems[0] );
  640. for ( unsigned i = 0; i < var[0].calpstr.cElems; i++ )
  641. {
  642. cb += strlen( var[0].calpstr.pElems[i] ) + 1;
  643. }
  644. if ( cb <= *pcb )
  645. {
  646. pbData->calpstr.pElems = (char **)PastHeader(pbData);
  647. char * pc = (char *)PastHeader(pbData) +
  648. var[0].calpstr.cElems * sizeof( var[0].calpstr.pElems[0] );
  649. for ( i = 0; i < var[0].calpstr.cElems; i++ )
  650. {
  651. pbData->calpstr.pElems[i] = pc;
  652. unsigned cc = strlen( var[0].calpstr.pElems[i] ) + 1;
  653. memcpy( pbData->calpstr.pElems[i],
  654. var[0].calpstr.pElems[i],
  655. cc );
  656. pc += cc;
  657. }
  658. }
  659. break;
  660. }
  661. case VT_LPWSTR|VT_VECTOR:
  662. {
  663. cb += var[0].calpwstr.cElems * sizeof( var[0].calpwstr.pElems[0] );
  664. for ( unsigned i = 0; i < var[0].calpwstr.cElems; i++ )
  665. {
  666. cb += (wcslen( var[0].calpwstr.pElems[i] ) + 1) * sizeof(WCHAR);
  667. }
  668. if ( cb <= *pcb )
  669. {
  670. pbData->calpwstr.pElems = (WCHAR **)PastHeader(pbData);
  671. WCHAR * pwc = (WCHAR *)(PastHeader(pbData) +
  672. var[0].calpwstr.cElems * sizeof( var[0].calpwstr.pElems[0] ));
  673. for ( i = 0; i < var[0].calpwstr.cElems; i++ )
  674. {
  675. pbData->calpwstr.pElems[i] = pwc;
  676. unsigned cc = wcslen( var[0].calpwstr.pElems[i] ) + 1;
  677. memcpy( pbData->calpwstr.pElems[i],
  678. var[0].calpwstr.pElems[i],
  679. cc * sizeof(WCHAR) );
  680. pwc += cc;
  681. }
  682. }
  683. break;
  684. }
  685. case VT_BSTR|VT_VECTOR:
  686. {
  687. cb += var[0].cabstr.cElems * sizeof( var[0].cabstr.pElems[0] );
  688. for ( unsigned i = 0; i < var[0].cabstr.cElems; i++ )
  689. {
  690. cb += AlignBlock( BSTRLEN( var[0].cabstr.pElems[i] ) +
  691. sizeof OLECHAR + sizeof DWORD,
  692. sizeof DWORD );
  693. }
  694. if ( cb <= *pcb )
  695. {
  696. pbData->cabstr.pElems = (BSTR *)PastHeader(pbData);
  697. BSTR pwc = (BSTR)(PastHeader(pbData) +
  698. var[0].cabstr.cElems * sizeof( var[0].cabstr.pElems[0] ));
  699. for ( i = 0; i < var[0].cabstr.cElems; i++ )
  700. {
  701. pbData->cabstr.pElems[i] = (BSTR) (((DWORD *) pwc) + 1);
  702. unsigned cbbstr = BSTRLEN( var[0].cabstr.pElems[i] ) +
  703. sizeof(OLECHAR) + sizeof (DWORD);
  704. memcpy( pwc,
  705. &BSTRLEN(var[0].cabstr.pElems[i]),
  706. cbbstr);
  707. pwc += AlignBlock( cbbstr, sizeof DWORD ) / sizeof OLECHAR;
  708. }
  709. }
  710. break;
  711. }
  712. case VT_ARRAY | VT_I4:
  713. case VT_ARRAY | VT_UI1:
  714. case VT_ARRAY | VT_I2:
  715. case VT_ARRAY | VT_R4:
  716. case VT_ARRAY | VT_R8:
  717. case VT_ARRAY | VT_BOOL:
  718. case VT_ARRAY | VT_ERROR:
  719. case VT_ARRAY | VT_CY:
  720. case VT_ARRAY | VT_DATE:
  721. case VT_ARRAY | VT_I1:
  722. case VT_ARRAY | VT_UI2:
  723. case VT_ARRAY | VT_UI4:
  724. case VT_ARRAY | VT_INT:
  725. case VT_ARRAY | VT_UINT:
  726. case VT_ARRAY | VT_DECIMAL:
  727. case VT_ARRAY | VT_BSTR:
  728. case VT_ARRAY | VT_VARIANT:
  729. {
  730. SAFEARRAY * pSaSrc = var[0].parray;
  731. SAFEARRAY * pSaDest = 0;
  732. cb += SaComputeSize( var[0].vt & ~VT_ARRAY, *pSaSrc );
  733. ciDebugOut(( DEB_ITRACE, "fetch safearray, *pcb, cb: %d, %d\n", *pcb, cb ));
  734. if ( cb <= *pcb )
  735. {
  736. CNonAlignAllocator ma( *pcb - sizeof (PROPVARIANT), PastHeader(pbData) );
  737. if ( SaCreateAndCopy( ma, pSaSrc, &pSaDest ) &&
  738. SaCreateDataUsingMA( ma,
  739. var[0].vt & ~VT_ARRAY,
  740. *pSaSrc,
  741. *pSaDest,
  742. TRUE) )
  743. {
  744. pbData->parray = pSaDest;
  745. ciDebugOut(( DEB_ITRACE, " pSaDest: %#x\n", pSaDest ));
  746. }
  747. else
  748. {
  749. // We've been guaranteed by SaComputeSize and *pcb that there
  750. // is sufficient memory to copy the array. There must be a
  751. // bug if we can't.
  752. ciDebugOut(( DEB_ERROR,
  753. " can't copy SA %#x using %d bytes\n",
  754. pSaSrc, cb ));
  755. Win4Assert( !"can't copy safearray" );
  756. }
  757. }
  758. break;
  759. }
  760. case VT_VARIANT|VT_VECTOR:
  761. {
  762. vqDebugOut(( DEB_WARN,
  763. "COLEPropManager::FetchProperty - variant vector fetch %x\n",
  764. &var[0] ));
  765. //Win4Assert( !"Fetch of variant vector not yet implemented" );
  766. pbData->vt = VT_EMPTY;
  767. *pcb = sizeof( *pbData );
  768. break;
  769. }
  770. case VT_STREAM:
  771. case VT_STREAMED_OBJECT:
  772. case VT_STORED_OBJECT:
  773. case VT_BLOB_OBJECT:
  774. {
  775. //
  776. // We don't support these datatypes. Some make since to support
  777. // some day, but users can always retrieve the path and load the
  778. // values themselves. Performance-wise it makes no since for us
  779. // to remote the values from our process.
  780. //
  781. pbData->vt = VT_EMPTY;
  782. cb = sizeof( *pbData );
  783. break;
  784. }
  785. default:
  786. Win4Assert( !"Unhandled variant type!" );
  787. }
  788. //
  789. // Cleanup
  790. //
  791. FreePropVariantArray( 1, &var[0] );
  792. *pcb = cb;
  793. } //FetchProperty
  794. //+---------------------------------------------------------------------------
  795. //
  796. // Member: COLEPropManager::CPropSetMap::isOpen, public
  797. //
  798. // Synopsis: Opens a property storage if it isn't already open
  799. //
  800. // Arguments: [ppsstg] - property set storage from which property
  801. // storage is opened.
  802. //
  803. // History: 13-Dec-95 dlee Created
  804. //
  805. //----------------------------------------------------------------------------
  806. BOOL COLEPropManager::CPropSetMap::isOpen(
  807. IPropertySetStorage * ppsstg )
  808. {
  809. if ( 0 != _pstg )
  810. return TRUE;
  811. if ( _fOpenAttempted )
  812. return FALSE;
  813. _fOpenAttempted = TRUE;
  814. SCODE sc = ppsstg->Open( _guid,
  815. STGM_READ | STGM_SHARE_EXCLUSIVE, // BChapman said to use these
  816. & _pstg );
  817. if ( FAILED( sc ) )
  818. {
  819. // don't fail the entire query if the property set doesn't
  820. // exist or if access is not allowed for this user, or if the
  821. // file was reverted after being opened.
  822. if ( STG_E_FILENOTFOUND != sc &&
  823. STG_E_ACCESSDENIED != sc &&
  824. NS_E_UNRECOGNIZED_STREAM_TYPE != sc && // The Shell enumeration routines do this
  825. NS_E_INVALID_DATA != sc && //
  826. NS_E_FILE_INIT_FAILED != sc && // ""
  827. NS_E_FILE_OPEN_FAILED != sc && // ""
  828. E_FAIL != sc && // ""
  829. STG_E_REVERTED != sc )
  830. {
  831. vqDebugOut(( DEB_WARN, "psstg->open failed: 0x%x\n", sc ));
  832. // this would be a coding bug in CI
  833. Win4Assert( STG_E_INVALIDPARAMETER != sc );
  834. Win4Assert( E_UNEXPECTED == sc ||
  835. E_OUTOFMEMORY == sc ||
  836. STG_E_INSUFFICIENTMEMORY == sc ||
  837. STG_E_INVALIDHEADER == sc ||
  838. STG_E_DOCFILECORRUPT == sc ||
  839. ( HRESULT_FROM_WIN32( ERROR_NOT_READY ) == sc ) );
  840. THROW( CException( sc ) );
  841. }
  842. }
  843. return SUCCEEDED( sc );
  844. } //isOpen
  845. //+---------------------------------------------------------------------------
  846. //
  847. // Member: COLEPropManager::CPropSetMap::Close, public
  848. //
  849. // Synopsis: Closes a property storage
  850. //
  851. // History: 13-Dec-95 dlee Created
  852. //
  853. //----------------------------------------------------------------------------
  854. void COLEPropManager::CPropSetMap::Close()
  855. {
  856. if ( 0 != _pstg )
  857. {
  858. _pstg->Release();
  859. _pstg = 0;
  860. }
  861. _fOpenAttempted = FALSE;
  862. } //Close
  863. //+---------------------------------------------------------------------------
  864. //
  865. // Member: COLEPropManager::ReadProperty, public
  866. //
  867. // Synopsis: Reads an OLE property value using CoTaskMem memory
  868. //
  869. // Arguments: [ps] -- property spec to read
  870. // [Var] -- where to put the value
  871. //
  872. // Returns: TRUE if a value found, FALSE otherwise, or throws on error
  873. //
  874. // History: 18-Dec-97 dlee Created
  875. //
  876. //----------------------------------------------------------------------------
  877. BOOL COLEPropManager::ReadProperty(
  878. CFullPropSpec const & ps,
  879. PROPVARIANT & Var )
  880. {
  881. Var.vt = VT_EMPTY;
  882. if ( 0 == _ppsstg )
  883. return FALSE;
  884. //
  885. // Open the property storage for the given guid
  886. //
  887. IPropertyStorage * pPropStg;
  888. SCODE sc = _ppsstg->Open( ps.GetPropSet(), // guid
  889. STGM_READ | STGM_SHARE_EXCLUSIVE, // BChapman said to use these...
  890. &pPropStg );
  891. if ( SUCCEEDED(sc) )
  892. {
  893. XInterface<IPropertyStorage> xPropStg( pPropStg );
  894. //
  895. // Read the value
  896. //
  897. //
  898. // HACK #274: Translate the Ole summary information LPSTR in LPWSTR
  899. // Makes these properties compatible with HTML filter
  900. // equivalents.
  901. //
  902. if ( ps.GetPropSet() == FMTID_SummaryInformation )
  903. {
  904. PROPVARIANT var[2];
  905. PropVariantInit( &var[0] );
  906. PropVariantInit( &var[1] );
  907. PROPSPEC aps[2];
  908. aps[0] = ps.GetPropSpec();
  909. aps[1].ulKind = PRSPEC_PROPID;
  910. aps[1].propid = PID_CODEPAGE;
  911. sc = xPropStg->ReadMultiple( 2,
  912. aps,
  913. var );
  914. if ( FAILED(sc) )
  915. return DBSTATUS_S_ISNULL;
  916. //
  917. // Did we get a codepage?
  918. //
  919. DWORD dwCodepage = ( var[1].vt == VT_I2 && CP_WINUNICODE != var[1].iVal ) ?
  920. (unsigned short) var[1].iVal :
  921. CP_ACP;
  922. if ( VT_LPWSTR == var[0].vt )
  923. {
  924. //
  925. // Convert to Unicode
  926. //
  927. unsigned cc = strlen( var[0].pszVal ) + 1;
  928. XGrowable<WCHAR> xwcsProp( cc + (cc * 10 / 100) ); // 10% fluff
  929. unsigned ccT = 0;
  930. while ( 0 == ccT )
  931. {
  932. ccT = MultiByteToWideChar( dwCodepage,
  933. 0, // precomposed implied if the codepage supports it
  934. var[0].pszVal,
  935. cc,
  936. xwcsProp.Get(),
  937. xwcsProp.Count() );
  938. if ( 0 == ccT )
  939. {
  940. if ( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  941. {
  942. unsigned ccNeeded = MultiByteToWideChar( dwCodepage,
  943. 0, // precomposed implied if the codepage supports it
  944. var[0].pszVal,
  945. cc,
  946. 0,
  947. 0 );
  948. Win4Assert( ccNeeded > 0 );
  949. xwcsProp.SetSize( ccNeeded );
  950. }
  951. else
  952. {
  953. vqDebugOut(( DEB_ERROR, "Error %d converting %s to codepage 0x%x\n",
  954. GetLastError(), var[0].pszVal, dwCodepage ));
  955. ccT = 0;
  956. break;
  957. }
  958. }
  959. }
  960. if ( ccT != 0 )
  961. {
  962. Var.vt = VT_LPWSTR;
  963. Var.pwszVal = (WCHAR *)CoTaskMemAlloc( ccT * sizeof(WCHAR) );
  964. if ( 0 == Var.pwszVal )
  965. {
  966. FreePropVariantArray( 2, var );
  967. THROW( CException( E_OUTOFMEMORY ) );
  968. }
  969. RtlCopyMemory( Var.pwszVal, xwcsProp.Get(), ccT * sizeof(WCHAR) );
  970. FreePropVariantArray( 2, var );
  971. }
  972. else
  973. Var = var[0];
  974. }
  975. else
  976. Var = var[0];
  977. }
  978. else
  979. {
  980. sc = xPropStg->ReadMultiple( 1, // 1 value to retrieve
  981. &ps.GetPropSpec(),
  982. &Var );
  983. }
  984. }
  985. if ( STG_E_FILENOTFOUND == sc ||
  986. STG_E_ACCESSDENIED == sc )
  987. return FALSE;
  988. if ( FAILED( sc ) )
  989. THROW( CException( sc ) );
  990. return TRUE;
  991. } //ReadProperty