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.

3221 lines
93 KiB

  1. //+=================================================================
  2. //
  3. // File:
  4. // PropTest.cxx
  5. //
  6. // Description:
  7. // This file contains the main() and most supporting functions
  8. // for the PropTest command-line DRT. Run "PropTest /?" for
  9. // usage information.
  10. //
  11. //+=================================================================
  12. // tests to do:
  13. // IEnumSTATPROPSTG
  14. // Create some properties, named and id'd
  15. // Enumerate them and check
  16. // (check vt, lpwstrName, propid)
  17. // (check when asking for more than there is: S_FALSE, S_OK)
  18. // Delete one
  19. // Reset the enumerator
  20. // Enumerate them and check
  21. // Delete one
  22. //
  23. // Reset the enumeratorA
  24. // Read one from enumeratorA
  25. // Clone enumerator -> enumeratorB
  26. // Loop comparing rest of enumerator contents
  27. //
  28. // Reset the enumerator
  29. // Skip all
  30. // Check none left
  31. //
  32. // Reset the enumerator
  33. // Skip all but one
  34. // Check one left
  35. //
  36. // Check refcounting and IUnknown
  37. //
  38. // IPropertyStorage tests
  39. //
  40. // Multiple readers/writers access tests
  41. //
  42. //+----------------------------------------------------------------------------
  43. //
  44. // I n c l u d e s
  45. //
  46. //+----------------------------------------------------------------------------
  47. #include "pch.cxx" // Brings in most other includes/defines/etc.
  48. #include "propstm.hxx"
  49. #include "propstg.hxx"
  50. //#include <memory.h> //
  51. //+----------------------------------------------------------------------------
  52. //
  53. // G l o b a l s
  54. //
  55. //+----------------------------------------------------------------------------
  56. OLECHAR g_aocMap[CCH_MAP + 1] = OLESTR("abcdefghijklmnopqrstuvwxyz012345");
  57. // Special-case property set names
  58. const OLECHAR oszSummaryInformation[] = OLESTR("\005SummaryInformation");
  59. ULONG cboszSummaryInformation = sizeof(oszSummaryInformation);
  60. const OLECHAR oszDocSummaryInformation[] = OLESTR("\005DocumentSummaryInformation");
  61. ULONG cboszDocSummaryInformation = sizeof(oszDocSummaryInformation);
  62. const OLECHAR oszGlobalInfo[] = OLESTR("\005Global Info");
  63. ULONG cboszGlobalInfo = sizeof(oszGlobalInfo);
  64. const OLECHAR oszImageContents[] = OLESTR("\005Image Contents");
  65. ULONG cboszImageContents = sizeof(oszImageContents);
  66. const OLECHAR oszImageInfo[] = OLESTR("\005Image Info");
  67. ULONG cboszImageInfo = sizeof(oszImageInfo);
  68. // Enumeration indicating how to get an IPropertySetStorage
  69. EnumImplementation g_enumImplementation = PROPIMP_UNKNOWN;
  70. DWORD g_Restrictions;
  71. BOOL g_fRegisterLocalServer = TRUE;
  72. BOOL g_fUseNt5PropsDll = FALSE;
  73. // Property Set APIs (which may be in OLE32.dll or IProp.dll)
  74. HINSTANCE g_hinstDLL = NULL;
  75. FNSTGCREATEPROPSTG *g_pfnStgCreatePropStg = NULL;
  76. FNSTGOPENPROPSTG *g_pfnStgOpenPropStg = NULL;
  77. FNSTGCREATEPROPSETSTG *g_pfnStgCreatePropSetStg = NULL;
  78. FNFMTIDTOPROPSTGNAME *g_pfnFmtIdToPropStgName = NULL;
  79. FNPROPSTGNAMETOFMTID *g_pfnPropStgNameToFmtId = NULL;
  80. FNPROPVARIANTCLEAR *g_pfnPropVariantClear = NULL;
  81. FNPROPVARIANTCOPY *g_pfnPropVariantCopy = NULL;
  82. FNFREEPROPVARIANTARRAY *g_pfnFreePropVariantArray = NULL;
  83. FNSTGCREATESTORAGEEX *g_pfnStgCreateStorageEx = NULL;
  84. FNSTGOPENSTORAGEEX *g_pfnStgOpenStorageEx = NULL;
  85. FNSTGOPENSTORAGEONHANDLE *g_pfnStgOpenStorageOnHandle = NULL;
  86. FNSTGCREATESTORAGEONHANDLE *g_pfnStgCreateStorageOnHandle = NULL;
  87. FNSTGPROPERTYLENGTHASVARIANT *g_pfnStgPropertyLengthAsVariant = NULL;
  88. FNSTGCONVERTVARIANTTOPROPERTY *g_pfnStgConvertVariantToProperty = NULL;
  89. FNSTGCONVERTPROPERTYTOVARIANT *g_pfnStgConvertPropertyToVariant = NULL;
  90. // PictureIt! Format IDs
  91. const FMTID fmtidGlobalInfo =
  92. { 0x56616F00,
  93. 0xC154, 0x11ce,
  94. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  95. const FMTID fmtidImageContents =
  96. { 0x56616400,
  97. 0xC154, 0x11ce,
  98. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  99. const FMTID fmtidImageInfo =
  100. { 0x56616500,
  101. 0xC154, 0x11ce,
  102. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  103. BOOL g_fOFS;
  104. LARGE_INTEGER g_li0;
  105. CPropVariant g_rgcpropvarAll[ CPROPERTIES_ALL ];
  106. CPropSpec g_rgcpropspecAll[ CPROPERTIES_ALL ];
  107. const OLECHAR* g_rgoszpropnameAll[ CPROPERTIES_ALL ];
  108. char g_szPropHeader[] = " propid/name propid cb type value\n";
  109. char g_szEmpty[] = "";
  110. BOOL g_fVerbose = FALSE;
  111. BOOL g_stgmDumpFlags = 0;
  112. // This flag indicates whether or not the run-time system supports
  113. // IPropertySetStorage on the DocFile IStorage object.
  114. BOOL g_fQIPropertySetStorage = FALSE;
  115. // g_curUuid is used by UuidCreate(). Everycall to that function
  116. // returns the current value of g_curUuid, and increments the DWORD
  117. // field.
  118. GUID g_curUuid =
  119. { /* e4ecf7f0-e587-11cf-b10d-00aa005749e9 */
  120. 0xe4ecf7f0,
  121. 0xe587,
  122. 0x11cf,
  123. {0xb1, 0x0d, 0x00, 0xaa, 0x00, 0x57, 0x49, 0xe9}
  124. };
  125. // Instantiate an object for the Marshaling tests
  126. #ifndef _MAC_NODOC
  127. CPropStgMarshalTest g_cpsmt;
  128. #endif
  129. // On the Mac, instantiate a CDisplay object, which is used
  130. // by these tests to write to the screen (see #define PRINTF).
  131. #ifdef _MAC
  132. CDisplay *g_pcDisplay;
  133. #endif
  134. // System information
  135. SYSTEMINFO g_SystemInfo;
  136. int g_nIndent = 0;
  137. void Status( char* szMessage )
  138. {
  139. for( int i = 0; i < g_nIndent; i++ )
  140. PRINTF( " " );
  141. if( g_fVerbose )
  142. PRINTF( szMessage );
  143. else
  144. PRINTF( "." );
  145. } // STATUS()
  146. //+----------------------------------------------------------------------------
  147. //
  148. // Function: IsOriginalPropVariantType
  149. //
  150. // Determines if a VARTYPE was one of the ones in the original PropVariant
  151. // definition (as defined in the OLE2 spec and shipped with NT4/DCOM95).
  152. //
  153. //+----------------------------------------------------------------------------
  154. // *** Duped from props\utils.cxx ***
  155. BOOL
  156. IsOriginalPropVariantType( VARTYPE vt )
  157. {
  158. if( vt & ~VT_TYPEMASK & ~VT_VECTOR )
  159. return( FALSE );
  160. switch( vt )
  161. {
  162. case VT_EMPTY:
  163. case VT_NULL:
  164. case VT_UI1:
  165. case VT_I2:
  166. case VT_UI2:
  167. case VT_BOOL:
  168. case VT_I4:
  169. case VT_UI4:
  170. case VT_R4:
  171. case VT_ERROR:
  172. case VT_I8:
  173. case VT_UI8:
  174. case VT_R8:
  175. case VT_CY:
  176. case VT_DATE:
  177. case VT_FILETIME:
  178. case VT_CLSID:
  179. case VT_BLOB:
  180. case VT_BLOB_OBJECT:
  181. case VT_CF:
  182. case VT_STREAM:
  183. case VT_STREAMED_OBJECT:
  184. case VT_STORAGE:
  185. case VT_STORED_OBJECT:
  186. case VT_BSTR:
  187. case VT_LPSTR:
  188. case VT_LPWSTR:
  189. case VT_UI1|VT_VECTOR:
  190. case VT_I2|VT_VECTOR:
  191. case VT_UI2|VT_VECTOR:
  192. case VT_BOOL|VT_VECTOR:
  193. case VT_I4|VT_VECTOR:
  194. case VT_UI4|VT_VECTOR:
  195. case VT_R4|VT_VECTOR:
  196. case VT_ERROR|VT_VECTOR:
  197. case VT_I8|VT_VECTOR:
  198. case VT_UI8|VT_VECTOR:
  199. case VT_R8|VT_VECTOR:
  200. case VT_CY|VT_VECTOR:
  201. case VT_DATE|VT_VECTOR:
  202. case VT_FILETIME|VT_VECTOR:
  203. case VT_CLSID|VT_VECTOR:
  204. case VT_CF|VT_VECTOR:
  205. case VT_BSTR|VT_VECTOR:
  206. case VT_BSTR_BLOB|VT_VECTOR:
  207. case VT_LPSTR|VT_VECTOR:
  208. case VT_LPWSTR|VT_VECTOR:
  209. case VT_VARIANT|VT_VECTOR:
  210. return( TRUE );
  211. }
  212. return( FALSE );
  213. }
  214. //+=================================================================
  215. //
  216. // Function: _Check
  217. //
  218. // Synopsis: Verify that the actual HR is the expected
  219. // value. If not, report an error and exit.
  220. //
  221. // Inputs: [HRESULT] hrExpected
  222. // What we expected
  223. // [HRESULT] hrActual
  224. // The actual HR of the previous operation.
  225. // [int] line
  226. // The line number of the operation.
  227. //
  228. // Outputs: None.
  229. //
  230. //+=================================================================
  231. void _Check(HRESULT hrExpected, HRESULT hrActual, LPCSTR szFile, int line)
  232. {
  233. if (hrExpected != hrActual)
  234. {
  235. PRINTF("\nFailed with hr=%08x at line %d\n"
  236. "in \"%s\"\n"
  237. "(expected hr=%08x, GetLastError=%lu)\n",
  238. hrActual, line, szFile, hrExpected, GetLastError() );
  239. // On NT, we simply exit here. On the Mac, where PropTest is a function rather
  240. // than a main(), we throw an exception so that the test may terminate somewhat
  241. // cleanly.
  242. #ifdef _MAC
  243. throw CHRESULT( hrActual, OLESTR("Fatal Error") );
  244. #else
  245. if( IsDebuggerPresent() )
  246. DebugBreak();
  247. exit(1);
  248. #endif
  249. }
  250. }
  251. OLECHAR * GetNextTest()
  252. {
  253. static int nTest;
  254. static OLECHAR ocsBuf[10];
  255. soprintf(ocsBuf, OLESTR("%d"), nTest++);
  256. return(ocsBuf);
  257. }
  258. VOID
  259. CalcSafeArrayIndices( LONG iLinear, LONG rgIndices[], const SAFEARRAYBOUND rgsaBounds[], ULONG cDims )
  260. {
  261. for( long i = 0; i < static_cast<long>(cDims) - 1; i++ )
  262. {
  263. LONG lProduct = rgsaBounds[cDims-1].cElements;
  264. for( int j = cDims-2; j > i; j-- )
  265. lProduct *= rgsaBounds[j].cElements;
  266. rgIndices[ i ] = rgsaBounds[i].lLbound + (iLinear / lProduct);
  267. iLinear %= lProduct;
  268. }
  269. rgIndices[ cDims-1 ] = rgsaBounds[cDims-1].lLbound + (iLinear % rgsaBounds[cDims-1].cElements);
  270. }
  271. ULONG
  272. CalcSafeArrayElementCount( const SAFEARRAY *psa )
  273. {
  274. ULONG cElems = 1;
  275. ULONG cDims = SafeArrayGetDim( const_cast<SAFEARRAY*>(psa) );
  276. for( ULONG i = 1; i <= cDims; i++ )
  277. {
  278. LONG lUpperBound = 0, lLowerBound = 0;
  279. Check( S_OK, SafeArrayGetLBound( const_cast<SAFEARRAY*>(psa), i, &lLowerBound ));
  280. Check( S_OK, SafeArrayGetUBound( const_cast<SAFEARRAY*>(psa), i, &lUpperBound ));
  281. cElems *= lUpperBound - lLowerBound + 1;
  282. }
  283. return( cElems );
  284. }
  285. VOID
  286. CompareSafeArrays( SAFEARRAY *psa1, SAFEARRAY *psa2 )
  287. {
  288. VARTYPE vt1, vt2;
  289. UINT cDims1, cDims2;
  290. UINT i;
  291. UINT cElems = 0;
  292. SAFEARRAYBOUND *rgsaBounds = NULL;
  293. LONG *rgIndices = NULL;
  294. Check( S_OK, SafeArrayGetVartype( psa1, &vt1 ));
  295. Check( S_OK, SafeArrayGetVartype( psa2, &vt2 ));
  296. Check( vt1, vt2 );
  297. cDims1 = SafeArrayGetDim( psa1 );
  298. cDims2 = SafeArrayGetDim( psa2 );
  299. Check( cDims1, cDims2 );
  300. Check( 0, memcmp( psa1->rgsabound, psa2->rgsabound, cDims1 * sizeof(SAFEARRAYBOUND) ));
  301. Check( psa1->fFeatures, psa2->fFeatures );
  302. Check( psa1->cbElements, psa2->cbElements );
  303. cElems = CalcSafeArrayElementCount( psa1 );
  304. switch( vt1 )
  305. {
  306. case VT_I1:
  307. case VT_UI1:
  308. case VT_I2:
  309. case VT_UI2:
  310. case VT_I4:
  311. case VT_UI4:
  312. case VT_INT:
  313. case VT_UINT:
  314. case VT_ERROR:
  315. case VT_BOOL:
  316. case VT_R4:
  317. case VT_R8:
  318. case VT_I8:
  319. case VT_UI8:
  320. Check( 0, memcmp( psa1->pvData, psa2->pvData, cDims1 * psa1->cbElements ));
  321. break;
  322. case VT_BSTR:
  323. rgsaBounds = new SAFEARRAYBOUND[ cDims1 ];
  324. Check( FALSE, NULL == rgsaBounds );
  325. rgIndices = new LONG[ cDims1 ];
  326. Check( FALSE, NULL == rgIndices );
  327. // The Bounds are stored in the safearray in reversed order. Correct them so
  328. // that we can use CalcSafeArrayIndices
  329. for( i = 0; i < cDims1; i++ )
  330. rgsaBounds[i] = psa1->rgsabound[ cDims1-1-i ];
  331. for( i = 0; i < cElems; i++ )
  332. {
  333. BSTR *pbstr1 = NULL, *pbstr2 = NULL;
  334. CalcSafeArrayIndices( i, rgIndices, rgsaBounds, cDims1 );
  335. Check( S_OK, SafeArrayPtrOfIndex( psa1, rgIndices, reinterpret_cast<void**>(&pbstr1) ));
  336. Check( S_OK, SafeArrayPtrOfIndex( psa2, rgIndices, reinterpret_cast<void**>(&pbstr2) ));
  337. Check( *(reinterpret_cast<ULONG*>(*pbstr1)-1), *(reinterpret_cast<ULONG*>(*pbstr2)-1) );
  338. Check( 0, ocscmp( *pbstr1, *pbstr2 ));
  339. }
  340. break;
  341. case VT_VARIANT:
  342. rgsaBounds = new SAFEARRAYBOUND[ cDims1 ];
  343. Check( FALSE, NULL == rgsaBounds );
  344. rgIndices = new LONG[ cDims1 ];
  345. Check( FALSE, NULL == rgIndices );
  346. // The Bounds are stored in the safearray in reversed order. Correct them so
  347. // that we can use CalcSafeArrayIndices
  348. for( i = 0; i < cDims1; i++ )
  349. rgsaBounds[i] = psa1->rgsabound[ cDims1-1-i ];
  350. for( i = 0; i < cElems; i++ )
  351. {
  352. CPropVariant *pcpropvar1 = NULL, *pcpropvar2 = NULL;
  353. CalcSafeArrayIndices( i, rgIndices, rgsaBounds, cDims1 );
  354. Check( S_OK, SafeArrayPtrOfIndex( psa1, rgIndices, reinterpret_cast<void**>(&pcpropvar1) ));
  355. Check( S_OK, SafeArrayPtrOfIndex( psa2, rgIndices, reinterpret_cast<void**>(&pcpropvar2) ));
  356. Check( TRUE, *pcpropvar1 == *pcpropvar2 );
  357. }
  358. break;
  359. default:
  360. Check( FALSE, TRUE );
  361. } // switch( vt1 )
  362. delete[] rgIndices;
  363. delete[] rgsaBounds;
  364. }
  365. #ifndef _MAC // SYSTEMTIME isn't supported on the Mac.
  366. void Now(FILETIME *pftNow)
  367. {
  368. SYSTEMTIME stStart;
  369. GetSystemTime(&stStart);
  370. SystemTimeToFileTime(&stStart, pftNow);
  371. }
  372. #endif
  373. IStorage *_pstgTemp = NULL;
  374. IStorage *_pstgTempCopyTo = NULL; // _pstgTemp is copied to _pstgTempCopyTo
  375. unsigned int CTempStorage::_iName;
  376. PROPVARIANT * CGenProps::GetNext(int HowMany, int *pActual, BOOL fWrapOk, BOOL fNoNonSimple)
  377. {
  378. PROPVARIANT *pVar = new PROPVARIANT[HowMany];
  379. if (pVar == NULL)
  380. return(NULL);
  381. for (int l=0; l<HowMany && _GetNext(pVar + l, fWrapOk, fNoNonSimple); l++) { };
  382. if (pActual)
  383. *pActual = l;
  384. if (l == 0)
  385. {
  386. delete pVar;
  387. return(NULL);
  388. }
  389. return(pVar);
  390. }
  391. BOOL CGenProps::_GetNext(PROPVARIANT *pVar, BOOL fWrapOk, BOOL fNoNonSimple)
  392. {
  393. if (_vt == (VT_VECTOR | VT_CLSID)+1)
  394. {
  395. if (!fWrapOk)
  396. return(FALSE);
  397. else
  398. _vt = (VARENUM)2;
  399. }
  400. PROPVARIANT Var;
  401. BOOL fFirst = TRUE;
  402. do
  403. {
  404. GUID *pg;
  405. if (!fFirst)
  406. {
  407. g_pfnPropVariantClear(&Var);
  408. }
  409. fFirst = FALSE;
  410. memset(&Var, 0, sizeof(Var));
  411. Var.vt = _vt;
  412. (*((int*)&_vt))++;
  413. switch (Var.vt)
  414. {
  415. case VT_LPSTR:
  416. Var.pszVal = new CHAR[ 6 ];
  417. strcpy(Var.pszVal, "lpstr");
  418. break;
  419. case VT_LPWSTR:
  420. Var.pwszVal = new WCHAR[ 7 ];
  421. wcscpy(Var.pwszVal, L"lpwstr");
  422. break;
  423. case VT_CLSID:
  424. pg = new GUID;
  425. UuidCreate(pg);
  426. Var.puuid = pg;
  427. break;
  428. case VT_CF:
  429. Var.pclipdata = new CLIPDATA;
  430. Var.pclipdata->cbSize = 10;
  431. Var.pclipdata->pClipData = new BYTE[ 10 ];
  432. Var.pclipdata->ulClipFmt = 0;
  433. break;
  434. case VT_VERSIONED_STREAM:
  435. Var.pVersionedStream = new VERSIONEDSTREAM;
  436. UuidCreate( &Var.pVersionedStream->guidVersion );
  437. Var.pVersionedStream->pStream = NULL;
  438. break;
  439. }
  440. } while ( (fNoNonSimple && (Var.vt == VT_STREAM || Var.vt == VT_STREAMED_OBJECT ||
  441. Var.vt == VT_STORAGE || Var.vt == VT_STORED_OBJECT || Var.vt == VT_VERSIONED_STREAM)
  442. )
  443. ||
  444. !IsOriginalPropVariantType(Var.vt) );
  445. g_pfnPropVariantCopy(pVar, &Var);
  446. g_pfnPropVariantClear(&Var);
  447. return(TRUE);
  448. }
  449. VOID
  450. CleanStat(ULONG celt, STATPROPSTG *psps)
  451. {
  452. while (celt--)
  453. {
  454. delete [] psps->lpwstrName;
  455. psps++;
  456. }
  457. }
  458. //+----------------------------------------------------------------------------
  459. //
  460. // Function: PopulateRGPropVar
  461. //
  462. // Synopsis: This function fills an input array of PROPVARIANTs
  463. // with an assortment of properties.
  464. //
  465. // Note: For compatibility with the marshaling test, all
  466. // non-simple properties must be at the end of the array.
  467. //
  468. //+----------------------------------------------------------------------------
  469. HRESULT
  470. PopulateRGPropVar( CPropVariant rgcpropvar[],
  471. CPropSpec rgcpropspec[],
  472. const OLECHAR *rgoszpropname[],
  473. IStorage *pstg )
  474. {
  475. HRESULT hr = (HRESULT) E_FAIL;
  476. int i;
  477. ULONG ulPropIndex = 0;
  478. CLIPDATA clipdataNull = {0, 0, NULL}, clipdataNonNull = {0, 0, NULL};
  479. CClipData cclipdataEmpty;
  480. cclipdataEmpty.Set( (ULONG) -1, "", 0 );
  481. // Initialize the PropVariants
  482. for( i = 0; i < CPROPERTIES_ALL; i++ )
  483. {
  484. rgcpropvar[i].Clear();
  485. }
  486. /*
  487. // Create a I1 property
  488. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "I1 Property" );
  489. rgcpropvar[ulPropIndex] = (CHAR) 38;
  490. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_I1 );
  491. ulPropIndex++;
  492. // Create a vector of I1s
  493. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "Vector|I1 Property" );
  494. rgcpropvar[ulPropIndex][1] = (CHAR) 22;
  495. rgcpropvar[ulPropIndex][0] = (CHAR) 23;
  496. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_VECTOR|VT_I1) );
  497. ulPropIndex++;
  498. */
  499. // Create a UI1 property
  500. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "UI1 Property" );
  501. rgcpropvar[ulPropIndex] = (UCHAR) 39;
  502. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_UI1 );
  503. ulPropIndex++;
  504. // Create an I2 property
  505. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "I2 Property" );
  506. rgcpropvar[ulPropIndex] = (short) -502;
  507. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_I2 );
  508. ulPropIndex++;
  509. // Create a UI2 property
  510. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "UI2 Property" );
  511. rgcpropvar[ulPropIndex] = (USHORT) 502;
  512. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_UI2 );
  513. ulPropIndex++;
  514. // Create a BOOL property
  515. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "Bool Property" );
  516. rgcpropvar[ulPropIndex].SetBOOL( VARIANT_TRUE );
  517. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_BOOL );
  518. ulPropIndex++;
  519. // Create a I4 property
  520. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "I4 Property" );
  521. rgcpropvar[ulPropIndex] = (long) -523;
  522. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_I4 );
  523. ulPropIndex++;
  524. // Create a UI4 property
  525. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "UI4 Property" );
  526. rgcpropvar[ulPropIndex] = (ULONG) 530;
  527. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_UI4 );
  528. ulPropIndex++;
  529. // Create a R4 property
  530. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "R4 Property" );
  531. rgcpropvar[ulPropIndex] = (float) 5.37;
  532. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_R4 );
  533. ulPropIndex++;
  534. // Create an ERROR property
  535. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "ERROR Property" );
  536. rgcpropvar[ulPropIndex].SetERROR( STG_E_FILENOTFOUND );
  537. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_ERROR );
  538. ulPropIndex++;
  539. // Create an I8 property
  540. LARGE_INTEGER large_integer;
  541. large_integer.LowPart = 551;
  542. large_integer.HighPart = 30;
  543. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "I8 Property" );
  544. rgcpropvar[ulPropIndex] = large_integer;
  545. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_I8 );
  546. ulPropIndex++;
  547. // Create a UI8 property
  548. ULARGE_INTEGER ularge_integer;
  549. ularge_integer.LowPart = 561;
  550. ularge_integer.HighPart = 30;
  551. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "UI8 Property" );
  552. rgcpropvar[ulPropIndex] = ularge_integer;
  553. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_UI8 );
  554. ulPropIndex++;
  555. // Create an R8 property
  556. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "R8 Property" );
  557. rgcpropvar[ulPropIndex] = (double) 571.36;
  558. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_R8 );
  559. ulPropIndex++;
  560. // Create a CY property
  561. CY cy;
  562. cy.Hi = 123;
  563. cy.Lo = 456;
  564. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "Cy Property" );
  565. rgcpropvar[ulPropIndex] = cy;
  566. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_CY );
  567. ulPropIndex++;
  568. // Create a DATE property
  569. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "DATE Property" );
  570. rgcpropvar[ulPropIndex].SetDATE( 587 );
  571. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_DATE );
  572. ulPropIndex++;
  573. // Create a FILETIME property
  574. FILETIME filetime;
  575. filetime.dwLowDateTime = 0x767c0570;
  576. filetime.dwHighDateTime = 0x1bb7ecf;
  577. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "FILETIME Property" );
  578. rgcpropvar[ulPropIndex] = filetime;
  579. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_FILETIME );
  580. ulPropIndex++;
  581. // Create a CLSID property
  582. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "CLSID Property" );
  583. rgcpropvar[ulPropIndex] = FMTID_SummaryInformation;
  584. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_CLSID );
  585. ulPropIndex++;
  586. // Create a vector of CLSIDs
  587. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR( "CLSID Vector Property" );
  588. rgcpropvar[ulPropIndex][0] = FMTID_SummaryInformation;
  589. rgcpropvar[ulPropIndex][1] = FMTID_DocSummaryInformation;
  590. rgcpropvar[ulPropIndex][2] = FMTID_UserDefinedProperties;
  591. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_CLSID | VT_VECTOR) );
  592. ulPropIndex++;
  593. // Create a BSTR property
  594. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("BSTR");
  595. rgcpropvar[ulPropIndex].SetBSTR( OLESTR("BSTR Value") );
  596. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_BSTR );
  597. ulPropIndex++;
  598. // Create a BSTR Vector property
  599. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("BSTR Vector");
  600. for( i = 0; i < 3; i++ )
  601. {
  602. OLECHAR olestrElement[] = OLESTR("# - BSTR Vector Element");
  603. olestrElement[0] = (OLECHAR) i%10 + OLESTR('0');
  604. rgcpropvar[ulPropIndex].SetBSTR( olestrElement, i );
  605. }
  606. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_BSTR | VT_VECTOR) );
  607. ulPropIndex++;
  608. // Create a variant vector BSTR property.
  609. rgcpropspec[ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("BSTR Variant Vector");
  610. for( i = 0; i < 3; i++ )
  611. {
  612. if( i == 0 )
  613. {
  614. rgcpropvar[ulPropIndex][0] = (PROPVARIANT) CPropVariant((long) 0x1234);
  615. }
  616. else
  617. {
  618. CPropVariant cpropvarBSTR;
  619. cpropvarBSTR.SetBSTR( OLESTR("# - Vector Variant BSTR") );
  620. (cpropvarBSTR.GetBSTR())[0] = (OLECHAR) i%10 + OLESTR('0');
  621. rgcpropvar[ulPropIndex][i] = (PROPVARIANT) cpropvarBSTR;
  622. }
  623. }
  624. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_VARIANT | VT_VECTOR) );
  625. ulPropIndex++;
  626. // Create an LPSTR property
  627. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("LPSTR Property");
  628. rgcpropvar[ulPropIndex] = "LPSTR Value";
  629. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_LPSTR );
  630. ulPropIndex++;
  631. // Create some ClipFormat properties
  632. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("ClipFormat property");
  633. rgcpropvar[ ulPropIndex ] = CClipData( L"Clipboard Data" );
  634. Check(TRUE, rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  635. ulPropIndex++;
  636. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("Empty ClipFormat property (NULL pointer)");
  637. clipdataNull.cbSize = 4;
  638. clipdataNull.ulClipFmt = (ULONG) -1;
  639. clipdataNull.pClipData = NULL;
  640. rgcpropvar[ ulPropIndex ] = clipdataNull;
  641. Check(TRUE, rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  642. ulPropIndex++;
  643. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("Empty ClipFormat property (non-NULL pointer)");
  644. clipdataNonNull.cbSize = 4;
  645. clipdataNonNull.ulClipFmt = (ULONG) -1;
  646. clipdataNonNull.pClipData = new BYTE[ 0 ];
  647. rgcpropvar[ ulPropIndex ] = clipdataNonNull;
  648. Check(TRUE, rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  649. ulPropIndex++;
  650. // Create a vector of ClipFormat properties
  651. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("ClipFormat Array Property");
  652. rgcpropvar[ ulPropIndex ][0] = CClipData( L"Clipboard Date element 1" );
  653. rgcpropvar[ ulPropIndex ][1] = cclipdataEmpty;
  654. rgcpropvar[ ulPropIndex ][2] = clipdataNull;
  655. rgcpropvar[ ulPropIndex ][3] = clipdataNonNull;
  656. rgcpropvar[ ulPropIndex ][4] = CClipData( L"Clipboard Date element 2" );
  657. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_CF | VT_VECTOR) );
  658. Check(TRUE, rgcpropvar[ulPropIndex].Count() == 5 );
  659. ulPropIndex++;
  660. // Create an LPSTR|Vector property (e.g., the DocSumInfo
  661. // Document Parts array).
  662. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("LPSTR|Vector property");
  663. rgcpropvar[ ulPropIndex ][0] = "LPSTR Element 0";
  664. rgcpropvar[ ulPropIndex ][1] = "LPSTR Element 1";
  665. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_LPSTR | VT_VECTOR) );
  666. ulPropIndex++;
  667. // Create an LPWSTR|Vector property
  668. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("LPWSTR|Vector property");
  669. rgcpropvar[ ulPropIndex ][0] = L"LPWSTR Element 0";
  670. rgcpropvar[ ulPropIndex ][1] = L"LPWSTR Element 1";
  671. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_LPWSTR | VT_VECTOR) );
  672. ulPropIndex++;
  673. // Create a DocSumInfo HeadingPairs array.
  674. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("HeadingPair array");
  675. rgcpropvar[ ulPropIndex ][0] = (PROPVARIANT) CPropVariant( "Heading 0" );
  676. rgcpropvar[ ulPropIndex ][1] = (PROPVARIANT) CPropVariant( (long) 1 );
  677. rgcpropvar[ ulPropIndex ][2] = (PROPVARIANT) CPropVariant( "Heading 1" );
  678. rgcpropvar[ ulPropIndex ][3] = (PROPVARIANT) CPropVariant( (long) 1 );
  679. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_VARIANT | VT_VECTOR) );
  680. ulPropIndex++;
  681. // Create some NULL (but extant) properties
  682. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("Empty LPSTR");
  683. rgcpropvar[ulPropIndex] = "";
  684. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_LPSTR );
  685. ulPropIndex++;
  686. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("Empty LPWSTR");
  687. rgcpropvar[ulPropIndex] = L"";
  688. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_LPWSTR );
  689. ulPropIndex++;
  690. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("Empty BLOB");
  691. rgcpropvar[ulPropIndex] = CBlob(0);
  692. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_BLOB );
  693. ulPropIndex++;
  694. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("Empty BSTR");
  695. rgcpropvar[ulPropIndex].SetBSTR( OLESTR("") );
  696. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_BSTR );
  697. ulPropIndex++;
  698. // Create some NULL (and non-extant) properties
  699. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("NULL BSTR");
  700. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->vt = VT_BSTR;
  701. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->bstrVal = NULL;
  702. ulPropIndex++;
  703. // ***
  704. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("NULL LPSTR");
  705. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->vt = VT_LPSTR;
  706. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->pszVal = NULL;
  707. ulPropIndex++;
  708. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("NULL LPWSTR");
  709. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->vt = VT_LPWSTR;
  710. ((PROPVARIANT*)&rgcpropvar[ulPropIndex])->pwszVal = NULL;
  711. ulPropIndex++;
  712. // ***
  713. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("BSTR Vector with NULL element");
  714. rgcpropvar[ulPropIndex].SetBSTR( NULL, 0 );
  715. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == (VT_VECTOR | VT_BSTR) );
  716. ulPropIndex++;
  717. /*
  718. rgcpropspec[ulPropIndex] = rgoszpropname[ulPropIndex] = OLESTR("LPSTR Vector with NULL element");
  719. rgcpropvar[ulPropIndex].SetLPSTR( NULL, 0 );
  720. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_VECTOR | VT_LPSTR );
  721. ulPropIndex++;
  722. */
  723. if( !(g_Restrictions & RESTRICT_SIMPLE_ONLY) )
  724. {
  725. // Create an IStream property
  726. IStream *pstmProperty = NULL;
  727. CheckLockCount( pstg, 0 );
  728. Check(S_OK, pstg->CreateStream( OLESTR("Stream Property"),
  729. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  730. 0L, 0L,
  731. &pstmProperty ));
  732. CheckLockCount( pstg, 0 );
  733. Check(S_OK, pstmProperty->Write("Hi There", 9, NULL ));
  734. Check(S_OK, pstmProperty->Seek( CLargeInteger(0), STREAM_SEEK_SET, NULL ));
  735. CheckLockCount( pstmProperty, 0 );
  736. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("Stream Property");
  737. rgcpropvar[ ulPropIndex ] = pstmProperty;
  738. pstmProperty->Release();
  739. pstmProperty = NULL;
  740. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_STREAM );
  741. ulPropIndex++;
  742. // Create a VersionedStream property
  743. VERSIONEDSTREAM VersionedStreamProperty;
  744. UuidCreate( &VersionedStreamProperty.guidVersion );
  745. Check(S_OK, pstg->CreateStream( OLESTR("Versioned Stream Property"),
  746. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  747. 0L, 0L,
  748. &VersionedStreamProperty.pStream ));
  749. Check(S_OK, VersionedStreamProperty.pStream->Write("Hi There, version", 9, NULL ));
  750. Check(S_OK, VersionedStreamProperty.pStream->Seek( CLargeInteger(0), STREAM_SEEK_SET, NULL ));
  751. rgcpropspec[ ulPropIndex ] = rgoszpropname[ ulPropIndex ] = OLESTR("Versioned Stream Property");
  752. rgcpropvar[ ulPropIndex ] = VersionedStreamProperty;
  753. RELEASE_INTERFACE( VersionedStreamProperty.pStream );
  754. Check( TRUE, rgcpropvar[ulPropIndex].VarType() == VT_VERSIONED_STREAM );
  755. ulPropIndex++;
  756. // Create an IStorage property
  757. IStorage *pstgProperty = NULL;
  758. Check(S_OK, StgCreateDocfile(NULL, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DELETEONRELEASE,
  759. 0, &pstgProperty ));
  760. rgcpropspec[ ulPropIndex ] = rgoszpropname[ulPropIndex] = OLESTR("Storage Property");
  761. rgcpropvar[ ulPropIndex ] = pstgProperty;
  762. pstgProperty->Release();
  763. pstgProperty = NULL;
  764. Check(TRUE, rgcpropvar[ulPropIndex].VarType() == VT_STORAGE );
  765. ulPropIndex++;
  766. }
  767. // ----
  768. // Exit
  769. // ----
  770. delete [] clipdataNonNull.pClipData;
  771. memset( &clipdataNonNull, 0, sizeof(clipdataNonNull) );
  772. Check(TRUE, CPROPERTIES_ALL >= ulPropIndex );
  773. hr = S_OK;
  774. return(hr);
  775. }
  776. HRESULT
  777. ResetRGPropVar( CPropVariant rgcpropvar[] )
  778. {
  779. HRESULT hr = S_OK;
  780. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  781. {
  782. IStream *pstm = NULL;
  783. if( VT_STREAM == rgcpropvar[i].VarType()
  784. ||
  785. VT_STREAMED_OBJECT == rgcpropvar[i].VarType() )
  786. {
  787. pstm = rgcpropvar[i].GetSTREAM();
  788. }
  789. else if( VT_VERSIONED_STREAM == rgcpropvar[i].VarType() )
  790. {
  791. pstm = rgcpropvar[i].GetVERSIONEDSTREAM().pStream;
  792. }
  793. if( NULL != pstm )
  794. {
  795. hr = pstm->Seek( CLargeInteger(0), STREAM_SEEK_SET, NULL );
  796. if( FAILED(hr) ) goto Exit;
  797. }
  798. }
  799. Exit:
  800. return( hr) ;
  801. }
  802. void
  803. CheckFormatVersion( IPropertyStorage *ppropstg, WORD wExpected )
  804. {
  805. HRESULT hr = S_OK;
  806. NTSTATUS status;
  807. WORD wActual;
  808. IStorageTest *ptest = NULL;
  809. hr = ppropstg->QueryInterface( IID_IStorageTest, reinterpret_cast<void**>(&ptest) );
  810. if( SUCCEEDED(hr) )
  811. {
  812. Check( S_OK, ptest->GetFormatVersion(&wActual) );
  813. Check( wExpected, wActual );
  814. RELEASE_INTERFACE(ptest);
  815. }
  816. return;
  817. }
  818. void
  819. CheckLockCount( IUnknown *punk, LONG lExpected )
  820. {
  821. IStorageTest *ptest = NULL;
  822. HRESULT hr = S_OK;
  823. hr = punk->QueryInterface( IID_IStorageTest, reinterpret_cast<void**>(&ptest) );
  824. if( SUCCEEDED(hr) )
  825. Check( lExpected, ptest->GetLockCount() );
  826. RELEASE_INTERFACE(ptest);
  827. return;
  828. }
  829. FILETIME operator - ( const FILETIME &ft1, const FILETIME &ft2 )
  830. {
  831. FILETIME ftDiff;
  832. if( ft1 < ft2 )
  833. {
  834. ftDiff.dwLowDateTime = 0;
  835. ftDiff.dwHighDateTime = 0;
  836. }
  837. else if( ft1.dwLowDateTime >= ft2.dwLowDateTime )
  838. {
  839. ftDiff.dwLowDateTime = ft1.dwLowDateTime - ft2.dwLowDateTime;
  840. ftDiff.dwHighDateTime = ft1.dwHighDateTime - ft2.dwHighDateTime;
  841. }
  842. else
  843. {
  844. ftDiff.dwLowDateTime = ft1.dwLowDateTime - ft2.dwLowDateTime;
  845. ftDiff.dwLowDateTime = (DWORD) -1 - ftDiff.dwLowDateTime;
  846. ftDiff.dwHighDateTime = ft1.dwHighDateTime - ft2.dwHighDateTime - 1;
  847. }
  848. return( ftDiff );
  849. }
  850. FILETIME operator -= ( FILETIME &ft1, const FILETIME &ft2 )
  851. {
  852. ft1 = ft1 - ft2;
  853. return( ft1 );
  854. }
  855. void CheckTime(const FILETIME &ftStart, const FILETIME &ftPropSet)
  856. {
  857. FILETIME ftNow;
  858. CoFileTimeNow(&ftNow);
  859. if (ftPropSet.dwLowDateTime == 0 && ftPropSet.dwHighDateTime == 0)
  860. {
  861. return;
  862. }
  863. // if ftPropSet < ftStart || ftNow < ftPropSet, error
  864. Check(TRUE, ftStart <= ftPropSet && ftPropSet <= ftNow );
  865. }
  866. void
  867. CheckStat( IPropertyStorage *pPropSet, REFFMTID fmtid,
  868. REFCLSID clsid, ULONG PropSetFlag,
  869. const FILETIME & ftStart, DWORD dwOSVersion )
  870. {
  871. STATPROPSETSTG StatPropSetStg;
  872. Check(S_OK, pPropSet->Stat(&StatPropSetStg));
  873. Check(TRUE, StatPropSetStg.fmtid == fmtid);
  874. Check(TRUE, StatPropSetStg.clsid == clsid);
  875. Check(TRUE, StatPropSetStg.grfFlags == PropSetFlag);
  876. Check(TRUE, StatPropSetStg.dwOSVersion == dwOSVersion);
  877. CheckTime(ftStart, StatPropSetStg.mtime);
  878. CheckTime(ftStart, StatPropSetStg.ctime);
  879. CheckTime(ftStart, StatPropSetStg.atime);
  880. }
  881. BOOL
  882. IsEqualSTATPROPSTG(const STATPROPSTG *p1, const STATPROPSTG *p2)
  883. {
  884. BOOL f1 = p1->propid == p2->propid;
  885. BOOL f2 = p1->vt == p2->vt;
  886. BOOL f3 = (p1->lpwstrName == NULL && p2->lpwstrName == NULL) ||
  887. ((p1->lpwstrName != NULL && p2->lpwstrName != NULL) &&
  888. ocscmp(p1->lpwstrName, p2->lpwstrName) == 0);
  889. return(f1 && f2 && f3);
  890. }
  891. void
  892. CreateCodePageTestFile( LPOLESTR poszFileName, IStorage **ppStg )
  893. {
  894. Check(TRUE, poszFileName != NULL );
  895. // --------------
  896. // Initialization
  897. // --------------
  898. TSafeStorage< IPropertySetStorage > pPSStg;
  899. TSafeStorage< IPropertyStorage > pPStg;
  900. PROPSPEC propspec;
  901. CPropVariant cpropvar;
  902. *ppStg = NULL;
  903. // Create the Docfile.
  904. Check(S_OK, g_pfnStgCreateStorageEx( poszFileName,
  905. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  906. DetermineStgFmt( g_enumImplementation ),
  907. 0, NULL, NULL,
  908. DetermineStgIID( g_enumImplementation ),
  909. reinterpret_cast<void**>(ppStg) ));
  910. // Get an IPropertySetStorage
  911. Check(S_OK, StgToPropSetStg( *ppStg, &pPSStg ));
  912. // Create an IPropertyStorage
  913. Check(S_OK, pPSStg->Create( FMTID_NULL,
  914. NULL,
  915. PROPSETFLAG_ANSI,
  916. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  917. &pPStg ));
  918. // ----------------------
  919. // Write a named property
  920. // ----------------------
  921. // Write a named I4 property
  922. propspec.ulKind = PRSPEC_LPWSTR;
  923. propspec.lpwstr = CODEPAGE_TEST_NAMED_PROPERTY;
  924. cpropvar = (LONG) 0x12345678;
  925. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  926. // --------------------------
  927. // Write singleton properties
  928. // --------------------------
  929. // Write an un-named BSTR.
  930. propspec.ulKind = PRSPEC_PROPID;
  931. propspec.propid = CODEPAGE_TEST_UNNAMED_BSTR_PROPID;
  932. cpropvar.SetBSTR( OLESTR("BSTR Property") );
  933. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  934. // Write an un-named I4
  935. propspec.ulKind = PRSPEC_PROPID;
  936. propspec.propid = CODEPAGE_TEST_UNNAMED_I4_PROPID;
  937. cpropvar = (LONG) 0x76543210;
  938. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  939. // -----------------------
  940. // Write vector properties
  941. // -----------------------
  942. // Write a vector of BSTRs.
  943. propspec.ulKind = PRSPEC_PROPID;
  944. propspec.propid = CODEPAGE_TEST_VBSTR_PROPID;
  945. cpropvar.SetBSTR( OLESTR("BSTR Element 1"), 1 );
  946. cpropvar.SetBSTR( OLESTR("BSTR Element 0"), 0 );
  947. Check(TRUE, (VT_VECTOR | VT_BSTR) == cpropvar.VarType() );
  948. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  949. // -------------------------------
  950. // Write Variant Vector Properties
  951. // -------------------------------
  952. // Write a variant vector that has a BSTR
  953. propspec.ulKind = PRSPEC_PROPID;
  954. propspec.propid = CODEPAGE_TEST_VPROPVAR_BSTR_PROPID;
  955. CPropVariant cpropvarT;
  956. cpropvarT.SetBSTR( OLESTR("PropVar Vector BSTR") );
  957. cpropvar[1] = (PROPVARIANT) cpropvarT;
  958. cpropvar[0] = (PROPVARIANT) CPropVariant((long) 44);
  959. Check(TRUE, (VT_VARIANT | VT_VECTOR) == cpropvar.VarType() );
  960. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  961. } // CreateCodePageTestFile()
  962. void
  963. ModifyPropSetCodePage( IStorage *pStg, const FMTID &fmtid, USHORT usCodePage )
  964. {
  965. Check(TRUE, pStg != NULL );
  966. // --------------
  967. // Initialization
  968. // --------------
  969. OLECHAR aocPropSetName[ 32 ];
  970. DWORD dwVT;
  971. ULONG cbWritten = 0;
  972. TSafeStorage< IStream > pStm;
  973. CPropVariant cpropvar;
  974. // Open the Stream
  975. RtlGuidToPropertySetName( &fmtid, aocPropSetName );
  976. Check(S_OK, pStg->OpenStream( aocPropSetName,
  977. NULL,
  978. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  979. NULL,
  980. &pStm ));
  981. // Seek to the codepage property
  982. SeekToProperty( pStm, PID_CODEPAGE );
  983. // Move past the VT
  984. Check(S_OK, pStm->Read( &dwVT, sizeof(DWORD), NULL ));
  985. // Write the new code page.
  986. PropByteSwap( &usCodePage );
  987. Check(S_OK, pStm->Write( &usCodePage, sizeof(usCodePage), &cbWritten ));
  988. Check(TRUE, cbWritten == sizeof(usCodePage) );
  989. } // ModifyPropSetCodePage()
  990. void
  991. ModifyPropertyType( IStorage *pStg, const FMTID &fmtid, PROPID propid, VARTYPE vt )
  992. {
  993. Check(TRUE, pStg != NULL );
  994. // --------------
  995. // Initialization
  996. // --------------
  997. OLECHAR aocPropSetName[ 32 ];
  998. DWORD dwVT;
  999. ULONG cbWritten = 0;
  1000. TSafeStorage< IStream > pStm;
  1001. CPropVariant cpropvar;
  1002. // Open the Stream
  1003. RtlGuidToPropertySetName( &fmtid, aocPropSetName );
  1004. Check(S_OK, pStg->OpenStream( aocPropSetName,
  1005. NULL,
  1006. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1007. NULL,
  1008. &pStm ));
  1009. // Seek to the property
  1010. SeekToProperty( pStm, propid );
  1011. // Write the new VT
  1012. PropByteSwap( &vt );
  1013. Check(S_OK, pStm->Write( &vt, sizeof(DWORD), &cbWritten ));
  1014. Check(TRUE, cbWritten == sizeof(DWORD) );
  1015. } // ModifyPropertyType()
  1016. void
  1017. SeekToProperty( IStream *pStm, PROPID propidSearch )
  1018. {
  1019. // --------------
  1020. // Initialization
  1021. // --------------
  1022. OLECHAR aocPropSetName[ 32 ];
  1023. DWORD dwOffset = 0;
  1024. DWORD dwcbSection = 0;
  1025. DWORD dwcProperties = 0;
  1026. ULONG ulcbWritten = 0;
  1027. LARGE_INTEGER liSectionOffset, liCodePageOffset;
  1028. CPropVariant cpropvar;
  1029. // Seek past the propset header and the format ID.
  1030. liSectionOffset.HighPart = 0;
  1031. liSectionOffset.LowPart = sizeof(PROPERTYSETHEADER) + sizeof(FMTID);
  1032. Check(S_OK, pStm->Seek(liSectionOffset, STREAM_SEEK_SET, NULL ));
  1033. // Move to the beginning of the property set.
  1034. liSectionOffset.HighPart = 0;
  1035. Check(S_OK, pStm->Read( &liSectionOffset.LowPart, sizeof(DWORD), NULL ));
  1036. PropByteSwap(&liSectionOffset.LowPart);
  1037. Check(S_OK, pStm->Seek( liSectionOffset, STREAM_SEEK_SET, NULL ));
  1038. // Get the section size & property count.
  1039. Check(S_OK, pStm->Read( &dwcbSection, sizeof(DWORD), NULL ));
  1040. PropByteSwap( &dwcbSection );
  1041. Check(S_OK, pStm->Read( &dwcProperties, sizeof(DWORD), NULL ));
  1042. PropByteSwap( &dwcProperties );
  1043. // Scan for the property.
  1044. for( ULONG ulIndex = 0; ulIndex < dwcProperties; ulIndex++ )
  1045. {
  1046. PROPID propid;
  1047. // Read in the PROPID
  1048. Check(S_OK, pStm->Read( &propid, sizeof(PROPID), NULL ));
  1049. // Read in this PROPIDs offset (we may not need it, but we want
  1050. // to seek past it.
  1051. Check(S_OK, pStm->Read( &dwOffset, sizeof(dwOffset), NULL ));
  1052. PropByteSwap(dwOffset);
  1053. // Is it the one we're looking for?
  1054. if( PropByteSwap(propid) == propidSearch )
  1055. break;
  1056. }
  1057. // Verify that the above for loop terminated because we found
  1058. // the codepage.
  1059. Check( TRUE, ulIndex < dwcProperties );
  1060. // Move to the property.
  1061. liSectionOffset.LowPart += dwOffset;
  1062. Check(S_OK, pStm->Seek( liSectionOffset, STREAM_SEEK_SET, NULL ));
  1063. return;
  1064. } // SeekToProperty()
  1065. void
  1066. ModifyOSVersion( IStorage* pStg, DWORD dwOSVersion )
  1067. {
  1068. Check(TRUE, pStg != NULL );
  1069. // --------------
  1070. // Initialization
  1071. // --------------
  1072. OLECHAR aocPropSetName[ 32 ];
  1073. ULONG ulcbWritten = 0;
  1074. LARGE_INTEGER liOffset;
  1075. TSafeStorage< IStream > pStm;
  1076. // Open the Stream
  1077. RtlGuidToPropertySetName( &FMTID_NULL, aocPropSetName );
  1078. Check(S_OK, pStg->OpenStream( aocPropSetName,
  1079. NULL,
  1080. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1081. NULL,
  1082. &pStm ));
  1083. // Seek to the OS Version field in the header.
  1084. liOffset.HighPart = 0;
  1085. liOffset.LowPart = sizeof(WORD) /*(byte-order)*/ + sizeof(WORD) /*(format)*/ ;
  1086. Check(S_OK, pStm->Seek( liOffset, STREAM_SEEK_SET, NULL ));
  1087. // Set the new OS Version
  1088. PropByteSwap( &dwOSVersion );
  1089. Check(S_OK, pStm->Write( &dwOSVersion, sizeof(dwOSVersion), &ulcbWritten ));
  1090. Check(TRUE, ulcbWritten == sizeof(dwOSVersion) );
  1091. } // ModifyOSVersion()
  1092. //+---------------------------------------------------------
  1093. //
  1094. // Function: MungePropertyStorage
  1095. //
  1096. // Synopsis: This routine munges the properties in a
  1097. // Property Storage. The values of the properties
  1098. // remain the same, but the underlying serialization
  1099. // is new (the properties are read, the property
  1100. // storage is deleted, and the properties are
  1101. // re-written).
  1102. //
  1103. // Inputs: [IPropertySetStorage*] ppropsetgstg (in)
  1104. // The Property Storage container.
  1105. // [FMTID] fmtid
  1106. // The Property Storage to munge.
  1107. //
  1108. // Returns: None.
  1109. //
  1110. // Note: Property names in the dictionary for which
  1111. // there is no property are not munged.
  1112. //
  1113. //+---------------------------------------------------------
  1114. #define MUNGE_PROPVARIANT_STEP 10
  1115. void
  1116. MungePropertyStorage( IPropertySetStorage *ppropsetstg,
  1117. FMTID fmtid )
  1118. {
  1119. // ------
  1120. // Locals
  1121. // ------
  1122. HRESULT hr;
  1123. ULONG celt, ulIndex;
  1124. TSafeStorage< IPropertyStorage > ppropstg;
  1125. IEnumSTATPROPSTG *penumstatpropstg;
  1126. PROPVARIANT *rgpropvar = NULL;
  1127. STATPROPSTG *rgstatpropstg = NULL;
  1128. ULONG cProperties = 0;
  1129. // Allocate an array of PropVariants. We may grow this later.
  1130. rgpropvar = new PROPVARIANT[ MUNGE_PROPVARIANT_STEP ];
  1131. Check( FALSE, NULL == rgpropvar );
  1132. // Allocate an array of STATPROPSTGs. We may grow this also.
  1133. rgstatpropstg = new STATPROPSTG[ MUNGE_PROPVARIANT_STEP ];
  1134. Check( FALSE, NULL == rgstatpropstg );
  1135. // -----------------
  1136. // Get an Enumerator
  1137. // -----------------
  1138. // Open the Property Storage. We may get an error if we're attempting
  1139. // the UserDefined propset. If it's file-not-found, then simply return,
  1140. // it's not an error, and there's nothing to do.
  1141. hr = ppropsetstg->Open( fmtid,
  1142. STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1143. &ppropstg );
  1144. if( FMTID_UserDefinedProperties == fmtid
  1145. &&
  1146. (HRESULT) STG_E_FILENOTFOUND == hr )
  1147. {
  1148. goto Exit;
  1149. }
  1150. Check( S_OK, hr );
  1151. // Get an Enumerator
  1152. Check(S_OK, ppropstg->Enum( &penumstatpropstg ));
  1153. // --------------------------------------------
  1154. // Read & delete in all of the properties/names
  1155. // --------------------------------------------
  1156. // Get the first property from the enumerator
  1157. hr = penumstatpropstg->Next( 1, &rgstatpropstg[cProperties], &celt );
  1158. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1159. // Iterate through the properties.
  1160. while( celt > 0 )
  1161. {
  1162. PROPSPEC propspec;
  1163. propspec.ulKind = PRSPEC_PROPID;
  1164. propspec.propid = rgstatpropstg[cProperties].propid;
  1165. // Read and delete the property
  1166. Check(S_OK, ppropstg->ReadMultiple( 1, &propspec, &rgpropvar[cProperties] ));
  1167. Check(S_OK, ppropstg->DeleteMultiple( 1, &propspec ));
  1168. // If there is a property name, delete it also.
  1169. if( NULL != rgstatpropstg[cProperties].lpwstrName )
  1170. {
  1171. // We have a name.
  1172. Check(S_OK, ppropstg->DeletePropertyNames( 1, &rgstatpropstg[cProperties].propid ));
  1173. }
  1174. // Increment the property count.
  1175. cProperties++;
  1176. // Do we need to grow the arrays?
  1177. if( 0 != cProperties
  1178. &&
  1179. (cProperties % MUNGE_PROPVARIANT_STEP) == 0 )
  1180. {
  1181. // Yes - they must be reallocated.
  1182. rgpropvar = (PROPVARIANT*)
  1183. CoTaskMemRealloc( rgpropvar,
  1184. ( (cProperties + MUNGE_PROPVARIANT_STEP)
  1185. *
  1186. sizeof(*rgpropvar)
  1187. ));
  1188. Check( FALSE, NULL == rgpropvar );
  1189. rgstatpropstg = (STATPROPSTG*)
  1190. CoTaskMemRealloc( rgstatpropstg,
  1191. ( (cProperties + MUNGE_PROPVARIANT_STEP)
  1192. *
  1193. sizeof(*rgstatpropstg)
  1194. ));
  1195. Check( FALSE, NULL == rgstatpropstg );
  1196. }
  1197. // Move on to the next property.
  1198. hr = penumstatpropstg->Next( 1, &rgstatpropstg[cProperties], &celt );
  1199. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1200. } // while( celt > 0 )
  1201. // -------------------------------------
  1202. // Write the properties & names back out
  1203. // -------------------------------------
  1204. for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  1205. {
  1206. // Write the property.
  1207. PROPSPEC propspec;
  1208. propspec.ulKind = PRSPEC_PROPID;
  1209. propspec.propid = rgstatpropstg[ ulIndex ].propid;
  1210. Check(S_OK, ppropstg->WriteMultiple(1, &propspec, &rgpropvar[ulIndex], PID_FIRST_USABLE ));
  1211. // If this property has a name, write it too.
  1212. if( rgstatpropstg[ ulIndex ].lpwstrName != NULL )
  1213. {
  1214. Check(S_OK, ppropstg->WritePropertyNames(
  1215. 1,
  1216. &rgstatpropstg[ulIndex].propid,
  1217. &rgstatpropstg[ulIndex].lpwstrName ));
  1218. }
  1219. } // for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  1220. // ----
  1221. // Exit
  1222. // ----
  1223. Exit:
  1224. if( penumstatpropstg )
  1225. {
  1226. penumstatpropstg->Release();
  1227. penumstatpropstg = NULL;
  1228. }
  1229. // Free the PropVariants
  1230. if( rgpropvar )
  1231. {
  1232. g_pfnFreePropVariantArray( cProperties, rgpropvar );
  1233. delete [] rgpropvar;
  1234. }
  1235. // Free the property names
  1236. if( rgstatpropstg )
  1237. {
  1238. for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  1239. {
  1240. if( NULL != rgstatpropstg[ ulIndex ].lpwstrName )
  1241. {
  1242. delete [] rgstatpropstg[ ulIndex ].lpwstrName;
  1243. }
  1244. } // for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  1245. delete [] rgstatpropstg;
  1246. }
  1247. } // MungePropertyStorage
  1248. //+---------------------------------------------------------
  1249. //
  1250. // Function: MungeStorage
  1251. //
  1252. // Synopsis: This routine munges the property sets in a
  1253. // Storage. The properties themselves are not
  1254. // modified, but the serialized bytes are.
  1255. // For each property set, all the properties are
  1256. // read, the property set is deleted, and
  1257. // the properties are re-written.
  1258. //
  1259. // Inputs: [IStorage*] pstg (in)
  1260. // The Storage to munge.
  1261. //
  1262. // Returns: None.
  1263. //
  1264. // Note: This routine only munges simple property
  1265. // sets.
  1266. //
  1267. //+---------------------------------------------------------
  1268. void
  1269. MungeStorage( IStorage *pstg )
  1270. {
  1271. // ------
  1272. // Locals
  1273. // ------
  1274. HRESULT hr;
  1275. ULONG celt;
  1276. STATPROPSETSTG statpropsetstg;
  1277. STATSTG statstg;
  1278. TSafeStorage< IPropertySetStorage > ppropsetstg;
  1279. TSafeStorage< IPropertyStorage > ppropstg;
  1280. IEnumSTATPROPSETSTG *penumstatpropsetstg;
  1281. IEnumSTATSTG *penumstatstg;
  1282. // -----------------------------------------------
  1283. // Munge each of the property sets in this Storage
  1284. // -----------------------------------------------
  1285. // Get the IPropertySetStorage interface
  1286. Check(S_OK, StgToPropSetStg( pstg, &ppropsetstg ));
  1287. // Get a property storage enumerator
  1288. Check(S_OK, ppropsetstg->Enum( &penumstatpropsetstg ));
  1289. // Get the first STATPROPSETSTG
  1290. hr = penumstatpropsetstg->Next( 1, &statpropsetstg, &celt );
  1291. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1292. // Loop through the STATPROPSETSTGs.
  1293. while( celt > 0 )
  1294. {
  1295. // Is this a simple property storage (we don't
  1296. // handle non-simple sets)?
  1297. if( !(statpropsetstg.grfFlags & PROPSETFLAG_NONSIMPLE) )
  1298. {
  1299. // Munge the Property Storage.
  1300. MungePropertyStorage( ppropsetstg, statpropsetstg.fmtid );
  1301. }
  1302. // Get the next STATPROPSETSTG
  1303. // If we just did the first section of the DocSumInfo
  1304. // property set, then attempt the second section.
  1305. if( FMTID_DocSummaryInformation == statpropsetstg.fmtid )
  1306. {
  1307. statpropsetstg.fmtid = FMTID_UserDefinedProperties;
  1308. }
  1309. else
  1310. {
  1311. hr = penumstatpropsetstg->Next( 1, &statpropsetstg, &celt );
  1312. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1313. }
  1314. }
  1315. // We're done with the Property Storage enumerator.
  1316. penumstatpropsetstg->Release();
  1317. penumstatpropsetstg = NULL;
  1318. // ------------------------------------------
  1319. // Recursively munge each of the sub-storages
  1320. // ------------------------------------------
  1321. // Get the IEnumSTATSTG enumerator
  1322. Check(S_OK, pstg->EnumElements( 0L, NULL, 0L, &penumstatstg ));
  1323. // Get the first STATSTG structure.
  1324. hr = penumstatstg->Next( 1, &statstg, &celt );
  1325. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1326. // Loop through the elements of this Storage.
  1327. while( celt > 0 )
  1328. {
  1329. // Is this a sub-Storage which must be
  1330. // munged?
  1331. if( STGTY_STORAGE & statstg.type // This is a Storage
  1332. &&
  1333. 0x20 <= *statstg.pwcsName ) // But not a system Storage.
  1334. {
  1335. // We'll munge it.
  1336. IStorage *psubstg;
  1337. // Open the sub-storage.
  1338. Check(S_OK, pstg->OpenStorage( statstg.pwcsName,
  1339. NULL,
  1340. STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1341. NULL,
  1342. 0L,
  1343. &psubstg ));
  1344. // Munge the sub-storage.
  1345. MungeStorage( psubstg );
  1346. psubstg->Release();
  1347. psubstg = NULL;
  1348. }
  1349. delete [] statstg.pwcsName;
  1350. statstg.pwcsName = NULL;
  1351. // Move on to the next Storage element.
  1352. hr = penumstatstg->Next( 1, &statstg, &celt );
  1353. Check( TRUE, (HRESULT) S_OK == hr || (HRESULT) S_FALSE == hr );
  1354. }
  1355. penumstatstg->Release();
  1356. penumstatstg = NULL;
  1357. } // MungeStorage
  1358. //+----------------------------------------------------------------------------
  1359. //+----------------------------------------------------------------------------
  1360. CLSID CObjectWithPersistStorage::_clsid = { /* 01c0652e-c97c-11d1-b2a8-00c04fb9386d */
  1361. 0x01c0652e,
  1362. 0xc97c,
  1363. 0x11d1,
  1364. {0xb2, 0xa8, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d}
  1365. };
  1366. CObjectWithPersistStorage::CObjectWithPersistStorage()
  1367. {
  1368. _poszData = NULL;
  1369. _cRefs = 1;
  1370. _fDirty = FALSE;
  1371. }
  1372. CObjectWithPersistStorage::CObjectWithPersistStorage( const OLECHAR *posz )
  1373. {
  1374. new(this) CObjectWithPersistStorage;
  1375. _poszData = new OLECHAR[ ocslen(posz) + 1 ];
  1376. Check( TRUE, NULL != _poszData );
  1377. ocscpy( _poszData, posz );
  1378. _fDirty = TRUE;
  1379. }
  1380. CObjectWithPersistStorage::~CObjectWithPersistStorage()
  1381. {
  1382. delete[] _poszData;
  1383. }
  1384. ULONG
  1385. CObjectWithPersistStorage::AddRef()
  1386. {
  1387. ULONG cRefs = InterlockedIncrement( &_cRefs );
  1388. return( cRefs );
  1389. }
  1390. ULONG
  1391. CObjectWithPersistStorage::Release()
  1392. {
  1393. ULONG cRefs = InterlockedDecrement( &_cRefs );
  1394. if( 0 == cRefs )
  1395. delete this;
  1396. return( cRefs );
  1397. }
  1398. HRESULT
  1399. CObjectWithPersistStorage::QueryInterface( REFIID iid, void **ppvObject )
  1400. {
  1401. if( IID_IPersistStorage == iid || IID_IUnknown == iid )
  1402. {
  1403. *ppvObject = static_cast<IPersistStorage*>(this);
  1404. AddRef();
  1405. return( S_OK );
  1406. }
  1407. else
  1408. return( E_NOINTERFACE );
  1409. }
  1410. HRESULT
  1411. CObjectWithPersistStorage::GetClassID( CLSID *pclsid )
  1412. {
  1413. *pclsid = GetClassID();
  1414. return( S_OK );
  1415. }
  1416. HRESULT
  1417. CObjectWithPersistStorage::IsDirty( void)
  1418. {
  1419. return( _fDirty );
  1420. }
  1421. HRESULT
  1422. CObjectWithPersistStorage::InitNew(
  1423. /* [unique][in] */ IStorage __RPC_FAR *pStg)
  1424. {
  1425. return( E_NOTIMPL );
  1426. }
  1427. HRESULT
  1428. CObjectWithPersistStorage::Load(
  1429. /* [unique][in] */ IStorage __RPC_FAR *pStg)
  1430. {
  1431. IStream *pStm = NULL;
  1432. ULONG cbRead;
  1433. Check( S_OK, pStg->OpenStream( OLESTR("CObjectWithPersistStorage"), NULL,
  1434. STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  1435. _poszData = new OLECHAR[ MAX_PATH ];
  1436. Check( TRUE, NULL != _poszData );
  1437. Check( S_OK, pStm->Read( _poszData, sizeof(OLECHAR)*MAX_PATH, &cbRead ));
  1438. _poszData[ MAX_PATH-1 ] = OLESTR('\0');
  1439. Check( 0, RELEASE_INTERFACE( pStm ));
  1440. return( S_OK );
  1441. }
  1442. HRESULT
  1443. CObjectWithPersistStorage::Save(
  1444. /* [unique][in] */ IStorage __RPC_FAR *pStgSave,
  1445. /* [in] */ BOOL fSameAsLoad)
  1446. {
  1447. IStream *pStm = NULL;
  1448. ULONG cbData, cbWritten;
  1449. Check( S_OK, pStgSave->CreateStream( OLESTR("CObjectWithPersistStorage"),
  1450. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1451. 0, 0, &pStm ));
  1452. cbData = sizeof(OLECHAR)*( 1 + ocslen(_poszData) );
  1453. Check( S_OK, pStm->Write( _poszData, cbData, &cbWritten ));
  1454. Check( TRUE, cbData == cbWritten );
  1455. Check( 0, RELEASE_INTERFACE(pStm) );
  1456. return( S_OK );
  1457. }
  1458. HRESULT
  1459. CObjectWithPersistStorage::SaveCompleted(
  1460. /* [unique][in] */ IStorage __RPC_FAR *pStgNew)
  1461. {
  1462. return( S_OK );
  1463. }
  1464. HRESULT
  1465. CObjectWithPersistStorage::HandsOffStorage( void)
  1466. {
  1467. return( E_NOTIMPL );
  1468. }
  1469. BOOL
  1470. CObjectWithPersistStorage::operator ==( const CObjectWithPersistStorage &Other )
  1471. {
  1472. return( Other._poszData == _poszData
  1473. ||
  1474. 0 == ocscmp( Other._poszData, _poszData ));
  1475. }
  1476. CLSID
  1477. CObjectWithPersistStream::_clsid= { /* b447cba0-c991-11d1-b2a8-00c04fb9386d */
  1478. 0xb447cba0,
  1479. 0xc991,
  1480. 0x11d1,
  1481. {0xb2, 0xa8, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d}
  1482. };
  1483. CObjectWithPersistStream::CObjectWithPersistStream()
  1484. {
  1485. _poszData = NULL;
  1486. _cRefs = 1;
  1487. _fDirty = FALSE;
  1488. }
  1489. CObjectWithPersistStream::CObjectWithPersistStream( const OLECHAR *posz )
  1490. {
  1491. new(this) CObjectWithPersistStream;
  1492. _poszData = new OLECHAR[ ocslen(posz) + 1 ];
  1493. Check( TRUE, NULL != _poszData );
  1494. ocscpy( _poszData, posz );
  1495. _fDirty = TRUE;
  1496. }
  1497. CObjectWithPersistStream::~CObjectWithPersistStream()
  1498. {
  1499. delete[] _poszData;
  1500. }
  1501. ULONG
  1502. CObjectWithPersistStream::AddRef()
  1503. {
  1504. ULONG cRefs = InterlockedIncrement( &_cRefs );
  1505. return( cRefs );
  1506. }
  1507. ULONG
  1508. CObjectWithPersistStream::Release()
  1509. {
  1510. ULONG cRefs = InterlockedDecrement( &_cRefs );
  1511. if( 0 == cRefs )
  1512. delete this;
  1513. return( cRefs );
  1514. }
  1515. HRESULT
  1516. CObjectWithPersistStream::QueryInterface( REFIID iid, void **ppvObject )
  1517. {
  1518. if( IID_IPersistStream == iid || IID_IUnknown == iid )
  1519. {
  1520. *ppvObject = static_cast<IPersistStream*>(this);
  1521. AddRef();
  1522. return( S_OK );
  1523. }
  1524. else
  1525. return( E_NOINTERFACE );
  1526. }
  1527. HRESULT
  1528. CObjectWithPersistStream::GetClassID( CLSID *pclsid )
  1529. {
  1530. *pclsid = GetClassID();
  1531. return( S_OK );
  1532. }
  1533. HRESULT
  1534. CObjectWithPersistStream::IsDirty( void)
  1535. {
  1536. return( _fDirty );
  1537. }
  1538. HRESULT
  1539. CObjectWithPersistStream::Load(
  1540. /* [unique][in] */ IStream __RPC_FAR *pStm)
  1541. {
  1542. ULONG cbRead;
  1543. _poszData = new OLECHAR[ MAX_PATH ];
  1544. Check( TRUE, NULL != _poszData );
  1545. Check( S_OK, pStm->Read( _poszData, sizeof(OLECHAR)*MAX_PATH, &cbRead ));
  1546. _poszData[ MAX_PATH-1 ] = OLESTR('\0');
  1547. return( S_OK );
  1548. }
  1549. HRESULT
  1550. CObjectWithPersistStream::Save(
  1551. /* [unique][in] */ IStream __RPC_FAR *pStm,
  1552. /* [in] */ BOOL fClearDirty)
  1553. {
  1554. ULONG cbData, cbWritten;
  1555. cbData = sizeof(OLECHAR)*( 1 + ocslen(_poszData) );
  1556. Check( S_OK, pStm->Write( _poszData, cbData, &cbWritten ));
  1557. Check( TRUE, cbData == cbWritten );
  1558. return( S_OK );
  1559. }
  1560. HRESULT
  1561. CObjectWithPersistStream::GetSizeMax(
  1562. /* [out] */ ULARGE_INTEGER __RPC_FAR *pcbSize)
  1563. {
  1564. return( E_NOTIMPL );
  1565. }
  1566. BOOL
  1567. CObjectWithPersistStream::operator ==( const CObjectWithPersistStream &Other )
  1568. {
  1569. return( Other._poszData == _poszData
  1570. ||
  1571. 0 == ocscmp( Other._poszData, _poszData ));
  1572. }
  1573. //+----------------------------------------------------------------------------
  1574. //+----------------------------------------------------------------------------
  1575. void
  1576. DeleteBagExProperties( IPropertyBagEx *pbag, const OLECHAR *poszPrefix )
  1577. {
  1578. HRESULT hr = S_OK;
  1579. IEnumSTATPROPBAG *penum = NULL;
  1580. STATPROPBAG statpropbag;
  1581. // Get an enumerator of the properties to be deleted.
  1582. Check( S_OK, pbag->Enum( poszPrefix, 0, &penum ));
  1583. // Loop through and delete the properties
  1584. hr = penum->Next(1, &statpropbag, NULL );
  1585. Check( TRUE, SUCCEEDED(hr) );
  1586. while( S_OK == hr )
  1587. {
  1588. Check( S_OK, pbag->DeleteMultiple(1, &statpropbag.lpwstrName, 0 ));
  1589. delete [] statpropbag.lpwstrName;
  1590. statpropbag.lpwstrName = NULL;
  1591. hr = penum->Next(1, &statpropbag, NULL );
  1592. Check( TRUE, SUCCEEDED(hr) );
  1593. } // while( S_OK == hr )
  1594. RELEASE_INTERFACE(penum);
  1595. return;
  1596. } // EmptyPropertyBagEx
  1597. //+----------------------------------------------------------------------------
  1598. //
  1599. // Function: DetermineSystemInfo
  1600. //
  1601. // Synopsis: Fill in the g_SystemInfo structure.
  1602. //
  1603. // Inputs: None.
  1604. //
  1605. // Returns: None.
  1606. //
  1607. //+----------------------------------------------------------------------------
  1608. void DetermineSystemInfo()
  1609. {
  1610. // Initilize g_SystemInfo.
  1611. g_SystemInfo.osenum = osenumUnknown;
  1612. g_SystemInfo.fIPropMarshaling = FALSE;
  1613. #ifdef _MAC
  1614. // Set the OS type.
  1615. g_SystemInfo.osenum = osenumMac;
  1616. #else
  1617. DWORD dwVersion;
  1618. // Get the OS Version
  1619. dwVersion = GetVersion();
  1620. // Is this an NT system?
  1621. if( (dwVersion & 0x80000000) == 0 )
  1622. {
  1623. // Is this at least NT4?
  1624. if( LOBYTE(LOWORD( dwVersion )) >= 4 )
  1625. g_SystemInfo.osenum = osenumNT4;
  1626. // Or, is this pre-NT4?
  1627. else
  1628. if( LOBYTE(LOWORD( dwVersion )) == 3 )
  1629. {
  1630. g_SystemInfo.osenum = osenumNT3;
  1631. }
  1632. }
  1633. // Otherwise, this is some kind of Win95 machine.
  1634. else
  1635. {
  1636. HINSTANCE hinst;
  1637. FARPROC farproc;
  1638. // Load OLE32, and see if CoIntializeEx exists. If it does,
  1639. // then DCOM95 is installed. Otherwise, this is just the base
  1640. // Win95.
  1641. hinst = LoadLibraryA( "ole32.dll" );
  1642. Check( TRUE, hinst != NULL );
  1643. farproc = GetProcAddress( hinst, "CoInitializeEx" );
  1644. if( NULL != farproc )
  1645. {
  1646. g_SystemInfo.osenum = osenumDCOM95;
  1647. }
  1648. else if( ERROR_PROC_NOT_FOUND == GetLastError() )
  1649. {
  1650. g_SystemInfo.osenum = osenumWin95;
  1651. }
  1652. } // if( (dwVersion & 0x80000000) == 0 )
  1653. Check( TRUE, g_SystemInfo.osenum != osenumUnknown );
  1654. #endif // #ifdef _MAC ... #else
  1655. if( osenumWin95 == g_SystemInfo.osenum
  1656. ||
  1657. osenumNT3 == g_SystemInfo.osenum
  1658. )
  1659. {
  1660. g_SystemInfo.fIPropMarshaling = TRUE;
  1661. }
  1662. }
  1663. void
  1664. DisplayUsage( LPSTR pszCommand )
  1665. {
  1666. #ifndef _MAC
  1667. printf("\n");
  1668. printf(" Usage: %s [options]\n", pszCommand);
  1669. printf(" Options:\n");
  1670. printf(" /s run Standard tests\n" );
  1671. printf(" /w run the Word 6 test\n");
  1672. printf(" /m run the Marshaling test\n");
  1673. printf(" /c run the CoFileTimeNow\n");
  1674. printf(" /p run the Performance test\n");
  1675. printf(" /a run All tests\n" );
  1676. printf(" /k run the simple leaK test\n" );
  1677. printf(" /n use nt5props.dll rather than ole32.dll where possible\n");
  1678. printf(" (mostly for STGFMT_FILE)\n" );
  1679. printf("\n");
  1680. printf(" /i# Implementation to use:\n");
  1681. printf(" 0 => Use DocFile and QI for IPropSetStg (default)\n");
  1682. printf(" 1 => Use DocFile and use Stg*Prop*Stg\n");
  1683. printf(" 3 => Use NSS\n");
  1684. printf(" 4 => Use NTFS native property sets\n");
  1685. printf(" /l Don't register the local server\n");
  1686. printf(" /v Verbose output\n" );
  1687. printf("\n");
  1688. printf(" File & Directory Options:\n" );
  1689. printf(" /t <directory> specifies temporary directory\n" );
  1690. printf(" (used during standard & optional tests - if not specified,\n" );
  1691. printf(" a default will be used)\n" );
  1692. printf(" /g <file> specifies a file to be munGed\n" );
  1693. printf(" (propsets are read, deleted, & re-written)\n" );
  1694. printf(" /d <file> specifies a file to be Dumped\n" );
  1695. printf(" (propsets are dumped to stdout\n" );
  1696. printf("\n");
  1697. printf(" For Example:\n" );
  1698. printf(" %s -smw /i1 -t d:\\test\n", pszCommand );
  1699. printf(" %s -d word6.doc\n", pszCommand );
  1700. printf(" %s -g word6.doc\n", pszCommand );
  1701. printf("\n");
  1702. #endif
  1703. return;
  1704. }
  1705. ULONG
  1706. ProcessCommandLine( int cArg, const LPSTR rgszArg[],
  1707. LPSTR *ppszFileToDump, LPSTR *ppszFileToMunge, LPSTR *ppszTemporaryDirectory )
  1708. {
  1709. ULONG ulTestOptions = 0;
  1710. ULONG ulTestOptionsT = 0;
  1711. int nArgIndex;
  1712. if( 2 > cArg )
  1713. {
  1714. goto Exit;
  1715. }
  1716. for( nArgIndex = 1; nArgIndex < cArg; nArgIndex++ )
  1717. {
  1718. if( rgszArg[nArgIndex][0] == '/'
  1719. ||
  1720. rgszArg[nArgIndex][0] == '-'
  1721. )
  1722. {
  1723. BOOL fNextArgument = FALSE;
  1724. for( int nOptionSubIndex = 1;
  1725. rgszArg[nArgIndex][nOptionSubIndex] != '\0' && !fNextArgument;
  1726. nOptionSubIndex++
  1727. )
  1728. {
  1729. switch( rgszArg[nArgIndex][nOptionSubIndex] )
  1730. {
  1731. case 's':
  1732. case 'S':
  1733. ulTestOptionsT |= TEST_STANDARD;
  1734. break;
  1735. case 'a':
  1736. case 'A':
  1737. ulTestOptionsT |= TEST_WORD6 | TEST_MARSHALING | TEST_COFILETIMENOW | TEST_PERFORMANCE;
  1738. break;
  1739. case 'g':
  1740. case 'G':
  1741. if( NULL != *ppszFileToMunge )
  1742. printf( "Error: Only one file may be munged\n" );
  1743. else
  1744. {
  1745. nArgIndex++;
  1746. *ppszFileToMunge = &rgszArg[nArgIndex][0];
  1747. fNextArgument = TRUE;
  1748. if(**ppszFileToMunge == '-' || **ppszFileToMunge == '/')
  1749. {
  1750. printf( "Error: Missing filename for munge option\n" );
  1751. goto Exit;
  1752. }
  1753. }
  1754. break;
  1755. case 'w':
  1756. case 'W':
  1757. ulTestOptionsT |= TEST_WORD6;
  1758. break;
  1759. case 'm':
  1760. case 'M':
  1761. ulTestOptionsT |= TEST_MARSHALING;
  1762. break;
  1763. case 'k':
  1764. case 'K':
  1765. ulTestOptionsT |= TEST_SIMPLE_LEAKS;
  1766. break;
  1767. case 'c':
  1768. case 'C':
  1769. ulTestOptionsT |= TEST_COFILETIMENOW;
  1770. break;
  1771. case 'p':
  1772. case 'P':
  1773. ulTestOptionsT |= TEST_PERFORMANCE;
  1774. break;
  1775. case 'i':
  1776. case 'I':
  1777. {
  1778. int nSubOption = rgszArg[nArgIndex][++nOptionSubIndex];
  1779. if( PROPIMP_UNKNOWN != g_enumImplementation )
  1780. {
  1781. printf( "Error in \"/i\" option (too many occurrences)\n" );
  1782. goto Exit;
  1783. }
  1784. switch( nSubOption )
  1785. {
  1786. case '0': // default, if unspecified
  1787. g_enumImplementation = PROPIMP_DOCFILE_QI;
  1788. break;
  1789. case '1':
  1790. g_enumImplementation = PROPIMP_DOCFILE_OLE32;
  1791. break;
  1792. case '3':
  1793. g_enumImplementation = PROPIMP_STORAGE;
  1794. break;
  1795. case '4':
  1796. g_enumImplementation = PROPIMP_NTFS;
  1797. break;
  1798. default:
  1799. printf( "Error in \"/i\" option\n" );
  1800. goto Exit;
  1801. }
  1802. break;
  1803. }
  1804. case 't':
  1805. case 'T':
  1806. if( NULL != *ppszTemporaryDirectory )
  1807. {
  1808. printf( "Error: Only one temporary directory may be specified\n" );
  1809. }
  1810. else
  1811. {
  1812. nArgIndex++;
  1813. *ppszTemporaryDirectory = &rgszArg[nArgIndex][0];
  1814. fNextArgument = TRUE;
  1815. if(**ppszTemporaryDirectory == '-'
  1816. ||
  1817. **ppszTemporaryDirectory == '/'
  1818. )
  1819. {
  1820. printf( "Error: Missing name for temporary directory option\n" );
  1821. goto Exit;
  1822. }
  1823. }
  1824. break;
  1825. case 'l':
  1826. case 'L':
  1827. g_fRegisterLocalServer = FALSE;
  1828. break;
  1829. case 'n':
  1830. case 'N':
  1831. g_fUseNt5PropsDll = TRUE;
  1832. break;
  1833. case '?':
  1834. return( FALSE );
  1835. break;
  1836. case 'd':
  1837. case 'D':
  1838. if( NULL != *ppszFileToDump )
  1839. {
  1840. printf( "Error: Only one file may be dumped\n" );
  1841. goto Exit;
  1842. }
  1843. else
  1844. {
  1845. nOptionSubIndex++;
  1846. switch (rgszArg[nArgIndex][nOptionSubIndex])
  1847. {
  1848. case 's':
  1849. g_stgmDumpFlags = STGM_SIMPLE;
  1850. break;
  1851. case '\0':
  1852. break;
  1853. default:
  1854. printf( "Error: Invalid Flag used with dump option\n" );
  1855. return( FALSE );
  1856. break;
  1857. }
  1858. nArgIndex++;
  1859. *ppszFileToDump = &rgszArg[nArgIndex][0];
  1860. fNextArgument = TRUE;
  1861. if(**ppszFileToDump == '-' || **ppszFileToDump == '/')
  1862. {
  1863. printf( "Error: Missing filename for dump option\n" );
  1864. goto Exit;
  1865. }
  1866. }
  1867. break;
  1868. case 'v':
  1869. case 'V':
  1870. g_fVerbose = TRUE;
  1871. break;
  1872. default:
  1873. printf( "Option '%c' ignored\n", rgszArg[nArgIndex][nOptionSubIndex] );
  1874. break;
  1875. } // switch( argv[nArgIndex][1] )
  1876. } // for( int nOptionSubIndex = 1; ...
  1877. } // if( argv[nArgIndex][0] == '/'
  1878. else
  1879. {
  1880. break;
  1881. }
  1882. } // for( ULONG nArgIndex = 2; nArgIndex < argc; nArgIndex++ )
  1883. ulTestOptions = ulTestOptionsT;
  1884. // ----
  1885. // Exit
  1886. // ----
  1887. Exit:
  1888. return( ulTestOptions );
  1889. } // ProcessCommandLine
  1890. #define Out wprintf
  1891. NTSTATUS GetProcessInfo(
  1892. PSYSTEM_PROCESS_INFORMATION pspi )
  1893. {
  1894. NUMBERFMT NumberFmt;
  1895. LCID lcid = GetUserDefaultLCID();
  1896. typedef NTSTATUS (__stdcall*PFNNtQuerySystemInformation)(ULONG,BYTE*,ULONG,VOID*);
  1897. static BYTE ab[81920];
  1898. static HINSTANCE hinstNTDLL = NULL;
  1899. static PFNNtQuerySystemInformation pfnNtQuerySystemInformation = NULL;
  1900. WCHAR *pwcImage = L"proptest.exe";
  1901. if( NULL == pfnNtQuerySystemInformation )
  1902. {
  1903. if( NULL == hinstNTDLL )
  1904. {
  1905. hinstNTDLL = LoadLibrary( TEXT("ntdll.dll") );
  1906. Check( FALSE, NULL == hinstNTDLL );
  1907. }
  1908. pfnNtQuerySystemInformation = (PFNNtQuerySystemInformation)
  1909. GetProcAddress( hinstNTDLL,
  1910. "NtQuerySystemInformation" );
  1911. Check( FALSE, NULL == pfnNtQuerySystemInformation );
  1912. }
  1913. NTSTATUS status = pfnNtQuerySystemInformation( SystemProcessInformation,
  1914. ab,
  1915. sizeof ab,
  1916. NULL );
  1917. if ( NT_SUCCESS( status ) )
  1918. {
  1919. status = STATUS_OBJECT_NAME_NOT_FOUND;
  1920. DWORD cbOffset = 0;
  1921. PSYSTEM_PROCESS_INFORMATION p = 0;
  1922. do
  1923. {
  1924. p = (PSYSTEM_PROCESS_INFORMATION)&(ab[cbOffset]);
  1925. if ( ( L'*' == *pwcImage ) ||
  1926. ( 0 == *pwcImage ) ||
  1927. ( p->ImageName.Buffer &&
  1928. !_wcsicmp( pwcImage, p->ImageName.Buffer ) ) )
  1929. {
  1930. status = STATUS_SUCCESS;
  1931. *pspi = *p;
  1932. break;
  1933. }
  1934. cbOffset += p->NextEntryOffset;
  1935. } while ( 0 != p->NextEntryOffset );
  1936. }
  1937. return( status );
  1938. } //GetProcessInfo
  1939. #ifdef _MAC
  1940. int __cdecl PropTestMain(int argc, char **argv, CDisplay *pcDisplay )
  1941. #else
  1942. int __cdecl main(int cArg, char *rgszArg[])
  1943. #endif
  1944. {
  1945. ULONG ulTestOptions = 0L;
  1946. CHAR* pszFileToMunge = NULL;
  1947. CHAR* pszTemporaryDirectory = NULL;
  1948. CHAR* pszFileToDump = NULL;
  1949. #ifdef _MAC
  1950. g_pcDisplay = pcDisplay;
  1951. Check( S_OK, InitOleManager( OLEMGR_BIND_NORMAL ));
  1952. #if DBG
  1953. FnAssertOn( TRUE );
  1954. #endif
  1955. #endif
  1956. // Print an appropriate header message
  1957. #ifdef WINNT
  1958. #ifdef _CAIRO_
  1959. PRINTF("\nCairo Property Set Tests\n");
  1960. #else
  1961. PRINTF("\nSUR Property Set Tests\n");
  1962. #endif
  1963. #elif defined(_MAC)
  1964. PRINTF("\nMacintosh Property Set Tests\n" );
  1965. #else
  1966. PRINTF("\nChicago Property Set Tests\n");
  1967. #endif
  1968. // Process the command-line
  1969. ulTestOptions = ProcessCommandLine( cArg, rgszArg, &pszFileToDump, &pszFileToMunge, &pszTemporaryDirectory );
  1970. if(( 0 == ulTestOptions ) && (NULL == pszFileToDump))
  1971. {
  1972. DisplayUsage( rgszArg[0] );
  1973. exit(0);
  1974. }
  1975. // Ensure that that one of the "-i" options is specified.
  1976. if( PROPIMP_UNKNOWN == g_enumImplementation )
  1977. {
  1978. g_enumImplementation = PROPIMP_DOCFILE_QI; // The default
  1979. }
  1980. if( PROPIMP_NTFS == g_enumImplementation )
  1981. g_Restrictions = RESTRICT_DIRECT_ONLY | RESTRICT_NON_HIERARCHICAL;
  1982. else
  1983. g_Restrictions = RESTRICT_NONE;
  1984. // This 'try' wraps the remainder of the routine.
  1985. try
  1986. {
  1987. OLECHAR ocsDir[MAX_PATH+1], ocsTest[MAX_PATH+1],
  1988. ocsTest2[MAX_PATH+1], ocsMarshalingTest[MAX_PATH+1],
  1989. ocsTestOffice[MAX_PATH+1];
  1990. CHAR szDir[ MAX_PATH+1 ];
  1991. CHAR pszGeneratedTempDir[ MAX_PATH + 1 ];
  1992. HRESULT hr;
  1993. DWORD dwFileAttributes;
  1994. UNREFERENCED_PARAMETER( dwFileAttributes );
  1995. UNREFERENCED_PARAMETER( pszGeneratedTempDir );
  1996. CoInitialize(NULL);
  1997. ocscpy( ocsDir, OLESTR("") );
  1998. // ----------------------------------------------------
  1999. // Get the pointers to the necessary exported functions
  2000. // ----------------------------------------------------
  2001. // We use explicit linking so that we can use either the OLE32.dll
  2002. // or nt5props.dll exports.
  2003. if( g_fUseNt5PropsDll )
  2004. {
  2005. // We're to use the propset APIs from nt5props.dll
  2006. g_hinstDLL = LoadLibraryA( "nt5props.dll" );
  2007. Check( TRUE, NULL != g_hinstDLL );
  2008. }
  2009. else
  2010. {
  2011. // We're to use the propset APIs from OLE32
  2012. g_hinstDLL = LoadLibraryA( "ole32.dll" );
  2013. Check( TRUE, NULL != g_hinstDLL );
  2014. }
  2015. g_pfnPropVariantCopy = (FNPROPVARIANTCOPY*)
  2016. GetProcAddress( g_hinstDLL,
  2017. "PropVariantCopy" );
  2018. Check( FALSE, NULL == g_pfnPropVariantCopy );
  2019. g_pfnPropVariantClear = (FNPROPVARIANTCLEAR*)
  2020. GetProcAddress( g_hinstDLL,
  2021. "PropVariantClear" );
  2022. Check( FALSE, NULL == g_pfnPropVariantClear );
  2023. g_pfnFreePropVariantArray = (FNFREEPROPVARIANTARRAY*)
  2024. GetProcAddress( g_hinstDLL,
  2025. "FreePropVariantArray" );
  2026. Check( FALSE, NULL == g_pfnFreePropVariantArray );
  2027. g_pfnStgCreatePropSetStg = (FNSTGCREATEPROPSETSTG*)
  2028. GetProcAddress( g_hinstDLL,
  2029. "StgCreatePropSetStg" );
  2030. Check( FALSE, NULL == g_pfnStgCreatePropSetStg );
  2031. g_pfnStgCreatePropStg = (FNSTGCREATEPROPSTG*)
  2032. GetProcAddress( g_hinstDLL,
  2033. "StgCreatePropStg" );
  2034. Check( FALSE, NULL == g_pfnStgCreatePropStg );
  2035. g_pfnStgOpenPropStg = (FNSTGOPENPROPSTG*)
  2036. GetProcAddress( g_hinstDLL,
  2037. "StgOpenPropStg" );
  2038. Check( FALSE, NULL == g_pfnStgOpenPropStg );
  2039. g_pfnFmtIdToPropStgName = (FNFMTIDTOPROPSTGNAME*)
  2040. GetProcAddress( g_hinstDLL,
  2041. "FmtIdToPropStgName" );
  2042. Check( FALSE, NULL == g_pfnFmtIdToPropStgName );
  2043. g_pfnPropStgNameToFmtId = (FNPROPSTGNAMETOFMTID*)
  2044. GetProcAddress( g_hinstDLL,
  2045. "PropStgNameToFmtId" );
  2046. Check( FALSE, NULL == g_pfnPropStgNameToFmtId );
  2047. g_pfnStgCreateStorageEx = (FNSTGCREATESTORAGEEX*)
  2048. GetProcAddress( g_hinstDLL, "StgCreateStorageEx" );
  2049. Check( FALSE, NULL == g_pfnStgCreateStorageEx );
  2050. g_pfnStgOpenStorageEx = (FNSTGOPENSTORAGEEX*)
  2051. GetProcAddress( g_hinstDLL, "StgOpenStorageEx" );
  2052. Check( FALSE, NULL == g_pfnStgOpenStorageEx );
  2053. g_pfnStgOpenStorageOnHandle = (FNSTGOPENSTORAGEONHANDLE*)
  2054. GetProcAddress( g_hinstDLL, "StgOpenStorageOnHandle" );
  2055. Check( FALSE, NULL == g_pfnStgOpenStorageOnHandle );
  2056. /*
  2057. g_pfnStgCreateStorageOnHandle = (FNSTGCREATESTORAGEONHANDLE*)
  2058. GetProcAddress( g_hinstDLL, "StgCreateStorageOnHandle" );
  2059. Check( FALSE, NULL == g_pfnStgCreateStorageOnHandle );
  2060. */
  2061. g_pfnStgPropertyLengthAsVariant = (FNSTGPROPERTYLENGTHASVARIANT*)
  2062. GetProcAddress( g_hinstDLL, "StgPropertyLengthAsVariant" );
  2063. Check( FALSE, NULL == g_pfnStgPropertyLengthAsVariant );
  2064. g_pfnStgConvertVariantToProperty = (FNSTGCONVERTVARIANTTOPROPERTY*)
  2065. GetProcAddress( g_hinstDLL, "StgConvertVariantToProperty" );
  2066. Check( FALSE, NULL == g_pfnStgConvertVariantToProperty );
  2067. g_pfnStgConvertPropertyToVariant = (FNSTGCONVERTPROPERTYTOVARIANT*)
  2068. GetProcAddress( g_hinstDLL, "StgConvertPropertyToVariant" );
  2069. Check( FALSE, NULL == g_pfnStgConvertPropertyToVariant );
  2070. // ------------------------
  2071. // Is there a file to dump?
  2072. // ------------------------
  2073. if( NULL != pszFileToDump )
  2074. {
  2075. IStorage *pstg;
  2076. IPropertySetStorage *pPropSetStg = NULL;
  2077. IPropertyStorage *pPropStg = NULL;
  2078. PROPSPEC psTest = {1, 2 }; // { 0, (ULONG) L"cimax" };
  2079. PROPVARIANT propvar;
  2080. #if 0
  2081. GUID const guidTest = { 0xCF2EAF90, 0x9311, 0x11CF, 0xBF, 0x8C,
  2082. 0x00, 0x20, 0xAF, 0xE5, 0x05, 0x08 };
  2083. GetProcessInfo( L"proptest.exe" );
  2084. #endif
  2085. PropTest_mbstoocs( ocsDir, sizeof(ocsDir), pszFileToDump );
  2086. for( int i = 0; i < 1; i++ )
  2087. {
  2088. HRESULT hr;
  2089. if ( 0 == ( i % 100 ) )
  2090. printf(".");
  2091. //
  2092. // Attempt to open as docfile or NSS. If that fails,
  2093. // then attempt to open as a FLAT_FILE.
  2094. //
  2095. hr = StgOpenStorageEx( ocsDir,
  2096. g_stgmDumpFlags | STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
  2097. STGFMT_ANY,
  2098. 0L,
  2099. NULL,
  2100. NULL,
  2101. IID_IStorage,
  2102. (PVOID*)&pstg );
  2103. if (FAILED(hr))
  2104. {
  2105. hr = StgOpenStorageEx( ocsDir,
  2106. g_stgmDumpFlags | STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
  2107. STGFMT_ANY,
  2108. 0L,
  2109. NULL,
  2110. NULL,
  2111. IID_IPropertySetStorage,
  2112. (PVOID*)&pPropSetStg );
  2113. }
  2114. Check(S_OK,hr);
  2115. DumpOleStorage( pstg, pPropSetStg, ocsDir );
  2116. #if 0
  2117. Check(S_OK, StgToPropSetStg( pstg, &pPropSetStg ));
  2118. Check(S_OK, pPropSetStg->Open( guidTest,
  2119. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2120. &pPropStg ));
  2121. Check(S_OK, pPropStg->ReadMultiple( 1,
  2122. &psTest,
  2123. &propvar ));
  2124. Check( TRUE, propvar.vt == VT_I4 );
  2125. pPropStg->Release();
  2126. pPropSetStg->Release();
  2127. #endif
  2128. if (pstg)
  2129. {
  2130. pstg->Release();
  2131. }
  2132. }
  2133. // GetProcessInfo( L"proptest.exe" );
  2134. printf( "Press enter key to exit ..." );
  2135. getchar();
  2136. return(0);
  2137. }
  2138. // -------------------------
  2139. // Is there a file to munge?
  2140. // -------------------------
  2141. if( NULL != pszFileToMunge )
  2142. {
  2143. IStorage *pstg;
  2144. PropTest_mbstoocs( ocsDir, sizeof(ocsDir), pszFileToMunge );
  2145. Check(S_OK, StgOpenStorage( ocsDir,
  2146. NULL,
  2147. STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2148. NULL,
  2149. 0L,
  2150. &pstg ));
  2151. MungeStorage( pstg );
  2152. OPRINTF( OLESTR("\"%s\" successfully munged\n"), ocsDir );
  2153. pstg->Release();
  2154. return(0);
  2155. }
  2156. // ----------------------------
  2157. // Create a temporary directory
  2158. // ----------------------------
  2159. // If no temporary directory was specified, generate one.
  2160. #ifndef _MAC
  2161. if( NULL == pszTemporaryDirectory )
  2162. {
  2163. GetTempPathA(sizeof(pszGeneratedTempDir)/sizeof(pszGeneratedTempDir[0]), pszGeneratedTempDir);
  2164. pszTemporaryDirectory = pszGeneratedTempDir;
  2165. }
  2166. // If necessary, add a path separator to the end of the
  2167. // temp directory name.
  2168. {
  2169. CHAR chLast = pszTemporaryDirectory[ strlen(pszTemporaryDirectory) - 1];
  2170. if( (CHAR) '\\' != chLast
  2171. &&
  2172. (CHAR) ':' != chLast )
  2173. {
  2174. strcat( pszTemporaryDirectory, "\\" );
  2175. }
  2176. }
  2177. #endif // #ifndef _MAC
  2178. int i=0;
  2179. #ifndef _MAC
  2180. // Verify that the user-provided directory path
  2181. // exists
  2182. dwFileAttributes = GetFileAttributesA( pszTemporaryDirectory );
  2183. if( (DWORD) -1 == dwFileAttributes )
  2184. {
  2185. printf( "Error: couldn't open temporary directory: \"%s\"\n", pszTemporaryDirectory );
  2186. exit(1);
  2187. }
  2188. else if( !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  2189. {
  2190. printf( "Error: \"%s\" is not a directory\n", pszTemporaryDirectory );
  2191. exit(1);
  2192. }
  2193. // Find a new directory name to use for temporary
  2194. // files ("PrpTstX", where "X" is a number).
  2195. do
  2196. {
  2197. // Post-pend a subdirectory name and counter
  2198. // to the temporary directory name.
  2199. strcpy( szDir, pszTemporaryDirectory );
  2200. strcat( szDir, "PrpTst" );
  2201. sprintf( strchr(szDir,0), "%d", i++ );
  2202. }
  2203. while (!PropTest_CreateDirectory(szDir, NULL));
  2204. printf( "Generated files will be put in \"%s\"\n", szDir );
  2205. strcat( szDir, "\\" );
  2206. // Convert to an OLESTR.
  2207. PropTest_mbstoocs( ocsDir, sizeof(ocsDir), szDir );
  2208. #endif // #ifndef _MAC
  2209. // --------------------------------
  2210. // Create necessary temporary files
  2211. // --------------------------------
  2212. // If any of the standard or extended tests will be run,
  2213. // create "testdoc" and "testdoc2".
  2214. if( ulTestOptions )
  2215. {
  2216. IPropertySetStorage *pPropSetStg;
  2217. // Create "testdoc"
  2218. ocscpy(ocsTest, ocsDir);
  2219. ocscat(ocsTest, OLESTR("testdoc"));
  2220. hr = g_pfnStgCreateStorageEx (
  2221. ocsTest,
  2222. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2223. DetermineStgFmt( g_enumImplementation ),
  2224. 0,
  2225. NULL,
  2226. NULL,
  2227. DetermineStgIID( g_enumImplementation ),
  2228. (void**) &_pstgTemp );
  2229. if (hr != S_OK)
  2230. {
  2231. OPRINTF( OLESTR("Can't create %s\n"), ocsTest);
  2232. exit(1);
  2233. }
  2234. // Create "testdoc2"
  2235. ocscpy(ocsTest2, ocsDir);
  2236. ocscat(ocsTest2, OLESTR("testdoc2"));
  2237. hr = StgCreateDocfile(ocsTest2, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2238. 0, &_pstgTempCopyTo);
  2239. if (hr != S_OK)
  2240. {
  2241. OPRINTF(OLESTR("Can't create %s\n"), ocsTest2);
  2242. exit(1);
  2243. }
  2244. } // if( ulTestOptions )
  2245. // ---------------------
  2246. // Finish initialization
  2247. // ---------------------
  2248. // Indicate what type of marshaling is being used: OLE32 or IPROP.
  2249. DetermineSystemInfo();
  2250. if( g_SystemInfo.fIPropMarshaling )
  2251. PRINTF( "Using IPROP.DLL for marshaling\n" );
  2252. else
  2253. PRINTF( "Using OLE32.DLL for marshaling\n" );
  2254. // Populate an array of propvars for use in tests.
  2255. Check(S_OK, PopulateRGPropVar( g_rgcpropvarAll, g_rgcpropspecAll, g_rgoszpropnameAll, _pstgTemp ));
  2256. // --------------
  2257. // Standard Tests
  2258. // --------------
  2259. // These are the standard tests that should run in
  2260. // any environment.
  2261. if( ulTestOptions & TEST_STANDARD )
  2262. {
  2263. PRINTF( "\nStandard Tests: " );
  2264. g_nIndent++;
  2265. if( g_fVerbose )
  2266. PRINTF( "\n---------------\n" );
  2267. // Run the quick tests.
  2268. test_WriteReadAllProperties( ocsDir );
  2269. // The codepage & lcid should be settable iff the property set is ~empty
  2270. test_SettingLocalization( _pstgTemp );
  2271. // Test the StgOpenStorageOnHandle API
  2272. test_StgOnHandle( ocsDir );
  2273. // Test invalid VTs
  2274. test_UnsupportedProperties( _pstgTemp );
  2275. // Test support for the new (to NT5) VTs (VTs from the Variant)
  2276. test_ExtendedTypes( _pstgTemp );
  2277. // Test the calculation of external memory requirements.
  2278. test_PropertyLengthAsVariant( );
  2279. // Test VT_ARRAY
  2280. test_SafeArray( _pstgTemp );
  2281. // Test each of the interfaces
  2282. test_PropertyInterfaces(_pstgTemp);
  2283. // Test StgCreate/OpenPropStg on CreateStreamOnHGlobal
  2284. test_PropsetOnHGlobal();
  2285. // Test the read-only range of reserved PROPIDs
  2286. test_ReadOnlyReservedProperties( _pstgTemp );
  2287. // Writing PID_ILLEGAL should be silently ignored.
  2288. test_PidIllegal( _pstgTemp );
  2289. // Test the Standalone APIs
  2290. test_StandaloneAPIs( ocsDir );
  2291. // Test for robustness (NTFS only)
  2292. //test_Robustness( ocsDir );
  2293. // Test read-only open of file with no property sets (NTFS only)
  2294. test_PropsetOnEmptyFile( ocsDir );
  2295. // Test having two read-only readers.
  2296. test_MultipleReader( ocsDir );
  2297. // Test PROPSETFLAG_CASE_SENSITIVE & long names
  2298. test_VersionOneNames( _pstgTemp );
  2299. // Test the low-memory support in IMappedStream
  2300. test_LowMemory( _pstgTemp );
  2301. // Test VT_BYREF
  2302. test_ByRef( _pstgTemp );
  2303. // Run the property bag tests
  2304. Status( "Bag Tests\n" );
  2305. g_nIndent++;
  2306. {
  2307. test_IPropertyBag( _pstgTemp );
  2308. test_BagVtUnknown( _pstgTemp );
  2309. test_BagDelete( _pstgTemp );
  2310. test_EmptyBag( ocsDir );
  2311. test_BagEnum( _pstgTemp );
  2312. test_BagCoercion( _pstgTemp );
  2313. test_BagOpenMethod( _pstgTemp );
  2314. }
  2315. --g_nIndent;
  2316. // Test that code pages are handled properly.
  2317. test_CodePages( ocsDir );
  2318. // Test the PROPSETFLAG_UNBUFFERED flag in Stg*PropStg APIs
  2319. test_PROPSETFLAG_UNBUFFERED( _pstgTemp );
  2320. // Test FMTID<->Name conversions
  2321. test_PropStgNameConversion( _pstgTemp );
  2322. // Test the FMTID<->Name conversion APIs
  2323. test_PropStgNameConversion2( );
  2324. // Test StgOpenStorageEx for NTFS flat file support.
  2325. test_ex_api(ocsDir);
  2326. // Test Simple Mode DocFile
  2327. test_SimpleDocFile(ocsDir);
  2328. // Test the IStorage::CopyTo operation, using all combinations of
  2329. // direct and transacted mode for the base and PropSet storages.
  2330. // We don't run this test on the Mac because it doesn't have IStorages
  2331. // which support IPropertySetStorages.
  2332. #ifndef _MAC_NODOC
  2333. if( PROPIMP_STORAGE == g_enumImplementation
  2334. ||
  2335. PROPIMP_DOCFILE_QI == g_enumImplementation )
  2336. {
  2337. for( int iteration = 0; iteration < 4; iteration++ )
  2338. {
  2339. OLECHAR aocStorageName[] = OLESTR( "#0 Test CopyTo" );
  2340. aocStorageName[1] = (OLECHAR) iteration + OLESTR('0');
  2341. test_CopyTo( _pstgTemp, _pstgTempCopyTo,
  2342. iteration & 2 ? STGM_TRANSACTED : STGM_DIRECT, // For the base Storage
  2343. iteration & 1 ? STGM_TRANSACTED : STGM_DIRECT, // For the PropSet Storages
  2344. aocStorageName );
  2345. }
  2346. }
  2347. #endif // #ifndef _MAC_NODOC
  2348. // Generate the stock ticker property set example
  2349. // from the OLE programmer's reference spec.
  2350. test_OLESpecTickerExample( _pstgTemp );
  2351. // Test Office Property Sets
  2352. ocscpy(ocsTestOffice, ocsDir);
  2353. ocscat(ocsTestOffice, OLESTR("Office"));
  2354. test_Office( ocsTestOffice );
  2355. test_Office2( _pstgTemp );
  2356. // Verify parameter validation
  2357. test_ParameterValidation( _pstgTemp );
  2358. // Test PropVariantCopy
  2359. test_PropVariantCopy();
  2360. if( PROPIMP_NTFS != g_enumImplementation )
  2361. {
  2362. // Verify PropVariant validation
  2363. test_PropVariantValidation( _pstgTemp );
  2364. }
  2365. if( !g_fVerbose )
  2366. printf( "\n" );
  2367. --g_nIndent;
  2368. PRINTF( "Standard tests PASSED\n" );
  2369. } // if( ulTestOptions & TEST_STANDARD )
  2370. // --------------
  2371. // Extended Tests
  2372. // --------------
  2373. if( ulTestOptions & ~TEST_STANDARD )
  2374. {
  2375. PRINTF( "\nExtended Tests: " );
  2376. g_nIndent++;
  2377. if( g_fVerbose )
  2378. PRINTF( "\n---------------\n" );
  2379. // Check the CoFileTimeNow fix.
  2380. if( ulTestOptions & TEST_COFILETIMENOW )
  2381. test_CoFileTimeNow();
  2382. // Test for compatibility with Word 6.0 files.
  2383. if( ulTestOptions & TEST_WORD6 )
  2384. test_Word6(_pstgTemp, szDir);
  2385. if( ulTestOptions & TEST_SIMPLE_LEAKS )
  2386. test_SimpleLeaks( ocsDir );
  2387. // Get some performance numbers.
  2388. if ( ulTestOptions & TEST_PERFORMANCE )
  2389. test_Performance( _pstgTemp );
  2390. // Test marshaling.
  2391. #ifndef _MAC // No property marshaling support on the Mac.
  2392. if( ulTestOptions & TEST_MARSHALING )
  2393. {
  2394. PRINTF( " Marshaling Test\n" );
  2395. ocscpy(ocsMarshalingTest, ocsDir);
  2396. ocscat(ocsMarshalingTest, OLESTR("Marshal"));
  2397. Check(S_OK, g_cpsmt.Init( ocsMarshalingTest,
  2398. (PROPVARIANT*) g_rgcpropvarAll,
  2399. (PROPSPEC*) g_rgcpropspecAll,
  2400. CPROPERTIES_ALL,
  2401. CPROPERTIES_ALL_SIMPLE ));
  2402. Check(S_OK, g_cpsmt.Run());
  2403. }
  2404. #endif
  2405. if( !g_fVerbose )
  2406. PRINTF( "\n" );
  2407. --g_nIndent;
  2408. PRINTF( "Extended tests PASSED\n" );
  2409. } // if( ulTestOptions )
  2410. } // try
  2411. catch( CHResult chr )
  2412. {
  2413. }
  2414. //Exit:
  2415. // Clean up and exit.
  2416. if( _pstgTemp != NULL )
  2417. _pstgTemp->Release();
  2418. if( _pstgTempCopyTo != NULL )
  2419. _pstgTempCopyTo->Release();
  2420. g_pfnFreePropVariantArray( CPROPERTIES_ALL, g_rgcpropvarAll );
  2421. // Free the propspec array too. It will free itself in its
  2422. // destructor anyway, but by then it will be too late to
  2423. // call CoTaskMemFree (since CoUninit will have been called
  2424. // by then).
  2425. {
  2426. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  2427. g_rgcpropspecAll[i].FreeResources();
  2428. }
  2429. CoUninitialize();
  2430. #ifdef _MAC
  2431. UninitOleManager();
  2432. #if DBG
  2433. FnAssertOn( FALSE );
  2434. #endif
  2435. #endif
  2436. if( g_hinstDLL ) FreeLibrary( g_hinstDLL );
  2437. CoFreeUnusedLibraries();
  2438. return 0;
  2439. }