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.

757 lines
22 KiB

  1. #define UNICODE
  2. #define _OLE32_
  3. #include <windows.h>
  4. #include <shlobj.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <limits.h>
  8. #include <eh.h>
  9. #include "minici.hxx"
  10. typedef HRESULT (STDAPICALLTYPE * LPStgOpenStorageEx) (
  11. const WCHAR* pwcsName,
  12. DWORD grfMode,
  13. DWORD stgfmt, // enum
  14. DWORD grfAttrs, // reserved
  15. STGOPTIONS * pStgOptions,
  16. void * reserved,
  17. REFIID riid,
  18. void ** ppObjectOpen );
  19. typedef HRESULT (STDAPICALLTYPE * PSHGetDesktopFolder) (
  20. IShellFolder ** ppshf );
  21. typedef HRESULT (STDAPICALLTYPE * PSHBindToParent) (
  22. LPCITEMIDLIST pidl,
  23. REFIID riid,
  24. void **ppv,
  25. LPCITEMIDLIST *ppidlLast);
  26. PSHGetDesktopFolder pShGetDesktopFolder = 0;
  27. PSHBindToParent pShBindToParent = 0;
  28. void Usage()
  29. {
  30. printf( "usage: enumprop [-s] filename\n" );
  31. printf( " -s -- use the shell's property code instead of OLE\n" );
  32. exit( 1 );
  33. } //Usage
  34. //+-------------------------------------------------------------------------
  35. //
  36. // Function: Render
  37. //
  38. // Synopsis: Prints an item in a safearray
  39. //
  40. // Arguments: [vt] - type of the element
  41. // [pa] - pointer to the item
  42. //
  43. //--------------------------------------------------------------------------
  44. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa );
  45. void Render( VARTYPE vt, void * pv )
  46. {
  47. if ( VT_ARRAY & vt )
  48. {
  49. PrintSafeArray( vt - VT_ARRAY, *(SAFEARRAY **) pv );
  50. return;
  51. }
  52. switch ( vt )
  53. {
  54. case VT_UI1: wprintf( L"%u", (unsigned) *(BYTE *)pv ); break;
  55. case VT_I1: wprintf( L"%d", (int) *(CHAR *)pv ); break;
  56. case VT_UI2: wprintf( L"%u", (unsigned) *(USHORT *)pv ); break;
  57. case VT_I2: wprintf( L"%d", (int) *(SHORT *)pv ); break;
  58. case VT_UI4:
  59. case VT_UINT: wprintf( L"%u", (unsigned) *(ULONG *)pv ); break;
  60. case VT_I4:
  61. case VT_ERROR:
  62. case VT_INT: wprintf( L"%d", *(LONG *)pv ); break;
  63. case VT_UI8: wprintf( L"%I64u", *(unsigned __int64 *)pv ); break;
  64. case VT_I8: wprintf( L"%I64d", *(__int64 *)pv ); break;
  65. case VT_R4: wprintf( L"%f", *(float *)pv ); break;
  66. case VT_R8: wprintf( L"%lf", *(double *)pv ); break;
  67. case VT_DECIMAL:
  68. {
  69. double dbl;
  70. VarR8FromDec( (DECIMAL *) pv, &dbl );
  71. wprintf( L"%lf", dbl );
  72. break;
  73. }
  74. case VT_CY:
  75. {
  76. double dbl;
  77. VarR8FromCy( * (CY *) pv, &dbl );
  78. wprintf( L"%lf", dbl );
  79. break;
  80. }
  81. case VT_BOOL: wprintf( *(VARIANT_BOOL *)pv ? L"TRUE" : L"FALSE" ); break;
  82. case VT_BSTR: wprintf( L"%ws", *(BSTR *) pv ); break;
  83. case VT_VARIANT:
  84. {
  85. PROPVARIANT * pVar = (PROPVARIANT *) pv;
  86. Render( pVar->vt, & pVar->lVal );
  87. break;
  88. }
  89. case VT_DATE:
  90. {
  91. SYSTEMTIME st;
  92. VariantTimeToSystemTime( *(DATE *)pv, &st );
  93. BOOL pm = st.wHour >= 12;
  94. if ( st.wHour > 12 )
  95. st.wHour -= 12;
  96. else if ( 0 == st.wHour )
  97. st.wHour = 12;
  98. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  99. (DWORD) st.wMonth,
  100. (DWORD) st.wDay,
  101. (DWORD) st.wYear,
  102. (DWORD) st.wHour,
  103. (DWORD) st.wMinute,
  104. pm ? L'p' : L'a' );
  105. break;
  106. }
  107. case VT_EMPTY:
  108. case VT_NULL:
  109. break;
  110. default :
  111. {
  112. wprintf( L"(vt 0x%x)", (int) vt );
  113. break;
  114. }
  115. }
  116. } //Render
  117. //+-------------------------------------------------------------------------
  118. //
  119. // Function: PrintSafeArray
  120. //
  121. // Synopsis: Prints items in a safearray
  122. //
  123. // Arguments: [vt] - type of elements in the safearray
  124. // [pa] - pointer to the safearray
  125. //
  126. //--------------------------------------------------------------------------
  127. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa )
  128. {
  129. // Get the dimensions of the array
  130. UINT cDim = SafeArrayGetDim( pa );
  131. if ( 0 == cDim )
  132. return;
  133. XPtr<LONG> xDim( cDim );
  134. XPtr<LONG> xLo( cDim );
  135. XPtr<LONG> xUp( cDim );
  136. for ( UINT iDim = 0; iDim < cDim; iDim++ )
  137. {
  138. HRESULT hr = SafeArrayGetLBound( pa, iDim + 1, &xLo[iDim] );
  139. if ( FAILED( hr ) )
  140. return;
  141. xDim[ iDim ] = xLo[ iDim ];
  142. hr = SafeArrayGetUBound( pa, iDim + 1, &xUp[iDim] );
  143. if ( FAILED( hr ) )
  144. return;
  145. wprintf( L"{" );
  146. }
  147. // slog through the array
  148. UINT iLastDim = cDim - 1;
  149. BOOL fDone = FALSE;
  150. while ( !fDone )
  151. {
  152. // inter-element formatting
  153. if ( xDim[ iLastDim ] != xLo[ iLastDim ] )
  154. wprintf( L"," );
  155. // Get the element and render it
  156. void *pv;
  157. SafeArrayPtrOfIndex( pa, xDim.Get(), &pv );
  158. Render( vt, pv );
  159. // Move to the next element and carry if necessary
  160. ULONG cOpen = 0;
  161. for ( LONG iDim = iLastDim; iDim >= 0; iDim-- )
  162. {
  163. if ( xDim[ iDim ] < xUp[ iDim ] )
  164. {
  165. xDim[ iDim ] = 1 + xDim[ iDim ];
  166. break;
  167. }
  168. wprintf( L"}" );
  169. if ( 0 == iDim )
  170. fDone = TRUE;
  171. else
  172. {
  173. cOpen++;
  174. xDim[ iDim ] = xLo[ iDim ];
  175. }
  176. }
  177. for ( ULONG i = 0; !fDone && i < cOpen; i++ )
  178. wprintf( L"{" );
  179. }
  180. } //PrintSafeArray
  181. //+-------------------------------------------------------------------------
  182. //
  183. // Function: PrintVectorItems
  184. //
  185. // Synopsis: Prints items in a PROPVARIANT vector
  186. //
  187. // Arguments: [pVal] - The array of values
  188. // [cVals] - The count of values
  189. // [pcFmt] - The format string
  190. //
  191. //--------------------------------------------------------------------------
  192. template<class T> void PrintVectorItems(
  193. T * pVal,
  194. ULONG cVals,
  195. char * pcFmt )
  196. {
  197. printf( "{ " );
  198. for( ULONG iVal = 0; iVal < cVals; iVal++ )
  199. {
  200. if ( 0 != iVal )
  201. printf( "," );
  202. printf( pcFmt, *pVal++ );
  203. }
  204. printf( " }" );
  205. } //PrintVectorItems
  206. //+-------------------------------------------------------------------------
  207. //
  208. // Function: DisplayValue
  209. //
  210. // Synopsis: Displays a PROPVARIANT value. Limited formatting is done.
  211. //
  212. // Arguments: [pVar] - The value to display
  213. //
  214. //--------------------------------------------------------------------------
  215. void DisplayValue( PROPVARIANT const * pVar )
  216. {
  217. if ( 0 == pVar )
  218. {
  219. wprintf( L"NULL" );
  220. return;
  221. }
  222. // Display the most typical variant types
  223. PROPVARIANT const & v = *pVar;
  224. switch ( v.vt )
  225. {
  226. case VT_EMPTY : wprintf( L"vt_empty" ); break;
  227. case VT_NULL : wprintf( L"vt_null" ); break;
  228. case VT_I4 : wprintf( L"%10d", v.lVal ); break;
  229. case VT_UI1 : wprintf( L"%10d", v.bVal ); break;
  230. case VT_I2 : wprintf( L"%10d", v.iVal ); break;
  231. case VT_R4 : wprintf( L"%10f", v.fltVal ); break;
  232. case VT_R8 : wprintf( L"%10lf", v.dblVal ); break;
  233. case VT_BOOL : wprintf( v.boolVal ? L"TRUE" : L"FALSE" ); break;
  234. case VT_I1 : wprintf( L"%10d", v.cVal ); break;
  235. case VT_UI2 : wprintf( L"%10u", v.uiVal ); break;
  236. case VT_UI4 : wprintf( L"%10u", v.ulVal ); break;
  237. case VT_INT : wprintf( L"%10d", v.lVal ); break;
  238. case VT_UINT : wprintf( L"%10u", v.ulVal ); break;
  239. case VT_I8 : wprintf( L"%20I64d", v.hVal ); break;
  240. case VT_UI8 : wprintf( L"%20I64u", v.hVal ); break;
  241. case VT_ERROR : wprintf( L"%#x", v.scode ); break;
  242. case VT_LPSTR : wprintf( L"%S", v.pszVal ); break;
  243. case VT_LPWSTR : wprintf( L"%ws", v.pwszVal ); break;
  244. case VT_BSTR : wprintf( L"%ws", v.bstrVal ); break;
  245. case VT_CY:
  246. {
  247. double dbl;
  248. VarR8FromCy( v.cyVal, &dbl );
  249. wprintf( L"%lf", dbl );
  250. break;
  251. }
  252. case VT_DECIMAL :
  253. {
  254. double dbl;
  255. VarR8FromDec( (DECIMAL *) &v.decVal, &dbl );
  256. wprintf( L"%lf", dbl );
  257. break;
  258. }
  259. case VT_FILETIME :
  260. case VT_DATE :
  261. {
  262. SYSTEMTIME st;
  263. if ( VT_DATE == v.vt )
  264. {
  265. VariantTimeToSystemTime( v.date, &st );
  266. }
  267. else
  268. {
  269. #if 0
  270. FILETIME ft;
  271. FileTimeToLocalFileTime( &v.filetime, &ft );
  272. FileTimeToSystemTime( &ft, &st );
  273. #else
  274. FileTimeToSystemTime( &v.filetime, &st );
  275. #endif
  276. }
  277. BOOL pm = st.wHour >= 12;
  278. if ( st.wHour > 12 )
  279. st.wHour -= 12;
  280. else if ( 0 == st.wHour )
  281. st.wHour = 12;
  282. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  283. (DWORD) st.wMonth,
  284. (DWORD) st.wDay,
  285. (DWORD) st.wYear,
  286. (DWORD) st.wHour,
  287. (DWORD) st.wMinute,
  288. pm ? L'p' : L'a' );
  289. break;
  290. }
  291. case VT_VECTOR | VT_I1:
  292. PrintVectorItems( v.cac.pElems, v.cac.cElems, "%d" ); break;
  293. case VT_VECTOR | VT_I2:
  294. PrintVectorItems( v.cai.pElems, v.cai.cElems, "%d" ); break;
  295. case VT_VECTOR | VT_I4:
  296. PrintVectorItems( v.cal.pElems, v.cal.cElems, "%d" ); break;
  297. case VT_VECTOR | VT_I8:
  298. PrintVectorItems( v.cah.pElems, v.cah.cElems, "%I64d" ); break;
  299. case VT_VECTOR | VT_UI1:
  300. PrintVectorItems( v.caub.pElems, v.caub.cElems, "%u" ); break;
  301. case VT_VECTOR | VT_UI2:
  302. PrintVectorItems( v.caui.pElems, v.caui.cElems, "%u" ); break;
  303. case VT_VECTOR | VT_UI4:
  304. PrintVectorItems( v.caul.pElems, v.caul.cElems, "%u" ); break;
  305. case VT_VECTOR | VT_ERROR:
  306. PrintVectorItems( v.cascode.pElems, v.cascode.cElems, "%#x" ); break;
  307. case VT_VECTOR | VT_UI8:
  308. PrintVectorItems( v.cauh.pElems, v.cauh.cElems, "%I64u" ); break;
  309. case VT_VECTOR | VT_BSTR:
  310. PrintVectorItems( v.cabstr.pElems, v.cabstr.cElems, "%ws" ); break;
  311. case VT_VECTOR | VT_LPSTR:
  312. PrintVectorItems( v.calpstr.pElems, v.calpstr.cElems, "%S" ); break;
  313. case VT_VECTOR | VT_LPWSTR:
  314. PrintVectorItems( v.calpwstr.pElems, v.calpwstr.cElems, "%ws" ); break;
  315. case VT_VECTOR | VT_R4:
  316. PrintVectorItems( v.caflt.pElems, v.caflt.cElems, "%f" ); break;
  317. case VT_VECTOR | VT_R8:
  318. PrintVectorItems( v.cadbl.pElems, v.cadbl.cElems, "%lf" ); break;
  319. default :
  320. {
  321. if ( VT_ARRAY & v.vt )
  322. PrintSafeArray( v.vt - VT_ARRAY, v.parray );
  323. else
  324. wprintf( L"vt 0x%05x", v.vt );
  325. break;
  326. }
  327. }
  328. } //DisplayValue
  329. void DumpProps(
  330. XInterface<IPropertySetStorage> & xPropSetStorage,
  331. BOOL fBonusProperties )
  332. {
  333. // Get enumerator for property set
  334. XInterface<IEnumSTATPROPSETSTG> xPropSetEnum;
  335. HRESULT hr = xPropSetStorage->Enum( xPropSetEnum.GetPPointer() );
  336. if ( FAILED( hr ) )
  337. {
  338. printf( "IPropertySetStorage::Enum failed: %#x\n", hr );
  339. exit( 1 );
  340. }
  341. STATPROPSETSTG propset;
  342. BOOL fUserProp = !fBonusProperties;
  343. while( ( (hr = xPropSetEnum->Next(1, &propset, NULL)) == S_OK ) ||
  344. !fUserProp)
  345. {
  346. GUID FormatID;
  347. if ( S_OK == hr )
  348. {
  349. FormatID = propset.fmtid;
  350. }
  351. else
  352. {
  353. FormatID = FMTID_UserDefinedProperties;
  354. fUserProp = TRUE;
  355. }
  356. XInterface<IPropertyStorage> xPropStorage;
  357. hr = xPropSetStorage->Open( FormatID,
  358. STGM_READ | STGM_SHARE_EXCLUSIVE,
  359. xPropStorage.GetPPointer() );
  360. if ( ( ( E_FAIL == hr ) || ( STG_E_FILENOTFOUND == hr ) ) &&
  361. ( FMTID_UserDefinedProperties == FormatID ) )
  362. {
  363. printf( "IPropertySetStorage::Open failed with %#x\n", hr );
  364. hr = S_OK;
  365. continue;
  366. }
  367. else if ( FAILED( hr ) )
  368. {
  369. printf( "IPropertySetStorage::Open failed badly with %#x\n", hr );
  370. exit( 1 );
  371. }
  372. printf( "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  373. FormatID.Data1,
  374. FormatID.Data2,
  375. FormatID.Data3,
  376. FormatID.Data4[0], FormatID.Data4[1],
  377. FormatID.Data4[2], FormatID.Data4[3],
  378. FormatID.Data4[4], FormatID.Data4[5],
  379. FormatID.Data4[6], FormatID.Data4[7] );
  380. XInterface<IEnumSTATPROPSTG> xEnumStatPropStg;
  381. // Get enumerator for property
  382. hr = xPropStorage->Enum( xEnumStatPropStg.GetPPointer() );
  383. if ( FAILED( hr ) )
  384. {
  385. printf( "IPropertyStorage::Enum failed %#x\n", hr );
  386. continue;
  387. }
  388. PROPVARIANT prop;
  389. PropVariantInit( &prop );
  390. // Get the locale for properties
  391. PROPSPEC ps;
  392. ps.ulKind = PRSPEC_PROPID;
  393. ps.propid = PID_LOCALE;
  394. hr = xPropStorage->ReadMultiple( 1,
  395. &ps,
  396. &prop );
  397. if ( SUCCEEDED( hr ) )
  398. {
  399. if ( VT_EMPTY == prop.vt )
  400. {
  401. printf( " no lcid, so using system default\n" );
  402. }
  403. else
  404. {
  405. printf( " locale: %d (%#x)\n", prop.ulVal, prop.ulVal );
  406. PropVariantClear(&prop);
  407. }
  408. }
  409. else
  410. {
  411. printf( " can't read the locale: %#x\n", hr );
  412. }
  413. // Get the code page for properties
  414. PROPSPEC psCodePage = { PRSPEC_PROPID, PID_CODEPAGE };
  415. hr = xPropStorage->ReadMultiple(1, &psCodePage, &prop);
  416. if ( SUCCEEDED( hr ) )
  417. {
  418. if(VT_I2 == prop.vt)
  419. printf( " codepage: %d (%#x)\n", (UINT)prop.uiVal, (UINT) prop.uiVal );
  420. else
  421. printf( " vt of codepage: %d (%#x)\n", prop.vt, prop.vt );
  422. PropVariantClear( &prop );
  423. }
  424. else
  425. {
  426. printf( " no codepage, assume ansi\n" );
  427. }
  428. // Enumerate all properties in the property set
  429. STATPROPSTG statPS;
  430. ULONG ul;
  431. if ( S_OK != hr )
  432. {
  433. hr = S_OK;
  434. }
  435. while ( ( S_OK == xEnumStatPropStg->Next( 1, &statPS, &ul ) ) &&
  436. ( 1 == ul ) &&
  437. ( SUCCEEDED( hr ) ) )
  438. {
  439. if ( 0 != statPS.lpwstrName )
  440. {
  441. printf( " name: '%ws', ", statPS.lpwstrName );
  442. ps.ulKind = PRSPEC_LPWSTR;
  443. ps.lpwstr = statPS.lpwstrName;
  444. }
  445. else
  446. {
  447. printf( " pid: %d (%#x), ", statPS.propid, statPS.propid );
  448. ps.ulKind = PRSPEC_PROPID;
  449. ps.propid = statPS.propid;
  450. }
  451. hr = xPropStorage->ReadMultiple( 1,
  452. &ps,
  453. &prop );
  454. if ( SUCCEEDED( hr ) )
  455. {
  456. if ( S_FALSE == hr )
  457. printf( "readmultiple returned S_FALSE!\n" );
  458. printf( "vt: %d (%#x), ", prop.vt, prop.vt );
  459. DisplayValue( &prop );
  460. printf( "\n" );
  461. PropVariantClear( &prop );
  462. }
  463. else
  464. {
  465. printf( " IPropertyStorage::ReadMultiple failed: %#x\n", hr );
  466. hr = S_OK;
  467. }
  468. }
  469. }
  470. } //DumpProps
  471. HRESULT BindToItemByName(
  472. WCHAR const * pszFile,
  473. REFIID riid,
  474. void ** ppv )
  475. {
  476. XInterface<IShellFolder> xDesktop;
  477. HRESULT hr = pShGetDesktopFolder( xDesktop.GetPPointer() );
  478. if ( SUCCEEDED( hr ) )
  479. {
  480. XInterface<IBindCtx> xBindCtx;
  481. hr = CreateBindCtx( 0, xBindCtx.GetPPointer() );
  482. if ( FAILED( hr ) )
  483. return hr;
  484. BIND_OPTS bo = {sizeof(bo), 0};
  485. bo.grfFlags = BIND_JUSTTESTEXISTENCE; // skip all junctions
  486. hr = xBindCtx->SetBindOptions( &bo );
  487. if ( FAILED( hr ) )
  488. return hr;
  489. LPITEMIDLIST pidl;
  490. // cast needed for bad interface def
  491. hr = xDesktop->ParseDisplayName( 0,
  492. xBindCtx.GetPointer(),
  493. (LPWSTR) pszFile,
  494. 0,
  495. &pidl,
  496. 0 );
  497. if ( SUCCEEDED( hr ) )
  498. {
  499. XInterface<IShellFolder> xSF;
  500. LPCITEMIDLIST pidlChild;
  501. hr = pShBindToParent( pidl,
  502. IID_IShellFolder,
  503. xSF.GetQIPointer(),
  504. &pidlChild );
  505. if (SUCCEEDED(hr))
  506. hr = xSF->BindToObject( pidlChild, 0, riid, ppv );
  507. else
  508. printf( "SHBindToParent failed: %#x\n", hr );
  509. CoTaskMemFree( pidl );
  510. }
  511. else
  512. {
  513. printf( "IShellFolder::ParseDisplayNamed failed %#x\n", hr );
  514. }
  515. }
  516. else
  517. {
  518. printf( "SHGetDesktopFolder failed: %#x\n", hr );
  519. }
  520. return hr;
  521. } //BindToItemByName
  522. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  523. {
  524. if ( 2 != argc && 3 != argc )
  525. Usage();
  526. BOOL fUseOLE = TRUE;
  527. if ( ( 3 == argc ) && !_wcsicmp( L"-s", argv[1] ) )
  528. fUseOLE = FALSE;
  529. WCHAR awcPath[MAX_PATH];
  530. _wfullpath( awcPath, argv[ (2 == argc) ? 1 : 2 ], MAX_PATH );
  531. HRESULT hr = CoInitialize( 0 );
  532. if ( FAILED( hr ) )
  533. {
  534. printf( "can't init com: %#x\n", hr );
  535. exit( 1 );
  536. }
  537. if ( fUseOLE )
  538. {
  539. BOOL fWindows2000Plus = FALSE;
  540. OSVERSIONINFOA ovi;
  541. ovi.dwOSVersionInfoSize = sizeof ovi;
  542. GetVersionExA( &ovi );
  543. if ( ( VER_PLATFORM_WIN32_NT == ovi.dwPlatformId ) &&
  544. ( ovi.dwMajorVersion >= 5 ) )
  545. fWindows2000Plus = TRUE;
  546. HINSTANCE h = LoadLibraryA( "ole32.dll" );
  547. if ( 0 == h )
  548. {
  549. printf( "can't load ole32.dll\n" );
  550. exit( 1 );
  551. }
  552. LPStgOpenStorageEx pOpen = (LPStgOpenStorageEx) GetProcAddress( h, "StgOpenStorageEx" );
  553. // Note: on some platforms closing the IStorage before finishing with
  554. // the IPropertySetStorage will result in the object going away. It's a bug
  555. // in OLE.
  556. XInterface<IStorage> xStorage;
  557. XInterface<IPropertySetStorage> xPropSetStorage;
  558. if ( fWindows2000Plus && 0 != pOpen )
  559. {
  560. HRESULT hr = pOpen( awcPath,
  561. STGM_DIRECT |
  562. STGM_READ |
  563. STGM_SHARE_DENY_WRITE,
  564. STGFMT_ANY,
  565. 0,
  566. 0,
  567. 0,
  568. IID_IPropertySetStorage,
  569. xPropSetStorage.GetQIPointer() );
  570. if ( FAILED( hr ) )
  571. {
  572. printf( "failed to openEx the file: %#x\n", hr );
  573. exit( 1 );
  574. }
  575. }
  576. else
  577. {
  578. HRESULT hr = StgOpenStorage( awcPath,
  579. 0,
  580. STGM_READ | STGM_SHARE_DENY_WRITE,
  581. 0,
  582. 0,
  583. xStorage.GetPPointer() );
  584. if ( FAILED( hr ) )
  585. {
  586. printf( "StgOpenStorage failed to open the file: %#x\n", hr );
  587. exit( 1 );
  588. }
  589. // Rely on iprop.dll on Win9x, since OLE32 doesn't have the code
  590. hr = StgCreatePropSetStg( xStorage.GetPointer(),
  591. 0,
  592. xPropSetStorage.GetPPointer() );
  593. if ( FAILED( hr ) )
  594. {
  595. printf( "StgCreatePropSetStg failed: %#x\n", hr );
  596. exit( 1 );
  597. }
  598. }
  599. DumpProps( xPropSetStorage, TRUE );
  600. FreeLibrary( h );
  601. }
  602. else
  603. {
  604. HINSTANCE h = LoadLibrary( L"shell32.dll" );
  605. if ( 0 == h )
  606. {
  607. printf( "can't load shell32.dll\n" );
  608. exit( 1 );
  609. }
  610. pShGetDesktopFolder = (PSHGetDesktopFolder) GetProcAddress( h, "SHGetDesktopFolder" );
  611. if ( 0 == pShGetDesktopFolder )
  612. {
  613. printf( "can't find SHGetDesktopFolder in shell32.dll\n" );
  614. exit( 1 );
  615. }
  616. pShBindToParent = (PSHBindToParent) GetProcAddress( h, "SHBindToParent" );
  617. if ( 0 == pShBindToParent )
  618. {
  619. printf( "can't find SHBindToParent in shell32.dll\n" );
  620. exit( 1 );
  621. }
  622. XInterface<IPropertySetStorage> xPropSetStorage;
  623. CLSID clsidPSS = IID_IPropertySetStorage;
  624. hr = BindToItemByName( awcPath,
  625. clsidPSS,
  626. xPropSetStorage.GetQIPointer() );
  627. if ( FAILED( hr ) )
  628. printf( "couldn't bind to item %ws by name: %#x\n", awcPath, hr );
  629. else
  630. DumpProps( xPropSetStorage, FALSE );
  631. FreeLibrary( h );
  632. }
  633. CoUninitialize();
  634. return 0;
  635. } //wmain