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.

9005 lines
310 KiB

  1. //+============================================================================
  2. //
  3. // File: TestCase.cxx
  4. //
  5. // Description:
  6. // This file provides all of the actual test-cases for the
  7. // PropTest DRT. Each test is a function, with a "test_"
  8. // prefix.
  9. //
  10. //+============================================================================
  11. #include "pch.cxx"
  12. #include <ddeml.h> // For CP_WINUNICODE
  13. #include "propstm.hxx"
  14. #include "propstg.hxx"
  15. #include "stgint.h"
  16. EXTERN_C const IID
  17. IID_IStorageTest = { /* 40621cf8-a17f-11d1-b28d-00c04fb9386d */
  18. 0x40621cf8,
  19. 0xa17f,
  20. 0x11d1,
  21. {0xb2, 0x8d, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d}
  22. };
  23. //+---------------------------------------------------------------
  24. //
  25. // Function: test_WriteReadAllProperties
  26. //
  27. // Synopsis: This test simply creates two new property
  28. // sets in a new file (one Ansi and one Unicode),
  29. // writes all the properties in g_rgcpropvarAll,
  30. // reads them back, and verifies that it reads what
  31. // it wrote.
  32. //
  33. // Inputs: [LPOLESTR] ocsDir (in)
  34. // The directory in which a file can be created.
  35. //
  36. // Outputs: None.
  37. //
  38. //+---------------------------------------------------------------
  39. void
  40. test_WriteReadAllProperties( LPOLESTR ocsDir )
  41. {
  42. OLECHAR ocsFile[ MAX_PATH ];
  43. FMTID fmtidAnsi, fmtidUnicode;
  44. UINT ExpectedCodePage;
  45. IStorage *pstg = NULL, *psubstg = NULL;
  46. IStream *pstm = NULL;
  47. IPropertySetStorage *ppropsetstg = NULL;
  48. IPropertyStorage *ppropstgAnsi = NULL, *ppropstgUnicode = NULL;
  49. CPropVariant rgcpropvar[ CPROPERTIES_ALL ];
  50. CPropVariant rgcpropvarAnsi[ CPROPERTIES_ALL ];
  51. CPropVariant rgcpropvarUnicode[ CPROPERTIES_ALL ];
  52. CPropVariant rgcpropvarBag[ CPROPERTIES_ALL ];
  53. CPropVariant rgcpropvarDefault[ 2 ];
  54. CPropSpec rgcpropspecDefault[ 2 ];
  55. IPropertySetStorage *pPropSetStg = NULL;
  56. IPropertyStorage *pPropStg = NULL;
  57. IPropertyBagEx *pbag = NULL;
  58. ULONG ulIndex;
  59. ULONG cPropertiesAll = CPROPERTIES_ALL;
  60. Status( "Simple Write/Read Test\n" );
  61. // ----------
  62. // Initialize
  63. // ----------
  64. // Generate FMTIDs.
  65. UuidCreate( &fmtidAnsi );
  66. UuidCreate( &fmtidUnicode );
  67. // Generate a filename from the directory name.
  68. ocscpy( ocsFile, ocsDir );
  69. ocscat( ocsFile, OLESTR( "AllProps.stg" ));
  70. // ----------------
  71. // Create a docfile
  72. // ----------------
  73. Check( S_OK, g_pfnStgCreateStorageEx( ocsFile,
  74. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  75. DetermineStgFmt( g_enumImplementation ),
  76. 0L,
  77. NULL,
  78. NULL,
  79. DetermineStgIID( g_enumImplementation ),
  80. (void**) &pstg )); //(void**) &ppropsetstg ));
  81. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, (void**) &ppropsetstg ));
  82. // Create the Property Storages
  83. Check( S_OK, ppropsetstg->Create( fmtidAnsi,
  84. &CLSID_NULL,
  85. ( (g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_DEFAULT : PROPSETFLAG_ANSI )
  86. |
  87. ( (g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_DEFAULT: PROPSETFLAG_NONSIMPLE ),
  88. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  89. &ppropstgAnsi ));
  90. Check( S_OK, ppropsetstg->Create( fmtidUnicode,
  91. &CLSID_NULL,
  92. (g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_DEFAULT: PROPSETFLAG_NONSIMPLE,
  93. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  94. &ppropstgUnicode ));
  95. // Get a property bag. This is also a convenient place to test that we can QI between
  96. // the storage and bag.
  97. IStorage *pstg2 = NULL;
  98. IPropertyBagEx *pbag2 = NULL;
  99. IUnknown *punk1 = NULL;
  100. IUnknown *punk2 = NULL;
  101. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  102. Check( S_OK, pbag->QueryInterface( DetermineStgIID( g_enumImplementation ), reinterpret_cast<void**>(&pstg2) ));
  103. Check( S_OK, pstg2->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag2) ));
  104. Check( TRUE, pbag == pbag2 && pstg == pstg2 );
  105. RELEASE_INTERFACE(pbag2);
  106. RELEASE_INTERFACE(pstg2);
  107. Check( S_OK, pstg->QueryInterface( IID_IUnknown, reinterpret_cast<void**>(&punk1) ));
  108. Check( S_OK, pbag->QueryInterface( IID_IUnknown, reinterpret_cast<void**>(&punk2) ));
  109. Check( TRUE, punk1 == punk2 );
  110. RELEASE_INTERFACE(punk1);
  111. RELEASE_INTERFACE(punk2);
  112. // Write some simple properties
  113. Check( S_OK, ppropstgAnsi->WriteMultiple( CPROPERTIES_ALL_SIMPLE,
  114. g_rgcpropspecAll,
  115. g_rgcpropvarAll,
  116. PID_FIRST_USABLE ));
  117. // Verify the format version is 0
  118. CheckFormatVersion(ppropstgAnsi, 0);
  119. // Write to all property sets.
  120. Check( S_OK, ppropstgAnsi->WriteMultiple( cPropertiesAll,
  121. g_rgcpropspecAll,
  122. g_rgcpropvarAll,
  123. PID_FIRST_USABLE ));
  124. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  125. // Verify that the format is now version 1, since we wrote a VersionedStream property
  126. CheckFormatVersion(ppropstgAnsi, 1);
  127. Check( S_OK, ppropstgUnicode->WriteMultiple( cPropertiesAll,
  128. g_rgcpropspecAll,
  129. g_rgcpropvarAll,
  130. PID_FIRST_USABLE ));
  131. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  132. Check( S_OK, pbag->WriteMultiple( cPropertiesAll,
  133. g_rgoszpropnameAll,
  134. g_rgcpropvarAll ));
  135. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  136. // Close and re-open everything
  137. RELEASE_INTERFACE(pstg);
  138. RELEASE_INTERFACE(ppropsetstg);
  139. RELEASE_INTERFACE(ppropstgAnsi);
  140. RELEASE_INTERFACE(ppropstgUnicode);
  141. Check( 0, pbag->Release() );
  142. pbag = NULL;
  143. Check( S_OK, g_pfnStgOpenStorageEx( ocsFile,
  144. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  145. DetermineStgFmt( g_enumImplementation ),
  146. 0L,
  147. NULL,
  148. NULL,
  149. DetermineStgIID( g_enumImplementation ),
  150. (void**) &pstg )); //(void**) &ppropsetstg ));
  151. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, (void**) &ppropsetstg ));
  152. // Create the Property Storages
  153. Check( S_OK, ppropsetstg->Open( fmtidAnsi,
  154. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  155. &ppropstgAnsi ));
  156. Check( S_OK, ppropsetstg->Open( fmtidUnicode,
  157. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  158. &ppropstgUnicode ));
  159. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  160. // Read and verify the auto-generated properties.
  161. rgcpropspecDefault[0] = static_cast<PROPID>(PID_CODEPAGE);
  162. rgcpropspecDefault[1] = static_cast<PROPID>(PID_LOCALE);
  163. Check( S_OK, ppropstgAnsi->ReadMultiple( 2, rgcpropspecDefault, rgcpropvarDefault ));
  164. ExpectedCodePage = (g_Restrictions & RESTRICT_UNICODE_ONLY) ? CP_WINUNICODE : GetACP();
  165. Check( TRUE, VT_I2 == rgcpropvarDefault[0].vt );
  166. Check( TRUE, ExpectedCodePage == (UINT) rgcpropvarDefault[0].iVal );
  167. Check( TRUE, VT_UI4 == rgcpropvarDefault[1].vt );
  168. Check( TRUE, GetUserDefaultLCID() == rgcpropvarDefault[1].ulVal );
  169. Check( S_OK, ppropstgUnicode->ReadMultiple( 2, rgcpropspecDefault, rgcpropvarDefault ));
  170. ExpectedCodePage = CP_WINUNICODE;
  171. Check( TRUE, VT_I2 == rgcpropvarDefault[0].vt );
  172. Check( TRUE, ExpectedCodePage == (UINT) rgcpropvarDefault[0].iVal );
  173. Check( TRUE, VT_UI4 == rgcpropvarDefault[1].vt );
  174. Check( TRUE, GetUserDefaultLCID() == rgcpropvarDefault[1].ulVal );
  175. // Read from all property sets
  176. Check( S_OK, ppropstgAnsi->ReadMultiple( cPropertiesAll,
  177. g_rgcpropspecAll,
  178. rgcpropvarAnsi ));
  179. Check( S_OK, ppropstgUnicode->ReadMultiple( cPropertiesAll,
  180. g_rgcpropspecAll,
  181. rgcpropvarUnicode ));
  182. Check( S_OK, pbag->ReadMultiple( cPropertiesAll, g_rgoszpropnameAll, rgcpropvarBag, NULL ));
  183. // Compare the properties
  184. for( int i = 0; i < (int)cPropertiesAll; i++ )
  185. {
  186. Check( TRUE, rgcpropvarAnsi[i] == g_rgcpropvarAll[i] );
  187. Check( TRUE, rgcpropvarUnicode[i] == g_rgcpropvarAll[i] );
  188. Check( TRUE, rgcpropvarBag[i] == g_rgcpropvarAll[i] );
  189. }
  190. // Show that we can delete everything
  191. Check( S_OK, ppropstgAnsi->DeleteMultiple( cPropertiesAll, g_rgcpropspecAll ));
  192. Check( S_OK, ppropstgUnicode->DeleteMultiple( cPropertiesAll, g_rgcpropspecAll ));
  193. Check( S_OK, pbag->DeleteMultiple( cPropertiesAll, g_rgoszpropnameAll, 0 ));
  194. // Re-write the properties, because it's convenient for debug sometimes
  195. // to have a file around with lots of properties in it.
  196. Check( S_OK, ppropstgAnsi->WriteMultiple( cPropertiesAll,
  197. g_rgcpropspecAll,
  198. g_rgcpropvarAll,
  199. PID_FIRST_USABLE ));
  200. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  201. Check( S_OK, ppropstgUnicode->WriteMultiple( cPropertiesAll,
  202. g_rgcpropspecAll,
  203. g_rgcpropvarAll,
  204. PID_FIRST_USABLE ));
  205. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  206. RELEASE_INTERFACE(pstg);
  207. RELEASE_INTERFACE(ppropsetstg);
  208. RELEASE_INTERFACE(ppropstgAnsi);
  209. RELEASE_INTERFACE(ppropstgUnicode);
  210. Check( 0, pbag->Release() );
  211. pbag = NULL;
  212. } // test_WriteReadProperties
  213. BOOL
  214. StgConvertPropertyToVariantWrapper(
  215. IN SERIALIZEDPROPERTYVALUE const *pprop,
  216. IN USHORT CodePage,
  217. OUT PROPVARIANT *pvar,
  218. IN PMemoryAllocator *pma,
  219. OUT NTSTATUS *pstatus )
  220. {
  221. BOOL boolRet = FALSE;
  222. *pstatus = STATUS_SUCCESS;
  223. __try
  224. {
  225. boolRet = g_pfnStgConvertPropertyToVariant( pprop, CodePage, pvar, pma );
  226. // boolRet = RtlConvertPropertyToVariant( pprop, CodePage, pvar, pma );
  227. }
  228. __except( EXCEPTION_EXECUTE_HANDLER )
  229. {
  230. *pstatus = GetExceptionCode();
  231. }
  232. return( boolRet );
  233. }
  234. ULONG
  235. StgPropertyLengthAsVariantWrapper( SERIALIZEDPROPERTYVALUE *pprop, ULONG cbprop, USHORT CodePage, BYTE flags,
  236. NTSTATUS *pstatus )
  237. {
  238. ULONG cbRet = 0;
  239. *pstatus = STATUS_SUCCESS;
  240. __try
  241. {
  242. cbRet = g_pfnStgPropertyLengthAsVariant( pprop, cbprop, CodePage, 0 );
  243. // cbRet = PropertyLengthAsVariant( pprop, cbprop, CodePage, 0 );
  244. }
  245. __except( EXCEPTION_EXECUTE_HANDLER )
  246. {
  247. *pstatus = GetExceptionCode();
  248. }
  249. return( cbRet );
  250. }
  251. SERIALIZEDPROPERTYVALUE *
  252. StgConvertVariantToPropertyWrapper(
  253. IN PROPVARIANT const *pvar,
  254. IN USHORT CodePage,
  255. OPTIONAL OUT SERIALIZEDPROPERTYVALUE *pprop,
  256. IN OUT ULONG *pcb,
  257. IN PROPID pid,
  258. IN BOOLEAN fVector,
  259. OPTIONAL OUT ULONG *pcIndirect,
  260. OUT NTSTATUS *pstatus )
  261. {
  262. SERIALIZEDPROPERTYVALUE * ppropRet = NULL;
  263. *pstatus = STATUS_SUCCESS;
  264. __try
  265. {
  266. ppropRet = g_pfnStgConvertVariantToProperty( pvar, CodePage, pprop, pcb, pid, fVector, pcIndirect );
  267. // ppropRet = RtlConvertVariantToProperty( pvar, CodePage, pprop, pcb, pid, fVariantVectorOrArray, pcIndirect );
  268. }
  269. __except( EXCEPTION_EXECUTE_HANDLER )
  270. {
  271. *pstatus = GetExceptionCode();
  272. }
  273. return( ppropRet );
  274. }
  275. void
  276. test_PidIllegal( IStorage *pstg )
  277. {
  278. IPropertySetStorage *ppropsetstg = NULL;
  279. IPropertyStorage *ppropstg = NULL;
  280. ULONG cRefsOriginal = GetRefCount(pstg);
  281. CPropVariant rgcpropvarWrite[3], rgcpropvarRead[3];
  282. CPropSpec rgcpropspec[3];
  283. PROPID rgpropid[3];
  284. LPOLESTR rgoszNames[3] = { NULL, NULL, NULL };
  285. // Get an IPropertyStorage
  286. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&ppropsetstg) ));
  287. Check( S_OK, ppropsetstg->Create( FMTID_NULL, NULL, PROPSETFLAG_DEFAULT,
  288. STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  289. &ppropstg ));
  290. // Write a PID_ILLEGAL property. Since it's ignored, nothing should be written.
  291. rgcpropvarWrite[0] = (long) 1234;
  292. rgcpropspec[0] = PID_ILLEGAL;
  293. Check( S_OK, ppropstg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  294. Check( S_FALSE, ppropstg->ReadMultiple( 1, rgcpropspec, rgcpropvarRead ));
  295. // Write several normal properties
  296. SHORT sOriginal = 1234;
  297. LPOLESTR oszOriginalName = OLESTR("Second");
  298. rgcpropvarWrite[0] = (long) 5678;
  299. rgcpropvarWrite[1] = sOriginal;
  300. rgcpropvarWrite[2] = (float) 23.5;
  301. rgcpropspec[0] = OLESTR("First");
  302. rgcpropspec[1] = oszOriginalName;
  303. rgcpropspec[2] = OLESTR("Third");
  304. Check( S_OK, ppropstg->WriteMultiple( 3, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  305. Check( S_OK, ppropstg->ReadMultiple( 3, rgcpropspec, rgcpropvarRead ));
  306. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  307. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  308. Check( TRUE, rgcpropvarWrite[2] == rgcpropvarRead[2] );
  309. // Re-write the properties except for one. The value of that property shouldn't change,
  310. // nor should its name.
  311. rgcpropvarWrite[0] = (short) 1234;
  312. rgcpropvarWrite[1] = (long) 5678;
  313. rgcpropvarWrite[2] = (double) 12.4;
  314. rgcpropspec[1] = PID_ILLEGAL;
  315. Check( S_OK, ppropstg->WriteMultiple( 3, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  316. rgcpropspec[1] = oszOriginalName;
  317. Check( S_OK, ppropstg->ReadMultiple( 3, rgcpropspec, rgcpropvarRead ));
  318. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  319. Check( TRUE, CPropVariant(sOriginal) == rgcpropvarRead[1] );
  320. Check( TRUE, rgcpropvarWrite[2] == rgcpropvarRead[2] );
  321. rgpropid[0] = PID_FIRST_USABLE;
  322. rgpropid[1] = PID_FIRST_USABLE + 1;
  323. rgpropid[2] = PID_FIRST_USABLE + 2;
  324. Check( S_OK, ppropstg->ReadPropertyNames( 3, rgpropid, rgoszNames ));
  325. Check( 0, wcscmp( rgcpropspec[0].lpwstr, rgoszNames[0] ));
  326. Check( 0, wcscmp( oszOriginalName, rgoszNames[1] ));
  327. Check( 0, wcscmp( rgcpropspec[2].lpwstr, rgoszNames[2] ));
  328. for( int i = 0; i < 3; i++ )
  329. {
  330. CoTaskMemFree( rgoszNames[i] );
  331. rgoszNames[i] = NULL;
  332. }
  333. // Re-write the names, again skipping one of them.
  334. rgoszNames[0] = OLESTR("Updated first");
  335. rgoszNames[1] = OLESTR("Updated second");
  336. rgoszNames[2] = OLESTR("Updated third");
  337. rgpropid[1] = PID_ILLEGAL;
  338. Check( S_OK, ppropstg->WritePropertyNames( 3, rgpropid, rgoszNames ));
  339. rgoszNames[0] = rgoszNames[1] = rgoszNames[2] = NULL;
  340. rgpropid[1] = PID_FIRST_USABLE + 1;
  341. Check( S_OK, ppropstg->ReadPropertyNames( 3, rgpropid, rgoszNames ));
  342. Check( 0, wcscmp( rgoszNames[0], OLESTR("Updated first") ));
  343. Check( 0, wcscmp( rgoszNames[1], oszOriginalName ));
  344. Check( 0, wcscmp( rgoszNames[2], OLESTR("Updated third") ));
  345. // Re-write just the one name, but skipping it.
  346. rgpropid[1] = PID_ILLEGAL;
  347. CoTaskMemFree( rgoszNames[1] );
  348. rgoszNames[1] = OLESTR("Write just the second");
  349. Check( S_OK, ppropstg->WritePropertyNames( 1, &rgpropid[1], &rgoszNames[1] ));
  350. rgoszNames[1] = NULL;
  351. rgpropid[1] = PID_FIRST_USABLE + 1;
  352. Check( S_OK, ppropstg->ReadPropertyNames( 1, &rgpropid[1], &rgoszNames[1] ));
  353. Check( 0, wcscmp( rgoszNames[1], oszOriginalName ));
  354. // Exit
  355. for( i = 0; i < 3; i++ )
  356. CoTaskMemFree( rgoszNames[i] );
  357. Check( 0, RELEASE_INTERFACE(ppropstg) );
  358. Check( cRefsOriginal, RELEASE_INTERFACE(ppropsetstg) );
  359. }
  360. void
  361. test_PropertyLengthAsVariant( )
  362. {
  363. Status( "StgPropertyLengthAsVariant, StgConvert*\n" );
  364. ULONG i = 0;
  365. BYTE *rgb = new BYTE[ 8192 ];
  366. Check( TRUE, NULL != rgb );
  367. CPropVariant rgcpropvar[ 7 ];
  368. ULONG rgcbExpected[ 7 ];
  369. CPropVariant *rgcpropvarSafeArray = NULL;
  370. SAFEARRAY *rgpsa[3];
  371. SAFEARRAYBOUND rgsaBounds[] = { {2,0}, {3,10}, {4,20} }; // [0..1], [10..12], [20..23]
  372. ULONG cDims = sizeof(rgsaBounds)/sizeof(rgsaBounds[0]);
  373. ULONG cElems = 0;
  374. rgcpropvar[i] = (long) 1234; // VT_I4
  375. rgcbExpected[i] = 0;
  376. i++;
  377. rgcpropvar[i].SetBSTR( OLESTR("Hello, world") ); // Creates a copy
  378. rgcbExpected[i] = sizeof(OLESTR("Hello, world")) + sizeof(ULONG);
  379. i++;
  380. rgcpropvar[i][2] = (short) 2; // VT_VECTOR | VT_I2
  381. rgcpropvar[i][1] = (short) 1;
  382. rgcpropvar[i][0] = (short) 0;
  383. rgcbExpected[i] = 3 * sizeof(short);
  384. i++;
  385. rgcpropvar[i][1] = (PROPVARIANT) CPropVariant( (unsigned long) 4 ); // VT_VECTOR | VT_VARIANT
  386. rgcpropvar[i][0] = (PROPVARIANT) CPropVariant( (BSTR) OLESTR("Hi there") );
  387. rgcbExpected[i] = 2 * sizeof(PROPVARIANT) + sizeof(OLESTR("Hi there")) + sizeof(ULONG);
  388. i++;
  389. rgpsa[0] = SafeArrayCreateEx( VT_I4, 3, rgsaBounds, NULL );
  390. Check( TRUE, NULL != rgpsa[0] );
  391. cElems = CalcSafeArrayElementCount( rgpsa[0] );
  392. rgcbExpected[i+0] = sizeof(SAFEARRAY) - sizeof(SAFEARRAYBOUND)
  393. + 3 * sizeof(SAFEARRAYBOUND)
  394. + cElems * sizeof(LONG);
  395. rgpsa[1] = SafeArrayCreateEx( VT_BSTR, 3, rgsaBounds, NULL );
  396. Check( TRUE, NULL != rgpsa[1] );
  397. rgcbExpected[i+1] = sizeof(SAFEARRAY) - sizeof(SAFEARRAYBOUND)
  398. + 3 * sizeof(SAFEARRAYBOUND)
  399. + cElems * sizeof(BSTR);
  400. rgpsa[2] = SafeArrayCreateEx( VT_VARIANT, 3, rgsaBounds, NULL );
  401. Check( TRUE, NULL != rgpsa[2] );
  402. rgcbExpected[i+2] = sizeof(SAFEARRAY) - sizeof(SAFEARRAYBOUND)
  403. + 3 * sizeof(SAFEARRAYBOUND)
  404. + cElems * sizeof(PROPVARIANT);
  405. rgcpropvarSafeArray = new CPropVariant[ cElems ];
  406. Check( FALSE, NULL == rgcpropvar );
  407. for( ULONG j = 0; j < cElems; j++ )
  408. {
  409. LONG rgIndices[3];
  410. CalcSafeArrayIndices( j, rgIndices, rgsaBounds, cDims );
  411. LONG lVal = static_cast<LONG>(j);
  412. Check( S_OK, SafeArrayPutElement( rgpsa[0], rgIndices, &lVal ));
  413. BSTR bstrVal = SysAllocString( OLESTR("0 BSTR Val") );
  414. *bstrVal = OLESTR('0') + static_cast<OLECHAR>(j);
  415. Check( S_OK, SafeArrayPutElement( rgpsa[1], rgIndices, bstrVal ));
  416. rgcbExpected[i+1] += ocslen(bstrVal) + sizeof(OLECHAR) + sizeof(ULONG);
  417. if( j & 1 )
  418. rgcpropvarSafeArray[j] = (long) j;
  419. else
  420. {
  421. rgcpropvarSafeArray[j].SetBSTR( bstrVal );
  422. rgcbExpected[i+2] += ocslen(bstrVal)*sizeof(OLECHAR) + sizeof(OLECHAR) + sizeof(ULONG);
  423. }
  424. Check( S_OK, SafeArrayPutElement( rgpsa[2], rgIndices, &rgcpropvarSafeArray[j] ));
  425. SysFreeString( bstrVal );
  426. }
  427. rgcpropvar[i].vt = VT_ARRAY | VT_I4;
  428. reinterpret_cast<VARIANT*>(&rgcpropvar[i])->parray = rgpsa[0];
  429. i++;
  430. rgcpropvar[i].vt = VT_ARRAY | VT_BSTR;
  431. reinterpret_cast<VARIANT*>(&rgcpropvar[i])->parray = rgpsa[1];
  432. i++;
  433. rgcpropvar[i].vt = VT_ARRAY | VT_VARIANT;
  434. reinterpret_cast<VARIANT*>(&rgcpropvar[i])->parray = rgpsa[2];
  435. i++;
  436. Check( sizeof(rgcpropvar)/sizeof(rgcpropvar[0]), i );
  437. for( i = 0; i < sizeof(rgcpropvar)/sizeof(rgcpropvar[0]); i++ )
  438. {
  439. PropTestMemoryAllocator ma;
  440. SERIALIZEDPROPERTYVALUE *pprop = NULL;
  441. CPropVariant cpropvarOut;
  442. ULONG cbWritten = 8192, cbAsVariant = 0;
  443. NTSTATUS status;
  444. ULONG cIndirect;
  445. pprop = StgConvertVariantToPropertyWrapper(
  446. &rgcpropvar[i], CP_WINUNICODE,
  447. reinterpret_cast<SERIALIZEDPROPERTYVALUE*>(rgb),
  448. &cbWritten, PID_FIRST_USABLE,
  449. FALSE,
  450. &cIndirect,
  451. &status );
  452. Check( TRUE, NT_SUCCESS(status) );
  453. Check( TRUE, NULL != pprop );
  454. cbAsVariant = StgPropertyLengthAsVariantWrapper(
  455. reinterpret_cast<SERIALIZEDPROPERTYVALUE*>(rgb),
  456. cbWritten, CP_WINUNICODE, 0, &status );
  457. Check( TRUE, NT_SUCCESS(status) );
  458. // Check that the cbAsVariant is at least big enough. Also sanity check that
  459. // it's not huge. We use a fudge multiple of 3 for this because the
  460. // StgPropertyLengthAsVariant can way overestimate (primarily because it
  461. // doesn't know if BSTRs will need conversion).
  462. Check( TRUE, cbAsVariant >= rgcbExpected[i] );
  463. Check( TRUE, cbAsVariant <= rgcbExpected[i]*3 );
  464. // Check that we can convert back to a PropVariant
  465. // (False because it's not an indirect property we're converting)
  466. Check( FALSE, StgConvertPropertyToVariantWrapper( reinterpret_cast<SERIALIZEDPROPERTYVALUE*>(rgb),
  467. CP_WINUNICODE, &cpropvarOut,
  468. &ma, &status ));
  469. Check( TRUE, NT_SUCCESS(status) );
  470. Check( TRUE, cpropvarOut == rgcpropvar[i] );
  471. }
  472. g_pfnFreePropVariantArray( cElems, rgcpropvarSafeArray );
  473. delete[] rgcpropvarSafeArray;
  474. g_pfnFreePropVariantArray( sizeof(rgcpropvar)/sizeof(rgcpropvar[0]), rgcpropvar );
  475. delete[] rgb;
  476. }
  477. void
  478. test_LargePropertySet( IStorage *pstg )
  479. {
  480. FMTID fmtid;
  481. IPropertySetStorage *pPropSetStg = NULL;
  482. IPropertyStorage *pPropStg = NULL;
  483. STATPROPSETSTG statpropsetstg;
  484. CPropSpec cpropspec;
  485. PROPVARIANT propvar;
  486. Status( "Large property sets\n" );
  487. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  488. // Create a new property set.
  489. UuidCreate( &fmtid );
  490. Check( S_OK, pPropSetStg->Create( fmtid, NULL,
  491. PROPSETFLAG_DEFAULT,
  492. STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  493. &pPropStg ));
  494. // Create a big property to write. Make it just about the max, 1M
  495. // (it's hard to make it exactly the right size, because it depends on the
  496. // size of the propset header, overallocs, etc.).
  497. propvar.vt = VT_BLOB;
  498. propvar.blob.cbSize = 1023 * 1024;
  499. propvar.blob.pBlobData = new BYTE[ propvar.blob.cbSize ];
  500. Check( FALSE, NULL == propvar.blob.pBlobData );
  501. cpropspec = OLESTR("Name");
  502. // Write this big property
  503. Check( S_OK, pPropStg->WriteMultiple( 1, &cpropspec, &propvar, PID_FIRST_USABLE ));
  504. // Create a slightly too large property set.
  505. PropVariantClear( &propvar );
  506. delete propvar.blob.pBlobData;
  507. propvar.vt = VT_BLOB;
  508. propvar.blob.cbSize = 1024 * 1024;
  509. propvar.blob.pBlobData = new BYTE[ propvar.blob.cbSize ];
  510. Check( FALSE, NULL == propvar.blob.pBlobData );
  511. // Write this too-big property
  512. Check( STG_E_MEDIUMFULL, pPropStg->WriteMultiple( 1, &cpropspec, &propvar, PID_FIRST_USABLE ));
  513. delete propvar.blob.pBlobData;
  514. RELEASE_INTERFACE( pPropStg );
  515. }
  516. void
  517. test_VersionOneNames( IStorage *pstg )
  518. {
  519. FMTID fmtidInsensitive, fmtidSensitive, fmtidLongNames;
  520. IPropertySetStorage *pPropSetStg = NULL;
  521. IPropertyStorage *pPropStg = NULL;
  522. STATPROPSETSTG statpropsetstg;
  523. CPropSpec rgcpropspec[2];
  524. CPropVariant rgcpropvarWrite[2], rgcpropvarRead[2];
  525. LPOLESTR rgposzNames[2] = { NULL, NULL };
  526. PROPID rgpropid[2] = { PID_FIRST_USABLE, PID_FIRST_USABLE+1 };
  527. Status( "PROPSETFLAG_CASE_SENSITIVE flag and long names\n" );
  528. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  529. UuidCreate( &fmtidInsensitive );
  530. UuidCreate( &fmtidSensitive );
  531. UuidCreate( &fmtidLongNames );
  532. // Make two passes, Unicode first, then Ansi.
  533. for( int iPass = 0; iPass < 2; iPass++ )
  534. {
  535. DWORD propsetflagAnsi = 0 == iPass ? 0 : PROPSETFLAG_ANSI;
  536. ULONG cbLongPropertyName = 1020 * 1024;
  537. ULONG cchLongPropertyName = 0 == iPass ? cbLongPropertyName/sizeof(OLECHAR) : cbLongPropertyName;
  538. // ------------------------
  539. // Case insensitive propset
  540. // ------------------------
  541. Check( S_OK, pPropSetStg->Create( fmtidInsensitive, NULL,
  542. PROPSETFLAG_DEFAULT | propsetflagAnsi,
  543. STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  544. &pPropStg ));
  545. // This should still be a version zero (original) propery set.
  546. CheckFormatVersion( pPropStg, 0);
  547. rgcpropspec[0] = OLESTR("Name");
  548. rgcpropspec[1] = OLESTR("name");
  549. rgcpropvarWrite[0] = (long) 0;
  550. rgcpropvarWrite[1] = (short) 1;
  551. // Write two properties with the same name (their the same because this is a
  552. // case-insensitive property set).
  553. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  554. // Read the names back.
  555. Check( S_OK, pPropStg->ReadPropertyNames( 2, rgpropid, rgposzNames ));
  556. // Since we really only wrote one property, we should only get one name back
  557. // Note that we get back the first name, but it's the second value!
  558. Check( 0, ocscmp( rgcpropspec[0].lpwstr, rgposzNames[0] ));
  559. Check( TRUE, NULL == rgposzNames[1] );
  560. delete[] rgposzNames[0];
  561. rgposzNames[0] = NULL;
  562. // Double check that we really one wrote one property (the second).
  563. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  564. Check( TRUE, VT_I2 == rgcpropvarRead[0].VarType() && rgcpropvarRead[0] == CPropVariant((short) 1) );
  565. Check( TRUE, VT_I2 == rgcpropvarRead[1].VarType() && rgcpropvarRead[1] == CPropVariant((short) 1) );
  566. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  567. Check( 0, statpropsetstg.grfFlags & PROPSETFLAG_CASE_SENSITIVE );
  568. RELEASE_INTERFACE( pPropStg );
  569. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  570. // ----------------------
  571. // Case sensitive propset
  572. // ----------------------
  573. Check( S_OK, pPropSetStg->Create( fmtidSensitive, NULL,
  574. PROPSETFLAG_CASE_SENSITIVE | propsetflagAnsi,
  575. STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  576. &pPropStg ));
  577. // Case-sensitivity requires a version 1 property set.
  578. CheckFormatVersion( pPropStg, 1 );
  579. // Write the two names that differ only by case.
  580. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  581. // Read the names back and validate.
  582. Check( S_OK, pPropStg->ReadPropertyNames( 2, rgpropid, rgposzNames ));
  583. Check( TRUE, !ocscmp( rgcpropspec[0].lpwstr, rgposzNames[0] ));
  584. Check( TRUE, !ocscmp( rgcpropspec[1].lpwstr, rgposzNames[1] ));
  585. delete[] rgposzNames[0]; rgposzNames[0] = NULL;
  586. delete[] rgposzNames[1]; rgposzNames[1] = NULL;
  587. // Read the values and validate them too.
  588. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  589. Check( TRUE, VT_I4 == rgcpropvarRead[0].VarType() && rgcpropvarRead[0] == CPropVariant((long) 0) );
  590. Check( TRUE, VT_I2 == rgcpropvarRead[1].VarType() && rgcpropvarRead[1] == CPropVariant((short) 1) );
  591. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  592. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  593. Check( PROPSETFLAG_CASE_SENSITIVE, statpropsetstg.grfFlags & PROPSETFLAG_CASE_SENSITIVE );
  594. RELEASE_INTERFACE( pPropStg );
  595. // -----------------------
  596. // Propset with long names
  597. // -----------------------
  598. Check( S_OK, pPropSetStg->Create( fmtidLongNames, NULL,
  599. PROPSETFLAG_DEFAULT | propsetflagAnsi,
  600. STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  601. &pPropStg ));
  602. // So far we haven't done anything that requires a post-original property set.
  603. CheckFormatVersion( pPropStg, 0 );
  604. // Write a short name, validate it, and validate that the format version doesn't change.
  605. rgcpropspec[0] = OLESTR("A short name");
  606. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  607. Check( S_OK, pPropStg->ReadPropertyNames( 1, rgpropid, rgposzNames )); // PROPID == 2
  608. Check( TRUE, !ocscmp( rgcpropspec[0].lpwstr, rgposzNames[0] ));
  609. CheckFormatVersion( pPropStg, 0 );
  610. delete[] rgposzNames[0]; rgposzNames[0] = NULL;
  611. // Now create a really, really, long name.
  612. rgcpropspec[0].Alloc( cchLongPropertyName );
  613. for( ULONG i = 0; i < cchLongPropertyName; i++ )
  614. rgcpropspec[0][i] = OLESTR('a') + ( static_cast<OLECHAR>(i) % 26 );
  615. rgcpropspec[0][cchLongPropertyName-1] = OLESTR('\0');
  616. // Write this long name.
  617. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  618. // The property set's format version should have been automatically bumped up.
  619. CheckFormatVersion( pPropStg, 1);
  620. // Read the property using the long name
  621. Check( S_OK, pPropStg->ReadMultiple( 1, rgcpropspec, rgcpropvarRead ));
  622. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  623. rgcpropvarRead[0].Clear();
  624. // Read and validate the property name.
  625. Check( S_OK, pPropStg->ReadPropertyNames( 1, &rgpropid[1], rgposzNames )); // PROPID == 3
  626. Check( TRUE, !ocscmp( rgcpropspec[0].lpwstr, rgposzNames[0] ));
  627. delete[] rgposzNames[0]; rgposzNames[0] = NULL;
  628. // Try to write a long, different name.
  629. rgcpropspec[0][0] = OLESTR('#');
  630. Check( STG_E_MEDIUMFULL, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  631. RELEASE_INTERFACE( pPropStg );
  632. } // for( int iPass = 0; iPass < 2; iPass++ )
  633. RELEASE_INTERFACE( pPropSetStg );
  634. } // test_VersionOneNames()
  635. void
  636. test_MultipleReader( LPOLESTR ocsDir )
  637. {
  638. OLECHAR ocsFile[ MAX_PATH ];
  639. IPropertyBagEx *pBag1 = NULL, *pBag2 = NULL;
  640. CPropVariant rgcpropvarRead1[ CPROPERTIES_ALL ], rgcpropvarRead2[ CPROPERTIES_ALL ];
  641. OLECHAR oszPropertyName[] = OLESTR("Simple property");
  642. IEnumSTATPROPBAG *penum = NULL;
  643. STATPROPBAG rgstatpropbag[ CPROPERTIES_ALL + 1];
  644. ULONG cEnum = 0;
  645. Status( "Multiple stgm_read|stgm_deny_write\n" );
  646. ocscpy( ocsFile, ocsDir );
  647. ocscat( ocsFile, OLESTR("test_MultipleReader") );
  648. Check( S_OK, g_pfnStgCreateStorageEx( ocsFile,
  649. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  650. DetermineStgFmt( g_enumImplementation ),
  651. 0L, NULL, NULL,
  652. IID_IPropertyBagEx,
  653. reinterpret_cast<void**>(&pBag1) ));
  654. Check( S_OK, pBag1->WriteMultiple( CPROPERTIES_ALL,
  655. g_rgoszpropnameAll,
  656. g_rgcpropvarAll ));
  657. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  658. Check( 0, RELEASE_INTERFACE(pBag1) );
  659. Check( S_OK, g_pfnStgOpenStorageEx( ocsFile,
  660. STGM_READ | STGM_SHARE_DENY_WRITE,
  661. STGFMT_ANY,
  662. 0L, NULL, NULL,
  663. IID_IPropertyBagEx,
  664. reinterpret_cast<void**>(&pBag1) ));
  665. Check( S_OK, g_pfnStgOpenStorageEx( ocsFile,
  666. STGM_READ | STGM_SHARE_DENY_WRITE,
  667. STGFMT_ANY,
  668. 0L, NULL, NULL,
  669. IID_IPropertyBagEx,
  670. reinterpret_cast<void**>(&pBag2) ));
  671. Check( S_OK, pBag2->Enum( NULL, 0, &penum )); //OLESTR(""), 0, &penum ));
  672. Check( S_OK, penum->Next( CPROPERTIES_ALL, rgstatpropbag, &cEnum ));
  673. Check( CPROPERTIES_ALL, cEnum );
  674. Check( S_OK, pBag1->ReadMultiple( CPROPERTIES_ALL, g_rgoszpropnameAll,
  675. rgcpropvarRead1, NULL ));
  676. Check( S_OK, pBag2->ReadMultiple( CPROPERTIES_ALL, g_rgoszpropnameAll,
  677. rgcpropvarRead2, NULL ));
  678. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  679. {
  680. Check( TRUE, rgcpropvarRead1[i] == g_rgcpropvarAll[i] );
  681. Check( TRUE, rgcpropvarRead2[i] == g_rgcpropvarAll[i] );
  682. delete[] rgstatpropbag[i].lpwstrName;
  683. rgstatpropbag[i].lpwstrName = NULL;
  684. }
  685. Check( 0, RELEASE_INTERFACE(penum) );
  686. Check( 0, RELEASE_INTERFACE(pBag1) );
  687. Check( 0, RELEASE_INTERFACE(pBag2) );
  688. return;
  689. } // test_MultipleReader
  690. void
  691. test_Robustness(OLECHAR *poszDir)
  692. {
  693. if( PROPIMP_NTFS != g_enumImplementation ) return;
  694. Status( "NTFS property set robustness\n" );
  695. HRESULT hr = S_OK;
  696. IStorage *pStorage = NULL;
  697. IPropertySetStorage *pPropSetStg = NULL;
  698. IPropertyStorage *pPropStg = NULL;
  699. IStorageTest *pPropStgTest = NULL;
  700. IStream *pStm = NULL;
  701. FMTID fmtid;
  702. STATSTG statstg;
  703. OLECHAR oszFile[ MAX_PATH ];
  704. OLECHAR oszName[ MAX_PATH ];
  705. OLECHAR oszUpdateName[ MAX_PATH ];
  706. CPropSpec rgcpropspec[2];
  707. CPropVariant rgcpropvarWrite[2], rgcpropvarRead[2];
  708. ocscpy( oszFile, poszDir );
  709. ocscat( oszFile, OLESTR("test_Robustness") );
  710. // Create a property set and put a property into it.
  711. Check( S_OK, g_pfnStgCreateStorageEx( oszFile, STGM_READWRITE|STGM_CREATE|STGM_SHARE_EXCLUSIVE,
  712. DetermineStgFmt(g_enumImplementation),
  713. 0, NULL, NULL,
  714. DetermineStgIID( g_enumImplementation ),
  715. reinterpret_cast<void**>(&pStorage) ));
  716. Check( S_OK, pStorage->QueryInterface( IID_IPropertySetStorage,
  717. reinterpret_cast<void**>(&pPropSetStg) ));
  718. UuidCreate( &fmtid );
  719. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT,
  720. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  721. &pPropStg ));
  722. rgcpropspec[0] = OLESTR("Property Name");
  723. rgcpropspec[1] = OLESTR("Second property name");
  724. rgcpropvarWrite[0] = static_cast<long>(23);
  725. rgcpropvarWrite[1] = OLESTR("Second property value");
  726. Check( S_OK, pPropStg->WriteMultiple( 1, &rgcpropspec[0], &rgcpropvarWrite[0], PID_FIRST_USABLE ));
  727. Check( 0, RELEASE_INTERFACE(pPropStg) );
  728. // Rename the property set's stream to "Updt_*", and create any empty stream
  729. // in its place. This simulates a crash during the flush of a property set.
  730. RtlGuidToPropertySetName( &fmtid, oszName );
  731. oszName[ 0 ] = OC_PROPSET0;
  732. wcscpy( oszUpdateName, OLESTR("Updt_") );
  733. wcscat( oszUpdateName, oszName );
  734. Check( S_OK, pStorage->RenameElement( oszName, oszUpdateName ));
  735. Check( S_OK, pStorage->CreateStream( oszName, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &pStm ));
  736. Check( 0, RELEASE_INTERFACE(pStm) );
  737. // Open the property set in read-only mode, and verify that we can still ready
  738. // the property. Since we're opening in read-only, the streams should remain
  739. // unchanged.
  740. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  741. Check( S_OK, pPropStg->ReadMultiple( 1, &rgcpropspec[0], &rgcpropvarRead[0] ));
  742. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  743. Check( 0, RELEASE_INTERFACE(pPropStg) );
  744. // Verify that the streams do not appear to have been changed.
  745. Check( S_OK, pStorage->OpenStream( oszName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  746. Check( S_OK, pStm->Stat( &statstg, STATFLAG_NONAME ));
  747. Check( TRUE, CULargeInteger(0) == CULargeInteger(statstg.cbSize) );
  748. Check( 0, RELEASE_INTERFACE(pStm) );
  749. Check( S_OK, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  750. Check( S_OK, pStm->Stat( &statstg, STATFLAG_NONAME ));
  751. Check( FALSE, CULargeInteger(0) == CULargeInteger(statstg.cbSize) );
  752. Check( 0, RELEASE_INTERFACE(pStm) );
  753. // Now open the property set for write. This should cause the problem to be fixed.
  754. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  755. // Read the property back
  756. Check( S_OK, pPropStg->ReadMultiple( 1, &rgcpropspec[0], &rgcpropvarRead[0] ));
  757. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  758. // Write another property and read both properties back
  759. Check( S_OK, pPropStg->WriteMultiple( 1, &rgcpropspec[1], &rgcpropvarWrite[1], PID_FIRST_USABLE ));
  760. Check( S_OK, pPropStg->ReadMultiple( 2, &rgcpropspec[0], &rgcpropvarRead[0] ));
  761. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  762. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  763. rgcpropvarRead[1].Clear();
  764. Check( 0, RELEASE_INTERFACE(pPropStg) );
  765. // Verify that the streams look corrected.
  766. Check( S_OK, pStorage->OpenStream( oszName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  767. Check( S_OK, pStm->Stat( &statstg, STATFLAG_NONAME ));
  768. Check( TRUE, CULargeInteger(0) != CULargeInteger(statstg.cbSize) );
  769. Check( 0, RELEASE_INTERFACE(pStm) );
  770. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  771. // Write/read after disabling the stream-rename
  772. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE, &pPropStg ));
  773. hr = pPropStg->QueryInterface( IID_IStorageTest, reinterpret_cast<void**>(&pPropStgTest) );
  774. if( SUCCEEDED(hr) )
  775. Check( S_OK, pPropStgTest->UseNTFS4Streams( TRUE ));
  776. if( E_NOINTERFACE == hr )
  777. {
  778. Status( " ... Partially skipping, IStorageTest not available (free build?)\n" );
  779. }
  780. else
  781. {
  782. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  783. Check( S_OK, pPropStg->WriteMultiple( 2, &rgcpropspec[0], &rgcpropvarWrite[0], PID_FIRST_USABLE ));
  784. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  785. Check( S_OK, pPropStg->Commit( STGC_DEFAULT ));
  786. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  787. RELEASE_INTERFACE( pPropStgTest );
  788. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  789. Check( 0, RELEASE_INTERFACE(pPropStg) );
  790. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READ|STGM_SHARE_DENY_WRITE, &pPropStg ));
  791. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  792. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  793. Check( STG_E_FILENOTFOUND, pStorage->OpenStream( oszUpdateName, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStm ));
  794. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  795. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  796. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  797. }
  798. // Write to the property set, then cause it to be shutdown and reverted.
  799. Check( 0, RELEASE_INTERFACE(pPropStg) );
  800. Check( S_OK, pPropSetStg->Open( fmtid, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, &pPropStg ));
  801. rgcpropvarWrite[0] = OLESTR("Hello");
  802. rgcpropvarWrite[1] = OLESTR("World");
  803. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  804. RELEASE_INTERFACE(pPropSetStg);
  805. Check( 0, RELEASE_INTERFACE(pStorage) ); // Should flush the properties
  806. Check( STG_E_REVERTED, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  807. Check( 0, RELEASE_INTERFACE(pPropStg) );
  808. Check( S_OK, g_pfnStgOpenStorageEx( oszFile, STGM_READ|STGM_SHARE_DENY_WRITE,
  809. STGFMT_ANY,
  810. 0, NULL, NULL,
  811. IID_IPropertySetStorage,
  812. reinterpret_cast<void**>(&pPropSetStg) ));
  813. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  814. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  815. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  816. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  817. Check( 0, RELEASE_INTERFACE(pPropStg) );
  818. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  819. //
  820. // Exit
  821. //
  822. RELEASE_INTERFACE(pPropSetStg);
  823. g_pfnFreePropVariantArray( 2, rgcpropvarWrite );
  824. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  825. } // test_Robustness
  826. void
  827. test_EmptyBag( OLECHAR *poszDir )
  828. {
  829. OLECHAR oszFile[ MAX_PATH ];
  830. IStorage *pstg = NULL;
  831. IPropertyBagEx *pbag = NULL;
  832. PROPVARIANT propvar;
  833. IEnumSTATPROPBAG *penum = NULL;
  834. STATPROPBAG statpropbag;
  835. ULONG cFetched;
  836. ocscpy( oszFile, poszDir );
  837. ocscat( oszFile, OLESTR("test_EmptyBag") );
  838. Check( S_OK, g_pfnStgCreateStorageEx( oszFile,
  839. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  840. DetermineStgFmt( g_enumImplementation ),
  841. 0L,
  842. NULL,
  843. NULL,
  844. IID_IPropertyBagEx,
  845. (void**) &pbag ));
  846. PropVariantInit( &propvar );
  847. OLECHAR *poszName = OLESTR("test");
  848. Check( S_FALSE, pbag->ReadMultiple( 1, &poszName, &propvar, NULL ));
  849. Check( VT_EMPTY, propvar.vt );
  850. Check( S_OK, pbag->Enum( OLESTR(""), 0, &penum ));
  851. Check( S_FALSE, penum->Next( 1, &statpropbag, &cFetched ));
  852. Check( 0, cFetched );
  853. Check( 0, RELEASE_INTERFACE(penum));
  854. Check( 0, RELEASE_INTERFACE(pbag));
  855. } // test_EmptyBag
  856. void
  857. test_BagDelete( IStorage *pstg )
  858. {
  859. HRESULT hr = S_OK;
  860. IPropertyBagEx *pbag = NULL;
  861. IEnumSTATPROPBAG* penum = NULL;
  862. ULONG cFetched;
  863. ULONG i, j;
  864. OLECHAR * rgoszDelete[2];
  865. // Note that some of these names only differ by case, which is legal in a bag
  866. OLECHAR *rgoszNames[] = { OLESTR("www.microsoft.com/bag/test?prop1"),
  867. OLESTR("www.microsoft.com/bag/test?PROP1"),
  868. OLESTR("www.microsoft.com/bag/2test?prop1"),
  869. OLESTR("www.microsoft.com/bag2/test?prop1") };
  870. CPropVariant rgcpropvarRead[ ELEMENTS(rgoszNames) + 1 ];
  871. STATPROPBAG rgstatpropbag[ ELEMENTS(rgoszNames) + 1 ];
  872. Status( "Property bag deletions\n" );
  873. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  874. DeleteBagExProperties( pbag, OLESTR("") );
  875. // ------------------------------------------
  876. // Delete bag2/test?prop1 by name & by prefix
  877. // ------------------------------------------
  878. for( i = 0; i < 2; i++ )
  879. {
  880. ULONG cFetchedExpected;
  881. switch(i)
  882. {
  883. case 0:
  884. // Delete by name
  885. rgoszDelete[0] = OLESTR("www.microsoft.com/bag2/test?prop1");
  886. cFetchedExpected = ELEMENTS(rgoszNames) - 1;
  887. break;
  888. case 1:
  889. // Delete by prefix
  890. rgoszDelete[0] = OLESTR("www.microsoft.com/bag2/test");
  891. cFetchedExpected = ELEMENTS(rgoszNames) - 1;
  892. break;
  893. default:
  894. Check( FALSE, TRUE ); //Check( FALSE, 0 == OLESTR("Invalid switch") );
  895. } // switch(i)
  896. Check( S_OK, pbag->WriteMultiple( ELEMENTS(rgoszNames), rgoszNames, g_rgcpropvarAll ));
  897. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  898. DeleteBagExProperties( pbag, rgoszDelete[0] );
  899. Check( S_OK, pbag->Enum( OLESTR(""), 0, &penum ));
  900. Check( ELEMENTS(rgoszNames) == cFetchedExpected ? S_OK : S_FALSE,
  901. penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  902. Check( TRUE, cFetchedExpected == cFetched );
  903. RELEASE_INTERFACE(penum);
  904. for( j = 0; j < cFetched; j++ )
  905. {
  906. Check( TRUE, !wcscmp(rgoszNames[j], rgstatpropbag[j].lpwstrName) );
  907. delete [] rgstatpropbag[j].lpwstrName;
  908. }
  909. } // for( i = 0; i < 2; i++ )
  910. // -----------------------------------------------
  911. // Delete the two "/bag/test" properties by prefix
  912. // -----------------------------------------------
  913. rgoszDelete[0] = OLESTR("www.microsoft.com/bag/test");
  914. Check( S_OK, pbag->WriteMultiple( ELEMENTS(rgoszNames), rgoszNames, g_rgcpropvarAll ));
  915. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  916. DeleteBagExProperties( pbag, rgoszDelete[0] );
  917. Check( S_OK, pbag->Enum( OLESTR(""), 0, &penum ));
  918. Check( S_FALSE, penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  919. Check( TRUE, 2 == cFetched );
  920. RELEASE_INTERFACE(penum);
  921. for( j = 0; j < cFetched; j++ )
  922. {
  923. Check( TRUE, !wcscmp(rgoszNames[j+2], rgstatpropbag[j].lpwstrName) );
  924. delete [] rgstatpropbag[j].lpwstrName;
  925. }
  926. /*
  927. // -------------------------
  928. // Delete all the properties
  929. // -------------------------
  930. rgoszDelete[0] = NULL;
  931. Check( S_OK, pbag->WriteMultiple( ELEMENTS(rgoszNames), rgoszNames, g_rgcpropvarAll ));
  932. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  933. Check( S_OK, pbag->Delete( OLESTR(""), DELETEPROPERTY_MASK));
  934. Check( S_OK, pbag->Enum( OLESTR(""), 0, &penum ));
  935. Check( S_FALSE, penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  936. Check( TRUE, 0 == cFetched );
  937. RELEASE_INTERFACE(penum);
  938. */
  939. pbag->Release();
  940. } // test_BagDelete
  941. void
  942. test_IPropertyBag( IStorage *pstg )
  943. {
  944. Status( "IPropertyBag\n" );
  945. IPropertyBagEx *pbagex = NULL;
  946. IPropertyBag *pbag = NULL;
  947. ULONG cRefsOriginal = GetRefCount( pstg );
  948. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbagex) ));
  949. DeleteBagExProperties( pbagex, OLESTR("") );
  950. RELEASE_INTERFACE(pbagex);
  951. Check( S_OK, pstg->QueryInterface( IID_IPropertyBag, reinterpret_cast<void**>(&pbag) ));
  952. VARIANT varWrite, varRead;
  953. VariantInit( &varWrite );
  954. VariantInit( &varRead );
  955. varWrite.vt = VT_I4;
  956. varWrite.lVal = 1234;
  957. Check( S_OK, pbag->Write( OLESTR("Variant I4"), &varWrite ));
  958. Check( S_OK, pbag->Read( OLESTR("Variant I4"), &varRead, NULL ));
  959. Check( TRUE, varWrite.vt == varRead.vt );
  960. Check( TRUE, varWrite.lVal == varRead.lVal );
  961. Check( cRefsOriginal, RELEASE_INTERFACE(pbag) );
  962. }
  963. void
  964. test_BagVtUnknown( IStorage *pstg )
  965. {
  966. HRESULT hr = S_OK;
  967. IPropertyBagEx *pbag = NULL;
  968. ULONG cRefsOriginal = 0;
  969. Status( "VT_UNKNOWN in an IPropertyBagEx\n" );
  970. pstg->AddRef();
  971. cRefsOriginal = pstg->Release();
  972. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  973. DeleteBagExProperties( pbag, OLESTR("") );
  974. CObjectWithPersistStorage *pStgObjectWritten = NULL, *pStgObjectRead = NULL;
  975. CObjectWithPersistStream *pStmObjectWritten = NULL, *pStmObjectRead = NULL;
  976. pStgObjectWritten = new CObjectWithPersistStorage( OLESTR("VtUnknown-Storage") );
  977. pStgObjectRead = new CObjectWithPersistStorage();
  978. pStmObjectWritten = new CObjectWithPersistStream( OLESTR("VtUnknown-Stream") );
  979. pStmObjectRead = new CObjectWithPersistStream();
  980. Check( TRUE, NULL != pStgObjectWritten && NULL != pStgObjectRead );
  981. Check( TRUE, NULL != pStmObjectWritten && NULL != pStmObjectRead );
  982. VARIANT rgvarRead[2], rgvarWritten[2];
  983. VariantInit( &rgvarRead[0] );
  984. VariantInit( &rgvarRead[1] );
  985. VariantInit( &rgvarWritten[0] );
  986. VariantInit( &rgvarWritten[1] );
  987. rgvarWritten[0].vt = VT_UNKNOWN;
  988. rgvarWritten[0].punkVal = static_cast<IUnknown*>(pStgObjectWritten);
  989. rgvarWritten[1].vt = VT_BYREF | VT_UNKNOWN;
  990. IUnknown *punkByRefVal = static_cast<IUnknown*>(pStmObjectWritten);
  991. rgvarWritten[1].ppunkVal = &punkByRefVal;
  992. rgvarRead[0].vt = VT_UNKNOWN;
  993. rgvarRead[0].punkVal = static_cast<IUnknown*>(pStgObjectRead);
  994. rgvarRead[1].vt = VT_UNKNOWN;
  995. rgvarRead[1].punkVal = static_cast<IUnknown*>(pStmObjectRead);
  996. OLECHAR *rgoszName[2] = { OLESTR("VtUnknown (persisted as Storage)"),
  997. OLESTR("ByRef VtUnknown (persisted as Stream)") };
  998. Check( S_OK, pbag->WriteMultiple( 2, rgoszName, reinterpret_cast<PROPVARIANT*>(rgvarWritten) ));
  999. Check( S_OK, pbag->ReadMultiple( 2, rgoszName, reinterpret_cast<PROPVARIANT*>(rgvarRead), NULL ));
  1000. Check( TRUE, *pStgObjectRead == *pStgObjectWritten );
  1001. Check( TRUE, *pStmObjectRead == *pStmObjectWritten );
  1002. Check( 0, RELEASE_INTERFACE( pStgObjectRead ));
  1003. Check( 0, RELEASE_INTERFACE( pStmObjectRead ));
  1004. PROPVARIANT rgpropvarReadRaw[2];
  1005. PropVariantInit( &rgpropvarReadRaw[0] );
  1006. PropVariantInit( &rgpropvarReadRaw[1] );
  1007. Check( S_OK, pbag->ReadMultiple( 2, rgoszName, rgpropvarReadRaw, NULL ));
  1008. Check( VT_STORED_OBJECT, rgpropvarReadRaw[0].vt );
  1009. Check( VT_STREAMED_OBJECT, rgpropvarReadRaw[1].vt );
  1010. STATSTG statstg;
  1011. Check( S_OK, rgpropvarReadRaw[0].pStorage->Stat( &statstg, STATFLAG_NONAME ));
  1012. Check( TRUE, statstg.clsid == pStgObjectWritten->GetClassID() );
  1013. Check( 0, RELEASE_INTERFACE( pStgObjectWritten ));
  1014. Check( S_OK, PropVariantClear( &rgpropvarReadRaw[0] ));
  1015. CLSID clsid;
  1016. ULONG cbRead;
  1017. Check( S_OK, rgpropvarReadRaw[1].pStream->Read( &clsid, sizeof(clsid), &cbRead ));
  1018. Check( sizeof(clsid), cbRead );
  1019. Check( TRUE, clsid == pStmObjectWritten->GetClassID() );
  1020. Check( 0, RELEASE_INTERFACE( pStmObjectWritten ));
  1021. Check( S_OK, PropVariantClear( &rgpropvarReadRaw[1] ));
  1022. Check( cRefsOriginal, RELEASE_INTERFACE(pbag) );
  1023. } // test_BagVtUnknown
  1024. void
  1025. test_BagEnum( IStorage *pstg )
  1026. {
  1027. IPropertyBagEx *pbag = NULL;
  1028. IEnumSTATPROPBAG *penum = NULL;
  1029. ULONG cFetched;
  1030. ULONG i;
  1031. const OLECHAR * rgoszDelete[] = { OLESTR("") };
  1032. const OLECHAR *rgoszNames[] = { OLESTR("www.microsoft.com/bag/test?prop1"),
  1033. OLESTR("www.microsoft.com/bag/test?prop2"),
  1034. OLESTR("www.microsoft.com/bag/2test?prop1"),
  1035. OLESTR("www.microsoft.com/bag2/test?prop1") };
  1036. STATPROPBAG rgstatpropbag[ ELEMENTS(rgoszNames) + 1 ];
  1037. Status( "Property bag enumeration\n" );
  1038. // Initialize the bag
  1039. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1040. DeleteBagExProperties( pbag, OLESTR("") );
  1041. Check( S_OK, pbag->WriteMultiple( ELEMENTS(rgoszNames), rgoszNames, g_rgcpropvarAll ));
  1042. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  1043. // Try to enum n+1 elements (to get an S_FALSE)
  1044. Check( S_OK, pbag->Enum( NULL, 0, &penum ));
  1045. Check( S_FALSE, penum->Next( ELEMENTS(rgstatpropbag), rgstatpropbag, &cFetched ));
  1046. Check( TRUE, ELEMENTS(rgoszNames) == cFetched );
  1047. for( i = 0; i < cFetched; i++ )
  1048. delete [] rgstatpropbag[i].lpwstrName;
  1049. RELEASE_INTERFACE(penum);
  1050. // Try to enum n elements (should get an S_OK)
  1051. Check( S_OK, pbag->Enum( OLESTR(""), 0, &penum ));
  1052. Check( S_OK, penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  1053. Check( TRUE, ELEMENTS(rgoszNames) == cFetched );
  1054. for( i = 0; i < cFetched; i++ )
  1055. delete [] rgstatpropbag[i].lpwstrName;
  1056. RELEASE_INTERFACE(penum);
  1057. // Enum a subset
  1058. Check( S_OK, pbag->Enum( OLESTR("www.microsoft.com/bag/test"), 0, &penum ));
  1059. Check( S_FALSE, penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  1060. Check( TRUE, 2 == cFetched );
  1061. for( i = 0; i < cFetched; i++ )
  1062. delete [] rgstatpropbag[i].lpwstrName;
  1063. RELEASE_INTERFACE(penum);
  1064. // Enum a non-extant subset
  1065. Check( S_OK, pbag->Enum( OLESTR("dummy"), 0, &penum ));
  1066. Check( S_FALSE, penum->Next( ELEMENTS(rgoszNames), rgstatpropbag, &cFetched ));
  1067. Check( TRUE, 0 == cFetched );
  1068. RELEASE_INTERFACE(penum);
  1069. // Enum a single property
  1070. Check( S_OK, pbag->Enum( OLESTR("www.microsoft.com/bag/test?prop1"), 0, &penum ));
  1071. Check( S_FALSE, penum->Next( 2, rgstatpropbag, &cFetched ));
  1072. Check( 1, cFetched );
  1073. delete[] rgstatpropbag[0].lpwstrName;
  1074. rgstatpropbag[0].lpwstrName = NULL;
  1075. RELEASE_INTERFACE(penum);
  1076. RELEASE_INTERFACE(pbag);
  1077. } // test_BagEnum
  1078. void
  1079. test_BagCoercion( IStorage *pstg )
  1080. {
  1081. IPropertyBag *pbag = NULL;
  1082. IPropertyBagEx *pbagX = NULL;
  1083. const OLECHAR *rgosz[2];
  1084. PROPVARIANT rgpropvar[2];
  1085. Status( "Property bag coercion\n" );
  1086. // Get a bag and a bagex, and clean the bag.
  1087. Check( S_OK, pstg->QueryInterface( IID_IPropertyBag,
  1088. reinterpret_cast<void**>(&pbag) ));
  1089. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx,
  1090. reinterpret_cast<void**>(&pbagX) ));
  1091. DeleteBagExProperties( pbagX, OLESTR("") );
  1092. // Initialize the bag with some properties
  1093. rgpropvar[0].vt = VT_I2;
  1094. rgpropvar[0].iVal = 2;
  1095. rgosz[0] = OLESTR("www.microsoft.com/test/i2");
  1096. rgpropvar[1].vt = VT_UI2;
  1097. rgpropvar[1].uiVal = 3;
  1098. rgosz[1] = OLESTR("www.microsoft.com/test/ui2");
  1099. Check( S_OK, pbagX->WriteMultiple( 2, rgosz, rgpropvar ));
  1100. g_pfnFreePropVariantArray( 2, rgpropvar );
  1101. // Read back the properties as (U)I4s with explicit coercion
  1102. rgpropvar[0].vt = VT_I4;
  1103. rgpropvar[1].vt = VT_UI4;
  1104. Check( S_OK, pbagX->ReadMultiple( 2, rgosz, rgpropvar, NULL ));
  1105. Check( TRUE, VT_I4 == rgpropvar[0].vt && 2 == rgpropvar[0].lVal );
  1106. Check( TRUE, VT_UI4 == rgpropvar[1].vt && 3 == rgpropvar[1].ulVal );
  1107. // This is an unrelated test, but while we're here, let's verify that we
  1108. // can't write a PropVariant (non-Variant) type through the Bag interface.
  1109. rgpropvar[0].vt= VT_I8;
  1110. rgpropvar[0].hVal.QuadPart = 1;
  1111. Check( STG_E_INVALIDPARAMETER, pbag->Write( rgosz[0],
  1112. reinterpret_cast<VARIANT*>(&rgpropvar[0]) ));
  1113. //--------
  1114. rgpropvar[0].vt = VT_LPSTR;
  1115. rgpropvar[0].pszVal = "Hello, world";
  1116. rgpropvar[1].vt = VT_I4;
  1117. rgpropvar[1].iVal = 123;
  1118. Check( S_OK, pbagX->WriteMultiple( 2, rgosz, rgpropvar ));
  1119. rgpropvar[0].vt = VT_EMPTY;
  1120. rgpropvar[0].pszVal = NULL;
  1121. rgpropvar[1].vt = VT_EMPTY;
  1122. rgpropvar[1].iVal = -1;
  1123. Check( S_OK, pbagX->ReadMultiple( 2, rgosz, rgpropvar, NULL ));
  1124. Check( TRUE, VT_LPSTR == rgpropvar[0].vt
  1125. && 0==strcmp( "Hello, world", rgpropvar[0].pszVal ) );
  1126. Check( TRUE, VT_I4 == rgpropvar[1].vt && 123 == rgpropvar[1].iVal );
  1127. g_pfnFreePropVariantArray( 2, rgpropvar );
  1128. //-------- Coercing Variant to Variant ------------------
  1129. rgpropvar[0].vt = VT_I4;
  1130. rgpropvar[0].lVal = 123;
  1131. rgpropvar[1].vt = VT_I4;
  1132. rgpropvar[1].lVal = 123;
  1133. Check( S_OK, pbagX->WriteMultiple( 2, rgosz, rgpropvar ));
  1134. rgpropvar[0].vt = VT_BSTR;
  1135. rgpropvar[1].vt = VT_I4;
  1136. Check( S_OK, pbagX->ReadMultiple( 2, rgosz, rgpropvar, NULL ));
  1137. Check( TRUE, VT_BSTR == rgpropvar[0].vt
  1138. && !wcscmp( L"123", rgpropvar[0].bstrVal ));
  1139. Check( TRUE, VT_I4 == rgpropvar[1].vt && 123 == rgpropvar[1].iVal );
  1140. g_pfnFreePropVariantArray( 2, rgpropvar );
  1141. //-------- Coercing PropVariant To PropVariant ------------
  1142. #define TEST_I8_VAL ((LONGLONG)1024*1000*1000*1000+42);
  1143. rgpropvar[0].vt = VT_LPWSTR;
  1144. rgpropvar[0].pwszVal = L"-312";
  1145. rgpropvar[1].vt = VT_I8;
  1146. rgpropvar[1].hVal.QuadPart = TEST_I8_VAL;
  1147. Check( S_OK, pbagX->WriteMultiple( 2, rgosz, rgpropvar ));
  1148. rgpropvar[0].vt = VT_I4;
  1149. rgpropvar[0].pszVal = NULL;
  1150. rgpropvar[1].vt = VT_LPWSTR;
  1151. rgpropvar[1].hVal.QuadPart = -1;
  1152. Check( S_OK, pbagX->ReadMultiple(2, rgosz, rgpropvar, NULL ) );
  1153. Check( TRUE, VT_I4 == rgpropvar[0].vt && -312 == rgpropvar[0].lVal );
  1154. Check( TRUE, VT_LPWSTR == rgpropvar[1].vt
  1155. && !wcscmp( L"1024000000042", rgpropvar[1].pwszVal ) );
  1156. g_pfnFreePropVariantArray( 2, rgpropvar );
  1157. //-------- Implcit Coercion PropVariant To Variant ------------
  1158. rgpropvar[0].vt = VT_I8;
  1159. rgpropvar[0].hVal.QuadPart = -666;
  1160. rgpropvar[1].vt = VT_VECTOR | VT_LPSTR;
  1161. rgpropvar[1].calpstr.cElems = 5;
  1162. rgpropvar[1].calpstr.pElems = new LPSTR[5];
  1163. rgpropvar[1].calpstr.pElems[0] = "Thirty Days hath September,";
  1164. rgpropvar[1].calpstr.pElems[1] = "April, June and No Wonder?";
  1165. rgpropvar[1].calpstr.pElems[2] = "All the Rest Have Thirty One";
  1166. rgpropvar[1].calpstr.pElems[3] = "Except my dear Grand Mother.";
  1167. rgpropvar[1].calpstr.pElems[4] = "She Has a Bright Red Tricycle.";
  1168. Check( S_OK, pbagX->WriteMultiple( 2, rgosz, rgpropvar ));
  1169. delete rgpropvar[1].calpstr.pElems;
  1170. PropVariantInit(&rgpropvar[0]);
  1171. PropVariantInit(&rgpropvar[1]);
  1172. rgpropvar[0].vt = VT_EMPTY;
  1173. rgpropvar[1].vt = VT_EMPTY;
  1174. Check( S_OK, pbag->Read(rgosz[0], (VARIANT*)&rgpropvar[0], NULL ) );
  1175. Check( S_OK, pbag->Read(rgosz[1], (VARIANT*)&rgpropvar[1], NULL ) );
  1176. Check( TRUE, VT_I4 == rgpropvar[0].vt && -666 == rgpropvar[0].lVal );
  1177. Check( TRUE, (VT_BSTR|VT_ARRAY) == rgpropvar[1].vt );
  1178. g_pfnFreePropVariantArray( 2, rgpropvar );
  1179. //
  1180. // UnCoercible.
  1181. //
  1182. rgpropvar[0].vt = VT_UNKNOWN;
  1183. rgpropvar[0].iVal = 42; // GARBAGE value; untouched in the error path
  1184. Check( DISP_E_TYPEMISMATCH, pbagX->ReadMultiple( 1, rgosz, rgpropvar, NULL ));
  1185. Check( TRUE, VT_UNKNOWN == rgpropvar[0].vt && 42==rgpropvar[0].iVal );
  1186. RELEASE_INTERFACE(pbagX);
  1187. RELEASE_INTERFACE(pbag);
  1188. } // test_BagCoercion
  1189. #define LOAD_VARIANT(var,vartype,field,value) (var).field = (value); (var).vt = vartype
  1190. void
  1191. test_ByRef( IStorage *pstg )
  1192. {
  1193. HRESULT hr = S_OK;
  1194. IPropertySetStorage *pPropSetStg = NULL;
  1195. IPropertyStorage *pPropStg = NULL;
  1196. FMTID fmtid;
  1197. Status( "ByRef Variants\n" );
  1198. UuidCreate( &fmtid );
  1199. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  1200. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT,
  1201. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1202. &pPropStg ));
  1203. PROPVARIANT rgvarWrite[17], rgvarRead[17];
  1204. CPropSpec rgcpropspec[17];
  1205. BYTE bVal = 1;
  1206. LOAD_VARIANT(rgvarWrite[0], VT_UI1|VT_BYREF, pbVal, &bVal);
  1207. rgcpropspec[0] = OLESTR("VT_UI1|VT_BYREF");
  1208. SHORT iVal = 2;
  1209. LOAD_VARIANT(rgvarWrite[1], VT_I2|VT_BYREF, piVal, &iVal );
  1210. rgcpropspec[1] = OLESTR("VT_I2|VY_BYREF");
  1211. LONG lVal = 3;
  1212. LOAD_VARIANT(rgvarWrite[2], VT_I4|VT_BYREF, plVal, &lVal );
  1213. rgcpropspec[2] = OLESTR("VT_I4|VY_BYREF");
  1214. FLOAT fltVal = (float)4.1;
  1215. LOAD_VARIANT(rgvarWrite[3], VT_R4|VT_BYREF, pfltVal, &fltVal );
  1216. rgcpropspec[3] = OLESTR("VT_I4|VT_BYREF");
  1217. DOUBLE dblVal = 5.2;
  1218. LOAD_VARIANT(rgvarWrite[4], VT_R8|VT_BYREF, pdblVal, &dblVal );
  1219. rgcpropspec[4] = OLESTR("VT_R8|VT_BYREF");
  1220. VARIANT_BOOL boolVal = VARIANT_TRUE;
  1221. LOAD_VARIANT(rgvarWrite[5], VT_BOOL|VT_BYREF, pboolVal, &boolVal );
  1222. rgcpropspec[5] = OLESTR("VT_BOOL|VT_BYREF");
  1223. SCODE scode = 6;
  1224. LOAD_VARIANT(rgvarWrite[6], VT_ERROR|VT_BYREF, pscode, &scode );
  1225. rgcpropspec[6] = OLESTR("VT_ERROR|VT_BYREF");
  1226. CY cyVal = { 7 };
  1227. LOAD_VARIANT(rgvarWrite[7], VT_CY|VT_BYREF, pcyVal, &cyVal );
  1228. rgcpropspec[7] = OLESTR("VT_CY|VT_BYREF");
  1229. DATE date = 8;
  1230. LOAD_VARIANT(rgvarWrite[8], VT_DATE|VT_BYREF, pdate, &date );
  1231. rgcpropspec[8] = OLESTR("VT_DATE|VT_BYREF");
  1232. BSTR bstrVal = SysAllocString( OLESTR("9") );
  1233. LOAD_VARIANT(rgvarWrite[9], VT_BSTR|VT_BYREF, pbstrVal, &bstrVal );
  1234. rgcpropspec[9] = OLESTR("VT_BSTR|VT_BYREF");
  1235. DECIMAL decVal = { 10, 9, 8, 7, 6 };
  1236. LOAD_VARIANT(rgvarWrite[10], VT_DECIMAL|VT_BYREF, pdecVal, &decVal );
  1237. rgcpropspec[10] = OLESTR("VT_DECIMAL|VT_BYREF");
  1238. CHAR cVal = 11;
  1239. LOAD_VARIANT(rgvarWrite[11], VT_I1 | VT_BYREF, pcVal, &cVal );
  1240. rgcpropspec[11] = OLESTR("VT_I1|VT_BYREF");
  1241. USHORT uiVal = 12;
  1242. LOAD_VARIANT(rgvarWrite[12], VT_UI2 | VT_BYREF, puiVal, &uiVal );
  1243. rgcpropspec[12] = OLESTR("VT_UI2|VT_BYREF");
  1244. ULONG ulVal = 13;
  1245. LOAD_VARIANT(rgvarWrite[13], VT_UI4 | VT_BYREF, pulVal, &ulVal );
  1246. rgcpropspec[13] = OLESTR("VT_UI4|VT_BYREF");
  1247. INT intVal = 14;
  1248. LOAD_VARIANT(rgvarWrite[14], VT_INT | VT_BYREF, pintVal, &intVal );
  1249. rgcpropspec[14] = OLESTR("VT_INT|VT_BYREF");
  1250. UINT uintVal = 15;
  1251. LOAD_VARIANT(rgvarWrite[15], VT_UINT | VT_BYREF, puintVal, &uintVal );
  1252. rgcpropspec[15] = OLESTR("VT_UINT | VT_BYREF");
  1253. CPropVariant cpropvarVal = (long) 16;
  1254. Check( VT_I4, cpropvarVal.vt );
  1255. LOAD_VARIANT(rgvarWrite[16], VT_VARIANT| VT_BYREF, pvarVal, &cpropvarVal );
  1256. rgcpropspec[16] = OLESTR("VT_VARIANT | VT_BYREF");
  1257. Check( S_OK, pPropStg->WriteMultiple( sizeof(rgvarWrite)/sizeof(rgvarWrite[0]),
  1258. rgcpropspec,
  1259. reinterpret_cast<PROPVARIANT*>(rgvarWrite),
  1260. PID_FIRST_USABLE ));
  1261. for( int i = 0; i < sizeof(rgvarRead)/sizeof(rgvarRead[0]); i++ )
  1262. PropVariantInit( &rgvarRead[i] );
  1263. Check( S_OK, pPropStg->ReadMultiple( sizeof(rgvarRead)/sizeof(rgvarRead[0]),
  1264. rgcpropspec,
  1265. reinterpret_cast<PROPVARIANT*>(rgvarRead) ));
  1266. Check( VT_UI1, rgvarRead[0].vt );
  1267. Check( TRUE, rgvarRead[0].bVal == *rgvarWrite[0].pbVal );
  1268. Check( VT_I2, rgvarRead[1].vt );
  1269. Check( TRUE, rgvarRead[1].iVal == *rgvarWrite[1].piVal );
  1270. Check( VT_I4, rgvarRead[2].vt );
  1271. Check( TRUE, rgvarRead[2].lVal == *rgvarWrite[2].plVal );
  1272. Check( VT_R4, rgvarRead[3].vt );
  1273. Check( TRUE, rgvarRead[3].fltVal == *rgvarWrite[3].pfltVal );
  1274. Check( VT_R8, rgvarRead[4].vt );
  1275. Check( TRUE, rgvarRead[4].dblVal == *rgvarWrite[4].pdblVal );
  1276. Check( VT_BOOL, rgvarRead[5].vt );
  1277. Check( TRUE, rgvarRead[5].boolVal == *rgvarWrite[5].pboolVal );
  1278. Check( VT_ERROR, rgvarRead[6].vt );
  1279. Check( TRUE, rgvarRead[6].scode == *rgvarWrite[6].pscode );
  1280. Check( VT_CY, rgvarRead[7].vt );
  1281. Check( 0, memcmp( &rgvarRead[7].cyVal, rgvarWrite[7].pcyVal, sizeof(CY) ));
  1282. Check( VT_DATE, rgvarRead[8].vt );
  1283. Check( TRUE, rgvarRead[8].date == *rgvarWrite[8].pdate );
  1284. Check( VT_BSTR, rgvarRead[9].vt );
  1285. Check( 0, ocscmp( rgvarRead[9].bstrVal, *rgvarWrite[9].pbstrVal ));
  1286. Check( VT_DECIMAL, rgvarRead[10].vt );
  1287. Check( 0, memcmp( &rgvarRead[10].decVal.scale, &rgvarWrite[10].pdecVal->scale,
  1288. sizeof(decVal) - sizeof(decVal.wReserved) ));
  1289. Check( VT_I1, rgvarRead[11].vt );
  1290. Check( TRUE, rgvarRead[11].cVal == *rgvarWrite[11].pcVal );
  1291. Check( VT_UI2, rgvarRead[12].vt );
  1292. Check( TRUE, rgvarRead[12].uiVal == *rgvarWrite[12].puiVal );
  1293. Check( VT_UI4, rgvarRead[13].vt );
  1294. Check( TRUE, rgvarRead[13].ulVal == *rgvarWrite[13].pulVal );
  1295. Check( VT_INT, rgvarRead[14].vt );
  1296. Check( TRUE, rgvarRead[14].intVal == *rgvarWrite[14].pintVal );
  1297. Check( VT_UINT, rgvarRead[15].vt );
  1298. Check( TRUE, rgvarRead[15].uintVal == *rgvarWrite[15].puintVal );
  1299. Check( VT_I4, rgvarRead[16].vt );
  1300. Check( TRUE, rgvarRead[16].lVal == rgvarWrite[16].pvarVal->lVal );
  1301. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1302. RELEASE_INTERFACE(pPropSetStg);
  1303. g_pfnFreePropVariantArray( sizeof(rgvarRead)/sizeof(rgvarRead[0]), rgvarRead );
  1304. SysFreeString( bstrVal );
  1305. }
  1306. void
  1307. test_SettingLocalization( IStorage *pstg )
  1308. {
  1309. HRESULT hr = S_OK;
  1310. IPropertySetStorage *pPropSetStg = NULL;
  1311. IPropertyStorage *pPropStg = NULL;
  1312. FMTID fmtid;
  1313. CPropVariant rgcpropvarWrite[3], rgcpropvarRead[3];
  1314. CPropSpec rgcpropspec[3];
  1315. ULONG cRefsOriginal = GetRefCount( pstg );
  1316. Status( "Changing localization properties\n" );
  1317. UuidCreate( &fmtid );
  1318. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  1319. for( int i = 0; i < 2; i++ )
  1320. {
  1321. // Create a unicode or ansi property set
  1322. Check( S_OK, pPropSetStg->Create( fmtid, NULL,
  1323. 0 == i ? PROPSETFLAG_DEFAULT : PROPSETFLAG_ANSI,
  1324. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1325. &pPropStg ));
  1326. // ---------------------------
  1327. // Change the codepage to Ansi
  1328. // ---------------------------
  1329. // Set the codepage. This should work because it's currently empty
  1330. // (note that it's also currently Unicode). Set it to GetACP+1 just
  1331. // to be sure that we can set a non-default codepage.
  1332. rgcpropspec[0] = PID_CODEPAGE;
  1333. rgcpropvarWrite[0] = (short) (GetACP() + 1);
  1334. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1335. Check( S_OK, pPropStg->ReadMultiple( 1, rgcpropspec, rgcpropvarRead ));
  1336. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1337. // Now set the codepage to GetACP so that we can work on it.
  1338. rgcpropvarWrite[0] = (short) GetACP();
  1339. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1340. Check( S_OK, pPropStg->ReadMultiple( 1, rgcpropspec, rgcpropvarRead ));
  1341. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1342. // Write some named properties. The VT_LPSTR shouldn't get converted to Unicode
  1343. // now that this is an Ansi property set.
  1344. rgcpropvarWrite[0] = "Hello, world";
  1345. rgcpropvarWrite[1].SetBSTR( OLESTR("How are you?") );
  1346. rgcpropspec[0] = PID_FIRST_USABLE;
  1347. rgcpropspec[1] = OLESTR("Second property name");
  1348. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1349. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1350. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1351. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1352. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1353. // If we stat the IPropertyStorage, it should call itself Ansi.
  1354. STATPROPSETSTG statpropsetstg;
  1355. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  1356. Check( PROPSETFLAG_ANSI, PROPSETFLAG_ANSI & statpropsetstg.grfFlags );
  1357. // Verify that we can close and re-open it and everything's still the same.
  1358. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1359. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  1360. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1361. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1362. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1363. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1364. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  1365. Check( PROPSETFLAG_ANSI, PROPSETFLAG_ANSI & statpropsetstg.grfFlags );
  1366. // ------------------------------
  1367. // Change the codepage to Unicode
  1368. // ------------------------------
  1369. // Clear out the property set.
  1370. PROPID propidDictionary = PID_DICTIONARY;
  1371. Check( S_OK, pPropStg->DeleteMultiple( 2, rgcpropspec ));
  1372. Check( S_OK, pPropStg->DeletePropertyNames( 1, &propidDictionary ));
  1373. // Switch to Unicode
  1374. rgcpropvarWrite[0] = (short) CP_WINUNICODE;
  1375. rgcpropspec[0] = PID_CODEPAGE;
  1376. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1377. Check( S_OK, pPropStg->ReadMultiple( 1, rgcpropspec, rgcpropvarRead ));
  1378. Check( TRUE, rgcpropvarRead[0] == rgcpropvarWrite[0] );
  1379. // Verify with a Stat
  1380. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  1381. Check( 0, PROPSETFLAG_ANSI & statpropsetstg.grfFlags );
  1382. // Write & read some properties again. This time the LPSTR should be converted.
  1383. rgcpropvarWrite[0] = "Hello, world";
  1384. rgcpropvarWrite[1].SetBSTR( OLESTR("How are you?") );
  1385. rgcpropspec[0] = PID_FIRST_USABLE;
  1386. rgcpropspec[1] = OLESTR("Second property name");
  1387. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1388. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1389. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1390. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1391. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1392. // Close, reopen, and read/stat again
  1393. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1394. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  1395. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1396. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1397. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1398. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1399. Check( S_OK, pPropStg->Stat( &statpropsetstg ));
  1400. Check( 0, PROPSETFLAG_ANSI & statpropsetstg.grfFlags );
  1401. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1402. } // for( int i = 0; i < 2; i++ )
  1403. // -----------------------
  1404. // Validate error checking
  1405. // -----------------------
  1406. // Create a new property set
  1407. Check( S_OK, pPropSetStg->Create( fmtid, NULL,
  1408. 0 == i ? PROPSETFLAG_DEFAULT : PROPSETFLAG_ANSI,
  1409. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1410. &pPropStg ));
  1411. // After writing a property, we shouldn't be able to set the codepage or LCID
  1412. rgcpropspec[0] = PID_FIRST_USABLE;
  1413. rgcpropvarWrite[0] = (long) 1234;
  1414. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1415. rgcpropspec[0] = PID_CODEPAGE;
  1416. rgcpropvarWrite[0] = (short) 1234;
  1417. Check( STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1418. rgcpropspec[0] = PID_LOCALE;
  1419. rgcpropvarWrite[0] = (ULONG) 5678;
  1420. Check( STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1421. // But it's settable after deleting the property
  1422. rgcpropspec[0] = PID_FIRST_USABLE;
  1423. Check( S_OK, pPropStg->DeleteMultiple( 1, rgcpropspec ));
  1424. rgcpropspec[0] = PID_CODEPAGE;
  1425. rgcpropvarWrite[0] = (short) 1234;
  1426. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1427. rgcpropspec[1] = PID_LOCALE;
  1428. rgcpropvarWrite[1] = (ULONG) 5678;
  1429. Check( S_OK, pPropStg->WriteMultiple( 1, &rgcpropspec[1], &rgcpropvarWrite[1], PID_FIRST_USABLE ));
  1430. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1431. Check( S_OK, pPropStg->ReadMultiple(2, rgcpropspec, rgcpropvarRead ));
  1432. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1433. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1434. // But again it's not writable if there's a name in the dictionary
  1435. rgcpropspec[0] = PID_CODEPAGE;
  1436. rgcpropvarWrite[0] = (short) CP_WINUNICODE;
  1437. Check( S_OK, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1438. PROPID rgpropid[1] = { PID_FIRST_USABLE };
  1439. LPOLESTR rglposz[1] = { OLESTR("Hello") };
  1440. Check( S_OK, pPropStg->WritePropertyNames( 1, rgpropid, rglposz ));
  1441. Check( STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1442. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1443. Check( cRefsOriginal, RELEASE_INTERFACE(pPropSetStg) );
  1444. }
  1445. void
  1446. test_ExtendedTypes( IStorage *pstg )
  1447. {
  1448. HRESULT hr = S_OK;
  1449. IPropertySetStorage *pPropSetStg = NULL;
  1450. IPropertyStorage *pPropStg = NULL;
  1451. FMTID fmtid;
  1452. Status( "Extended Types\n" );
  1453. UuidCreate( &fmtid );
  1454. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  1455. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT,
  1456. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1457. &pPropStg ));
  1458. CPropVariant rgcpropvarWrite[5], rgcpropvarRead[5];
  1459. CPropSpec rgcpropspec[5];
  1460. rgcpropvarWrite[0] = (CHAR) 1;
  1461. rgcpropspec[0] = OLESTR("VT_I1");
  1462. DECIMAL decVal = { 10, 9, 8, 7, 6 };
  1463. rgcpropvarWrite[1] = decVal;
  1464. rgcpropspec[1] = OLESTR("VT_DECIMAL");
  1465. rgcpropvarWrite[2].SetINT( 2 );
  1466. rgcpropspec[2] = OLESTR("VT_INT");
  1467. rgcpropvarWrite[3].SetUINT( 3 );
  1468. rgcpropspec[3] = OLESTR("VT_UINT");
  1469. rgcpropvarWrite[4][1] = (CHAR) 2;
  1470. rgcpropvarWrite[4][0] = (CHAR) 1;
  1471. rgcpropspec[4] = OLESTR("VT_VECTOR|VT_I1");
  1472. Check( S_OK, pPropStg->WriteMultiple( sizeof(rgcpropvarWrite)/sizeof(rgcpropvarWrite[0]),
  1473. rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1474. for( int i = 0; i < sizeof(rgcpropvarRead)/sizeof(rgcpropvarRead[0]); i++ )
  1475. PropVariantInit( &rgcpropvarRead[i] );
  1476. CheckFormatVersion(pPropStg, PROPSET_WFORMAT_EXPANDED_VTS);
  1477. Check( S_OK, pPropStg->ReadMultiple( sizeof(rgcpropvarRead)/sizeof(rgcpropvarRead[0]),
  1478. rgcpropspec,
  1479. reinterpret_cast<PROPVARIANT*>(rgcpropvarRead) ));
  1480. Check( rgcpropvarRead[0].vt, rgcpropvarWrite[0].vt );
  1481. Check( TRUE, rgcpropvarWrite[0].cVal == rgcpropvarRead[0].cVal );
  1482. Check( rgcpropvarRead[1].vt, rgcpropvarWrite[1].vt );
  1483. Check( 0, memcmp( &rgcpropvarRead[1].decVal.scale, &rgcpropvarWrite[1].decVal.scale,
  1484. sizeof(rgcpropvarRead[1].decVal) - sizeof(rgcpropvarRead[1].decVal.wReserved) ));
  1485. Check( rgcpropvarRead[2].vt, rgcpropvarWrite[2].vt );
  1486. Check( rgcpropvarRead[2].intVal, rgcpropvarWrite[2].intVal );
  1487. Check( rgcpropvarRead[3].vt, rgcpropvarWrite[3].vt );
  1488. Check( rgcpropvarRead[3].uintVal, rgcpropvarWrite[3].uintVal );
  1489. Check( TRUE, rgcpropvarRead[4] == rgcpropvarWrite[4] );
  1490. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1491. RELEASE_INTERFACE(pPropSetStg);
  1492. }
  1493. void
  1494. test_StgOnHandle( OLECHAR *poszDir )
  1495. {
  1496. HRESULT hr = S_OK;
  1497. OLECHAR oszFile[ MAX_PATH ], oszDir[ MAX_PATH ];
  1498. CPropVariant cpropvarWrite, cpropvarRead;
  1499. HANDLE hFile = INVALID_HANDLE_VALUE;
  1500. HANDLE hDir = INVALID_HANDLE_VALUE;
  1501. IPropertyBagEx *pbag = NULL;
  1502. Status( "StgOpenStorageOnHandle\n" );
  1503. ocscpy( oszFile, poszDir );
  1504. ocscat( oszFile, OLESTR("test_StgOnHandle") );
  1505. ocscpy( oszDir, poszDir );
  1506. ocscat( oszDir, OLESTR("test_StgOnHandle Dir") );
  1507. // Create a storage and put a property in it.
  1508. Check( S_OK, g_pfnStgCreateStorageEx( oszFile, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  1509. DetermineStgFmt( g_enumImplementation ),
  1510. 0, NULL, NULL,
  1511. IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1512. OLECHAR *poszPropName = OLESTR("Prop Name");
  1513. cpropvarWrite = (long) 123; // VT_I4
  1514. Check( S_OK, pbag->WriteMultiple( 1, &poszPropName, &cpropvarWrite ));
  1515. Check( 0, RELEASE_INTERFACE(pbag) );
  1516. // Create a directory and put a property in it too.
  1517. Check( TRUE, CreateDirectory( oszDir, NULL ));
  1518. hDir = CreateFile( oszDir, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1519. NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE );
  1520. Check( TRUE, INVALID_HANDLE_VALUE != hDir );
  1521. Check( S_OK, g_pfnStgOpenStorageOnHandle( hDir, STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1522. NULL, NULL,
  1523. IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1524. CloseHandle( hDir );
  1525. Check( S_OK, pbag->WriteMultiple( 1, &poszPropName, &cpropvarWrite ));
  1526. Check( 0, RELEASE_INTERFACE(pbag) );
  1527. // Open the file and read the properties
  1528. hFile = CreateFile( oszFile, GENERIC_READ|GENERIC_WRITE, 0,
  1529. NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
  1530. Check( TRUE, INVALID_HANDLE_VALUE != hFile );
  1531. Check( S_OK, g_pfnStgOpenStorageOnHandle( hFile, STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1532. NULL, NULL,
  1533. IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1534. CloseHandle( hFile );
  1535. PropVariantClear( &cpropvarRead );
  1536. Check( S_OK, pbag->ReadMultiple( 1, &poszPropName, &cpropvarRead, NULL ));
  1537. Check( TRUE, cpropvarRead == cpropvarWrite );
  1538. Check( 0, RELEASE_INTERFACE(pbag) );
  1539. // Open the directory and read the properties
  1540. hFile = CreateFile( oszDir, GENERIC_READ|GENERIC_WRITE, 0,
  1541. NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
  1542. Check( TRUE, INVALID_HANDLE_VALUE != hFile );
  1543. Check( S_OK, g_pfnStgOpenStorageOnHandle( hFile, STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1544. NULL, NULL,
  1545. IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1546. CloseHandle( hFile );
  1547. PropVariantClear( &cpropvarRead );
  1548. Check( S_OK, pbag->ReadMultiple( 1, &poszPropName, &cpropvarRead, NULL ));
  1549. Check( TRUE, cpropvarRead == cpropvarWrite );
  1550. Check( 0, RELEASE_INTERFACE(pbag) );
  1551. }
  1552. void
  1553. test_PropsetOnEmptyFile( OLECHAR *poszDir )
  1554. {
  1555. HRESULT hr = S_OK;
  1556. OLECHAR oszFile[ MAX_PATH ];
  1557. CPropVariant cpropvarWrite, cpropvarRead;
  1558. HANDLE hFile = INVALID_HANDLE_VALUE;
  1559. IPropertySetStorage *pset = NULL;
  1560. // We only run this test for NFF property sets; there's special code there
  1561. // for the case of a read-only open of an empty file.
  1562. if( PROPIMP_NTFS != g_enumImplementation ) return;
  1563. Status( "Empty file\n" );
  1564. ocscpy( oszFile, poszDir );
  1565. ocscat( oszFile, OLESTR("test_PropsetOnEmptyFile") );
  1566. // Create a file
  1567. hFile = CreateFile( oszFile, GENERIC_READ|GENERIC_WRITE, 0,
  1568. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
  1569. Check( FALSE, INVALID_HANDLE_VALUE == hFile );
  1570. CloseHandle( hFile );
  1571. // Get a read-only property interface on the file.
  1572. Check( S_OK, StgOpenStorageEx( oszFile, STGM_READ|STGM_SHARE_DENY_WRITE,
  1573. STGFMT_ANY, 0, NULL, NULL,
  1574. IID_IPropertySetStorage,
  1575. reinterpret_cast<void**>(&pset) ));
  1576. Check( 0, RELEASE_INTERFACE(pset) );
  1577. }
  1578. void
  1579. test_PropsetOnHGlobal()
  1580. {
  1581. HANDLE hglobal = NULL;
  1582. IPropertyStorage *pPropStg = NULL;
  1583. IStream *pStm = NULL;
  1584. Status( "StgCreate/OpenPropStg on CreateStreamOnHGlobal\n" );
  1585. // Build up an IPropertyStorage on a memory block
  1586. hglobal = GlobalAlloc( GHND, 0 );
  1587. Check( FALSE, NULL == hglobal );
  1588. Check( S_OK, CreateStreamOnHGlobal( hglobal, FALSE, &pStm ));
  1589. hglobal = NULL;
  1590. Check( S_OK, StgCreatePropStg( (IUnknown*) pStm, FMTID_NULL, &CLSID_NULL,
  1591. PROPSETFLAG_DEFAULT,
  1592. 0L, // Reserved
  1593. &pPropStg ));
  1594. // Write a Unicode string property to the property set
  1595. CPropVariant rgcpropvarWrite[2] = { L"First Value", L"Second Value" };
  1596. CPropSpec rgcpropspec[2] = { L"First Name", L"Second Name" };
  1597. Check( S_OK, pPropStg->WriteMultiple( 1, &rgcpropspec[0], &rgcpropvarWrite[0], PID_FIRST_USABLE ));
  1598. // Close the IPropertyStorage and IStream.
  1599. Check( S_OK, pPropStg->Commit( STGC_DEFAULT )); // Flush to pStm
  1600. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1601. Check( S_OK, GetHGlobalFromStream( pStm, &hglobal ));
  1602. Check( 0, RELEASE_INTERFACE(pStm) );
  1603. // Reopen everything
  1604. Check( S_OK, CreateStreamOnHGlobal( hglobal, FALSE, &pStm ));
  1605. hglobal = NULL;
  1606. Check( S_OK, StgOpenPropStg( (IUnknown*) pStm, FMTID_NULL,
  1607. PROPSETFLAG_DEFAULT,
  1608. 0L, // Reserved
  1609. &pPropStg ));
  1610. // Write another property
  1611. Check( S_OK, pPropStg->WriteMultiple( 1, &rgcpropspec[1], &rgcpropvarWrite[1], PID_FIRST_USABLE ));
  1612. // Read and verify the properties
  1613. CPropVariant rgcpropvarRead[2];
  1614. Check( S_OK, pPropStg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1615. Check( TRUE, rgcpropvarRead[0] == rgcpropvarWrite[0] );
  1616. Check( TRUE, rgcpropvarRead[1] == rgcpropvarWrite[1] );
  1617. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1618. Check( S_OK, GetHGlobalFromStream( pStm, &hglobal ));
  1619. Check( 0, RELEASE_INTERFACE(pStm) );
  1620. // Reopen everything using a read-only stream.
  1621. Check( S_OK, CreateStreamOnHGlobal( hglobal, TRUE, &pStm ));
  1622. hglobal = NULL;
  1623. CReadOnlyStream ReadOnlyStream( pStm );
  1624. Check( S_OK, StgOpenPropStg( (IUnknown*) &ReadOnlyStream, FMTID_NULL,
  1625. PROPSETFLAG_DEFAULT,
  1626. 0L, // Reserved
  1627. &pPropStg ));
  1628. Check( STG_E_ACCESSDENIED, pPropStg->WriteMultiple( 1, &rgcpropspec[1],
  1629. &rgcpropvarWrite[1], PID_FIRST_USABLE ));
  1630. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1631. Check( 0, RELEASE_INTERFACE(pStm) );
  1632. }
  1633. void
  1634. test_SafeArray( IStorage *pstg )
  1635. {
  1636. HRESULT hr = S_OK;
  1637. IPropertySetStorage *pPropSetStg = NULL;
  1638. IPropertyStorage *pPropStg = NULL;
  1639. FMTID fmtid;
  1640. ULONG crefpstg = 0;
  1641. Status( "SafeArrays\n" );
  1642. UuidCreate( &fmtid );
  1643. pstg->AddRef();
  1644. crefpstg = pstg->Release();
  1645. // Get an IPropertyStorage from the input IStorage
  1646. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  1647. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT,
  1648. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1649. &pPropStg ));
  1650. SAFEARRAY *rgpsa[] = { NULL, NULL, NULL }; //, NULL, NULL };
  1651. CPropVariant *rgcpropvar = NULL;
  1652. SAFEARRAYBOUND rgsaBounds[] = { {2,0}, {3,10}, {4,20} }; // [0..1], [10..12], [20..23]
  1653. ULONG cDims = sizeof(rgsaBounds)/sizeof(rgsaBounds[0]);
  1654. ULONG cElems = 0;
  1655. // Create three SafeArrays to test a fixed sized type, a variable sized type
  1656. // (which is also ByRef), and a Variant.
  1657. rgpsa[0] = SafeArrayCreate( VT_I4, 3, rgsaBounds ); // Try both Create and CreateEx
  1658. Check( TRUE, NULL != rgpsa[0] );
  1659. rgpsa[1] = SafeArrayCreateEx( VT_BSTR, 3, rgsaBounds, NULL );
  1660. Check( TRUE, NULL != rgpsa[1] );
  1661. rgpsa[2] = SafeArrayCreateEx( VT_VARIANT, 3, rgsaBounds, NULL );
  1662. Check( TRUE, NULL != rgpsa[2] );
  1663. /*
  1664. rgpsa[3] = SafeArrayCreateEx( VT_I8, 3, rgsaBounds, NULL );
  1665. Check( TRUE, NULL != rgpsa[3] );
  1666. rgpsa[4] = SafeArrayCreateEx( VT_UI8, 3, rgsaBounds, NULL );
  1667. Check( TRUE, NULL != rgpsa[4] );
  1668. */
  1669. // Determine how many elements are in the SafeArrays, and alloc that
  1670. // many PropVariants. We'll need this for the SafeArray of Variants.
  1671. cElems = CalcSafeArrayElementCount( rgpsa[0] );
  1672. rgcpropvar = new CPropVariant[ cElems ];
  1673. Check( FALSE, NULL == rgcpropvar );
  1674. // Fill in each of the SafeArrays.
  1675. for( ULONG i = 0; i < cElems; i++ )
  1676. {
  1677. LONG rgIndices[3];
  1678. // Map this this element from linear space to bounds space
  1679. CalcSafeArrayIndices( i, rgIndices, rgsaBounds, cDims );
  1680. // Add an I4
  1681. LONG lVal = static_cast<LONG>(i);
  1682. Check( S_OK, SafeArrayPutElement( rgpsa[0], rgIndices, &lVal ));
  1683. // Add a BSTR
  1684. BSTR bstrVal = SysAllocString( OLESTR("0 BSTR Val") );
  1685. *bstrVal = OLESTR('0') + static_cast<OLECHAR>(i);
  1686. Check( S_OK, SafeArrayPutElement( rgpsa[1], rgIndices, bstrVal ));
  1687. // Add a PropVariant that could be an I4 or a BSTR
  1688. if( i & 1 )
  1689. rgcpropvar[i] = (long) i;
  1690. else
  1691. rgcpropvar[i].SetBSTR( bstrVal ); // Copies string
  1692. Check( S_OK, SafeArrayPutElement( rgpsa[2], rgIndices, &rgcpropvar[i] ));
  1693. // The SafeArrays have copied the BSTR, so we can free our local copy
  1694. SysFreeString( bstrVal );
  1695. // Add I8/UI8
  1696. /*
  1697. LONGLONG llVal = i;
  1698. Check( S_OK, SafeArrayPutElement( rgpsa[3], rgIndices, &llVal ));
  1699. llVal += 1000;
  1700. Check( S_OK, SafeArrayPutElement( rgpsa[4], rgIndices, &llVal ));
  1701. */
  1702. }
  1703. VARIANT rgvarWrite[3], rgvarRead[3];
  1704. PROPVARIANT rgpropvarCopy[3];
  1705. CPropSpec rgcpropspec[3];
  1706. // Load the SafeArrays into PropVariants
  1707. LOAD_VARIANT(rgvarWrite[0], VT_ARRAY|VT_I4, parray, rgpsa[0] );
  1708. rgcpropspec[0] = OLESTR("VT_ARRAY|VT_I4");
  1709. LOAD_VARIANT(rgvarWrite[1], VT_BYREF|VT_ARRAY|VT_BSTR, pparray, &rgpsa[1] );
  1710. rgcpropspec[1] = OLESTR("VT_BYREF|VT_ARRAY|VT_BSTR");
  1711. LOAD_VARIANT(rgvarWrite[2], VT_ARRAY|VT_VARIANT, parray, rgpsa[2] );
  1712. rgcpropspec[2] = OLESTR("VT_ARRAY|VT_VARIANT");
  1713. /*
  1714. LOAD_VARIANT(rgvarWrite[3], VT_ARRAY|VT_I8, parray, rgpsa[3] );
  1715. rgcpropspec[3] = OLESTR("VT_ARRAY|VT_I8");
  1716. LOAD_VARIANT(rgvarWrite[4], VT_ARRAY|VT_UI8, parray, rgpsa[4] );
  1717. rgcpropspec[4] = OLESTR("VT_ARRAY|VT_UI8");
  1718. */
  1719. // Write the PropVariant SafeArrays and verify that the propset version in the
  1720. // header gets incremented.
  1721. Check( S_OK, pPropStg->WriteMultiple( sizeof(rgvarWrite)/sizeof(rgvarWrite[0]),
  1722. rgcpropspec,
  1723. reinterpret_cast<PROPVARIANT*>(rgvarWrite),
  1724. PID_FIRST_USABLE ));
  1725. CheckFormatVersion(pPropStg, PROPSET_WFORMAT_EXPANDED_VTS);
  1726. // Test PropVariantCopy by copying each of the PropVariants and comparing the result.
  1727. for( i = 0; i < sizeof(rgvarRead)/sizeof(rgvarRead[0]); i++ )
  1728. {
  1729. PropVariantInit( &rgpropvarCopy[i] );
  1730. Check( S_OK, g_pfnPropVariantCopy( &rgpropvarCopy[i], reinterpret_cast<PROPVARIANT*>(&rgvarWrite[i]) ));
  1731. Check( rgpropvarCopy[i].vt, rgvarWrite[i].vt );
  1732. if( VT_BYREF & rgpropvarCopy[i].vt )
  1733. CompareSafeArrays( *rgpropvarCopy[i].pparray, *rgvarWrite[i].pparray );
  1734. else
  1735. CompareSafeArrays( rgpropvarCopy[i].parray, rgvarWrite[i].parray );
  1736. // As long as we're looping, let's start init-ing the Read array too.
  1737. VariantInit( &rgvarRead[i] );
  1738. }
  1739. // Read back the values that we wrote.
  1740. Check( S_OK, pPropStg->ReadMultiple( sizeof(rgvarRead)/sizeof(rgvarRead[0]),
  1741. rgcpropspec,
  1742. reinterpret_cast<PROPVARIANT*>(rgvarRead) ));
  1743. // Validate the Read values. For the second one, the byref should no longer
  1744. // be set.
  1745. Check( rgvarWrite[0].vt, rgvarRead[0].vt );
  1746. CompareSafeArrays( rgvarWrite[0].parray, rgvarRead[0].parray );
  1747. Check( 0, rgvarRead[1].vt & VT_BYREF );
  1748. Check( rgvarWrite[1].vt, rgvarRead[1].vt|VT_BYREF );
  1749. CompareSafeArrays( *rgvarWrite[1].pparray, rgvarRead[1].parray );
  1750. Check( rgvarWrite[2].vt, rgvarRead[2].vt );
  1751. CompareSafeArrays( rgvarWrite[2].parray, rgvarRead[2].parray );
  1752. /*
  1753. Check( rgvarWrite[3].vt, rgvarRead[3].vt );
  1754. CompareSafeArrays( rgvarWrite[3].parray, rgvarRead[3].parray );
  1755. Check( rgvarWrite[4].vt, rgvarRead[4].vt );
  1756. CompareSafeArrays( rgvarWrite[4].parray, rgvarRead[4].parray );
  1757. */
  1758. // Free the safearrays (they're in rgvarWrite, but we don't clear that).
  1759. Check( S_OK, SafeArrayDestroy( rgpsa[0] ));
  1760. Check( S_OK, SafeArrayDestroy( rgpsa[1] ));
  1761. Check( S_OK, SafeArrayDestroy( rgpsa[2] ));
  1762. /*
  1763. Check( S_OK, SafeArrayDestroy( rgpsa[3] ));
  1764. Check( S_OK, SafeArrayDestroy( rgpsa[4] ));
  1765. */
  1766. Check( S_OK, g_pfnFreePropVariantArray( sizeof(rgpropvarCopy)/sizeof(rgpropvarCopy[0]),
  1767. reinterpret_cast<PROPVARIANT*>(rgpropvarCopy) ));
  1768. Check( S_OK, g_pfnFreePropVariantArray( sizeof(rgvarRead)/sizeof(rgvarRead[0]),
  1769. reinterpret_cast<PROPVARIANT*>(rgvarRead) ));
  1770. Check( S_OK, g_pfnFreePropVariantArray( cElems, rgcpropvar ));
  1771. // ------------------------------------------------------
  1772. // Verify that we can't write a safearray with a bad type
  1773. // ------------------------------------------------------
  1774. LONG rgIndices[] = { 0 };
  1775. VARIANT *pvar;
  1776. rgpsa[0] = SafeArrayCreateVector( VT_VARIANT, 0, 1 );
  1777. Check( TRUE, NULL != rgpsa[0] );
  1778. SafeArrayPtrOfIndex( rgpsa[0], rgIndices, reinterpret_cast<void**>(&pvar) );
  1779. pvar->vt = VT_STREAM;
  1780. rgcpropvar[0].vt = VT_ARRAY | VT_VARIANT;
  1781. rgcpropvar[0].parray = rgpsa[0];
  1782. rgpsa[0] = NULL;
  1783. // In NT5, this returned HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), which was
  1784. // the error that StgConvertVariantToPropertyNoEH got from SafeArrayGetVartype.
  1785. // In Whistler, SafeArrayGetVartype is returning success, so the error doesn't
  1786. // get caught until the recursive call to StgConvertVariantToPropertyNoEH,
  1787. // which returns STATUS_INVALID_PARAMETER, which gets translated into
  1788. // STG_E_INVALIDPARAMETER.
  1789. Check( STG_E_INVALIDPARAMETER,
  1790. pPropStg->WriteMultiple( 1, rgcpropspec, rgcpropvar, PID_FIRST_USABLE ));
  1791. // Clear the propvar we just used (which also destroys the safearray)
  1792. Check( S_OK, g_pfnPropVariantClear( &rgcpropvar[0] ) );
  1793. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvar, PID_FIRST_USABLE ));
  1794. Check( S_OK, g_pfnFreePropVariantArray( 2, rgcpropvar ));
  1795. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1796. Check( crefpstg, RELEASE_INTERFACE(pPropSetStg) );
  1797. delete[] rgcpropvar;
  1798. }
  1799. void
  1800. test_ReadOnlyReservedProperties( IStorage *pStg )
  1801. {
  1802. IPropertySetStorage *pPropSetStg = NULL;
  1803. IPropertyStorage *pPropStg = NULL;
  1804. CPropVariant cpropvar = L"Property Value";
  1805. CPropSpec cpropspec;
  1806. FMTID fmtid;
  1807. ULONG cRefsOriginal = GetRefCount(pStg);
  1808. Status( "Read-only reserved PROPIDs\n" );
  1809. UuidCreate( &fmtid );
  1810. Check( S_OK, pStg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg) ));
  1811. Check( S_OK, pPropSetStg->Create( fmtid, NULL, PROPSETFLAG_DEFAULT,
  1812. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1813. &pPropStg ));
  1814. cpropspec = PID_BEHAVIOR + 1;
  1815. Check( STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, &cpropspec, &cpropvar, PID_FIRST_USABLE ));
  1816. cpropspec = PID_MAX_READONLY;
  1817. Check( STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, &cpropspec, &cpropvar, PID_FIRST_USABLE ));
  1818. cpropspec = PID_MAX_READONLY + 1;
  1819. Check( S_OK, pPropStg->WriteMultiple( 1, &cpropspec, &cpropvar, PID_FIRST_USABLE ));
  1820. Check( 0, RELEASE_INTERFACE(pPropStg) );
  1821. Check( cRefsOriginal, RELEASE_INTERFACE(pPropSetStg) );
  1822. }
  1823. void
  1824. test_LowMemory( IStorage *pstg )
  1825. {
  1826. HRESULT hr = S_OK;
  1827. IPropertySetStorage *psetstg = NULL;
  1828. IPropertyStorage *ppropstg = NULL;
  1829. IStorageTest *ptest = NULL;
  1830. CPropSpec rgcpropspec[2];
  1831. CPropVariant rgcpropvarWrite[2], rgcpropvarRead[2];
  1832. int i;
  1833. Status( "Low-memory mapped stream code\n" );
  1834. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&psetstg) ));
  1835. for( i = 0; i < 2; i++ )
  1836. {
  1837. DWORD propsetflag = i == 0 ? PROPSETFLAG_DEFAULT : PROPSETFLAG_NONSIMPLE;
  1838. FMTID fmtid;
  1839. UuidCreate( &fmtid );
  1840. Check( S_OK, psetstg->Create( fmtid, NULL, propsetflag,
  1841. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1842. &ppropstg ));
  1843. // Go into low-memory mode
  1844. hr = ppropstg->QueryInterface( IID_IStorageTest, reinterpret_cast<void**>(&ptest) );
  1845. if( SUCCEEDED(hr) )
  1846. hr = ptest->SimulateLowMemory( TRUE );
  1847. // IStorageTest isn't available in a free build. As of this writing
  1848. // it's not available in docfile.
  1849. if( E_NOINTERFACE == hr )
  1850. {
  1851. Status( " ... Partially skipping, IStorageTest not available\n" );
  1852. continue;
  1853. }
  1854. else
  1855. Check( S_OK, hr );
  1856. // Write and read properties
  1857. rgcpropspec[0] = OLESTR("First property");
  1858. rgcpropvarWrite[0] = "Hello, world";
  1859. rgcpropspec[1] = OLESTR("Second property");
  1860. rgcpropvarWrite[1] = "How are you?";
  1861. Check( S_OK, ppropstg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1862. Check( S_OK, ppropstg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1863. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1864. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1865. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1866. // Write, commit, and read
  1867. g_pfnFreePropVariantArray( 2, rgcpropvarWrite );
  1868. rgcpropvarWrite[0] = CBlob( L"go blue" );
  1869. rgcpropvarWrite[1] = static_cast<CLSID>(fmtid);
  1870. Check( S_OK, ppropstg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1871. Check( S_OK, ppropstg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1872. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1873. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1874. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1875. Check( S_OK, ppropstg->Commit( STGC_DEFAULT ));
  1876. Check( S_OK, ppropstg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1877. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1878. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1879. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1880. // Write, close, reopen, and read
  1881. g_pfnFreePropVariantArray( 2, rgcpropvarWrite );
  1882. rgcpropvarWrite[0] = 0.1234;
  1883. rgcpropvarWrite[1] = CClipData("Hi");
  1884. Check( S_OK, ppropstg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  1885. RELEASE_INTERFACE(ptest);
  1886. RELEASE_INTERFACE(ppropstg);
  1887. Check( S_OK, psetstg->Open( fmtid, STGM_READ|STGM_SHARE_EXCLUSIVE, &ppropstg ));
  1888. Check( S_OK, ppropstg->ReadMultiple( 2, rgcpropspec, rgcpropvarRead ));
  1889. Check( TRUE, rgcpropvarWrite[0] == rgcpropvarRead[0] );
  1890. Check( TRUE, rgcpropvarWrite[1] == rgcpropvarRead[1] );
  1891. g_pfnFreePropVariantArray( 2, rgcpropvarRead );
  1892. RELEASE_INTERFACE(ppropstg);
  1893. } // for( i = 0; i < 2; i++ )
  1894. //Exit:
  1895. RELEASE_INTERFACE(ptest);
  1896. RELEASE_INTERFACE(ppropstg);
  1897. RELEASE_INTERFACE(psetstg);
  1898. }
  1899. void
  1900. test_BagOpenMethod( IStorage *pstg )
  1901. {
  1902. HRESULT hr = S_OK;
  1903. IPropertyBagEx *pbag = NULL;
  1904. OLECHAR * rgoszDelete[2];
  1905. CPropVariant cpropvar;
  1906. PROPVARIANT propvar;
  1907. VERSIONEDSTREAM VersionedStream;
  1908. GUID guidVersion2;
  1909. OLECHAR *pwszName = { OLESTR("Versioned Stream") };
  1910. IUnknown *punk = NULL;
  1911. IStream *pstm = NULL;
  1912. CHAR rgbStreamDataWrite[50] = "Stream data";
  1913. CHAR rgbStreamDataRead[100];
  1914. ULONG cbRead;
  1915. STATSTG statstg;
  1916. Status( "IPropertyBagEx::Open\n" );
  1917. Check( S_OK, pstg->QueryInterface( IID_IPropertyBagEx, reinterpret_cast<void**>(&pbag) ));
  1918. // Create a VersionedStream
  1919. UuidCreate( &VersionedStream.guidVersion );
  1920. VersionedStream.pStream = NULL;
  1921. cpropvar = VersionedStream;
  1922. // Write the versioned stream (causing a stream to be created) and read it back.
  1923. Check( S_OK, pbag->WriteMultiple( 1, &pwszName, &cpropvar ));
  1924. cpropvar.Clear();
  1925. Check( S_OK, pbag->ReadMultiple( 1, &pwszName, &cpropvar, NULL ));
  1926. Check( TRUE, VT_VERSIONED_STREAM == cpropvar.VarType() && NULL != cpropvar.pVersionedStream->pStream );
  1927. // Put some data in the stream and release it.
  1928. Check( S_OK, cpropvar.pVersionedStream->pStream->Write( rgbStreamDataWrite, sizeof(rgbStreamDataWrite), NULL ));
  1929. cpropvar.Clear();
  1930. // Now read that VersionedStream, with the proper GUID
  1931. Check( S_OK, pbag->Open( NULL, pwszName, VersionedStream.guidVersion, 0, IID_IStream, &punk ));
  1932. Check( S_OK, punk->QueryInterface( IID_IStream, reinterpret_cast<void**>(&pstm) ));
  1933. // Verify the data.
  1934. Check( S_OK, pstm->Read( rgbStreamDataRead, sizeof(rgbStreamDataRead), &cbRead ));
  1935. Check( TRUE, cbRead == sizeof(rgbStreamDataWrite) );
  1936. Check( TRUE, 0 == strcmp( rgbStreamDataWrite, rgbStreamDataRead ));
  1937. RELEASE_INTERFACE(pstm);
  1938. RELEASE_INTERFACE(punk);
  1939. // Attempt to read the same VersionedStream with a bad GUID
  1940. UuidCreate( &guidVersion2 );
  1941. Check( STG_E_FILEALREADYEXISTS, pbag->Open( NULL, pwszName, guidVersion2, 0, IID_IStream, &punk ));
  1942. // Attempt with a bad guid again, but this time cause a new property to be created.
  1943. Check( S_OK, pbag->Open( NULL, pwszName, guidVersion2, OPENPROPERTY_OVERWRITE, IID_IStream, &punk ));
  1944. Check( S_OK, punk->QueryInterface( IID_IStream, reinterpret_cast<void**>(&pstm) ));
  1945. Check( S_OK, pstm->Stat( &statstg, STATFLAG_NONAME ));
  1946. Check( TRUE, CULargeInteger(0) == statstg.cbSize );
  1947. RELEASE_INTERFACE(pstm);
  1948. RELEASE_INTERFACE(punk);
  1949. // Show that we can overwrite an existing property of a different type, but only
  1950. // by setting the overwrite flag.
  1951. cpropvar = static_cast<long>(45);
  1952. Check( S_OK, pbag->WriteMultiple( 1, &pwszName, &cpropvar ));
  1953. Check( STG_E_FILEALREADYEXISTS, pbag->Open( NULL, pwszName, guidVersion2, 0, IID_IStream, &punk ));
  1954. Check( S_OK, pbag->Open( NULL, pwszName, guidVersion2, OPENPROPERTY_OVERWRITE, IID_IStream, &punk ));
  1955. RELEASE_INTERFACE(punk);
  1956. // Show that if a property doesn't exist, Open creates it.
  1957. Check( S_OK, pbag->DeleteMultiple( 1, &pwszName, 0 ));
  1958. PropVariantClear( &cpropvar );
  1959. Check( S_FALSE, pbag->ReadMultiple( 1, &pwszName, &cpropvar, NULL ));
  1960. Check( S_OK, pbag->Open( NULL, pwszName, guidVersion2, 0, IID_IStream, &punk ));
  1961. RELEASE_INTERFACE(punk);
  1962. RELEASE_INTERFACE(pbag);
  1963. } // test_BagOpenMethod
  1964. void
  1965. test_StandaloneAPIs( LPOLESTR ocsDir )
  1966. {
  1967. OLECHAR ocsFile[ MAX_PATH + 1 ];
  1968. FMTID fmtidStgPropStg, fmtidStgPropSetStg;
  1969. IStorage *pstg = NULL; //TSafeStorage< IStorage > pstg;
  1970. IStream *pstmInMemory = NULL;
  1971. IStorage *pstgInMemory = NULL;
  1972. IPropertySetStorage *ppropsetstg = NULL; //TSafeStorage< IPropertySetStorage > ppropsetstg;
  1973. CPropVariant rgcpropvar[ CPROPERTIES_ALL ];
  1974. IPropertySetStorage *pPropSetStg;
  1975. IPropertyStorage *pPropStg;
  1976. DWORD propsetflag;
  1977. ULONG cPropertiesAll;
  1978. ULONG ulIndex;
  1979. Status( "Standalone API test\n" );
  1980. // Generate FMTIDs.
  1981. UuidCreate( &fmtidStgPropStg );
  1982. UuidCreate( &fmtidStgPropSetStg );
  1983. // Generate a filename from the directory name.
  1984. ocscpy( ocsFile, ocsDir );
  1985. ocscat( ocsFile, OLESTR( "IPropAPIs.stg" ));
  1986. // Create a storage.
  1987. Check( S_OK, g_pfnStgCreateStorageEx( ocsFile,
  1988. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1989. DetermineStgFmt( g_enumImplementation ),
  1990. 0L,
  1991. NULL,
  1992. NULL,
  1993. DetermineStgIID( g_enumImplementation ),
  1994. (void**) &pstg ));
  1995. // Run the following part of the test twice; once for a simple
  1996. // property set and once for a non-simple.
  1997. for( int i = 0; i < 2; i++ )
  1998. {
  1999. ILockBytes *pLockBytes = NULL;
  2000. IStorage *pstgInMemory = NULL;
  2001. #ifdef _MAC
  2002. Handle hglobal;
  2003. hglobal = NewHandle( 0 );
  2004. #else
  2005. HANDLE hglobal;
  2006. hglobal = GlobalAlloc( GPTR, 0 );
  2007. #endif
  2008. Check( TRUE, NULL != hglobal );
  2009. if( 0 == i )
  2010. {
  2011. // Create simple IPropertyStorage
  2012. Check(S_OK, CreateStreamOnHGlobal( hglobal, TRUE, &pstmInMemory ));
  2013. Check( S_OK, g_pfnStgCreatePropStg( (IUnknown*) pstmInMemory,
  2014. fmtidStgPropStg,
  2015. &CLSID_NULL,
  2016. PROPSETFLAG_ANSI,
  2017. 0L, // Reserved
  2018. &pPropStg ));
  2019. }
  2020. else
  2021. {
  2022. // If we're not allowed to do non-simple, skip out now.
  2023. if( (RESTRICT_SIMPLE_ONLY & g_Restrictions)
  2024. ||
  2025. (RESTRICT_NON_HIERARCHICAL & g_Restrictions) )
  2026. {
  2027. break;
  2028. }
  2029. // Create a non-simple IPropertyStorage
  2030. Check( S_OK, CreateILockBytesOnHGlobal( hglobal, TRUE, &pLockBytes ));
  2031. Check( S_OK, StgCreateDocfileOnILockBytes( pLockBytes,
  2032. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  2033. 0,
  2034. &pstgInMemory ));
  2035. Check( S_OK, g_pfnStgCreatePropStg( (IUnknown*) pstgInMemory,
  2036. fmtidStgPropStg,
  2037. &CLSID_NULL,
  2038. PROPSETFLAG_ANSI | PROPSETFLAG_NONSIMPLE,
  2039. 0,
  2040. &pPropStg ));
  2041. }
  2042. // Write to the property set.
  2043. Check( S_OK, pPropStg->WriteMultiple( 0 == i ? CPROPERTIES_ALL_SIMPLE : CPROPERTIES_ALL,
  2044. g_rgcpropspecAll,
  2045. g_rgcpropvarAll,
  2046. PID_FIRST_USABLE ));
  2047. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  2048. // Read from the property set
  2049. Check( S_OK, pPropStg->ReadMultiple( 0 == i ? CPROPERTIES_ALL_SIMPLE : CPROPERTIES_ALL,
  2050. g_rgcpropspecAll,
  2051. rgcpropvar ));
  2052. // Compare the properties
  2053. for( ulIndex = 0;
  2054. 0 == i ? (ulIndex < CPROPERTIES_ALL_SIMPLE) : (ulIndex < CPROPERTIES_ALL);
  2055. ulIndex++ )
  2056. {
  2057. Check( TRUE, rgcpropvar[ulIndex] == g_rgcpropvarAll[ulIndex] );
  2058. rgcpropvar[ulIndex].Clear();
  2059. }
  2060. pPropStg->Release();
  2061. pPropStg = NULL;
  2062. // -------------------
  2063. // Test StgOpenPropStg
  2064. // -------------------
  2065. // Open the IPropertyStorage
  2066. Check( S_OK, g_pfnStgOpenPropStg( 0 == i
  2067. ? (IUnknown*) pstmInMemory
  2068. : (IUnknown*) pstgInMemory,
  2069. fmtidStgPropStg,
  2070. PROPSETFLAG_DEFAULT
  2071. | (0 == i ? 0 : PROPSETFLAG_NONSIMPLE),
  2072. 0L, // Reserved
  2073. &pPropStg ));
  2074. // Read from the property set
  2075. Check( S_OK, pPropStg->ReadMultiple( 0 == i ? CPROPERTIES_ALL_SIMPLE : CPROPERTIES_ALL,
  2076. g_rgcpropspecAll,
  2077. rgcpropvar ));
  2078. // Compare the properties
  2079. for( ulIndex = 0;
  2080. 0 == i ? (ulIndex < CPROPERTIES_ALL_SIMPLE) : (ulIndex < CPROPERTIES_ALL);
  2081. ulIndex++ )
  2082. {
  2083. Check( TRUE, rgcpropvar[ulIndex] == g_rgcpropvarAll[ulIndex] );
  2084. rgcpropvar[ulIndex].Clear();
  2085. }
  2086. pPropStg->Release();
  2087. pPropStg = NULL;
  2088. RELEASE_INTERFACE( pstmInMemory );
  2089. RELEASE_INTERFACE( pstgInMemory );
  2090. RELEASE_INTERFACE( pLockBytes );
  2091. }
  2092. // --------------------------------
  2093. // Test StgCreatePropSetStg::Create
  2094. // --------------------------------
  2095. // This is equivalent to the previous tests, but
  2096. // uses StgCreatePropSetStg to create an IPropertySetStorage,
  2097. // and uses that to create a property set.
  2098. // Create the IPropertySetStorage
  2099. Check( S_OK, g_pfnStgCreatePropSetStg( pstg,
  2100. 0L, // Reserved
  2101. &pPropSetStg ));
  2102. // Create an IPropertyStorage. Create it non-simple, unless the underlying
  2103. // IStorage (i.e. NTFS) doesn't support it.
  2104. if( (RESTRICT_SIMPLE_ONLY & g_Restrictions) || (RESTRICT_NON_HIERARCHICAL & g_Restrictions) )
  2105. {
  2106. propsetflag = PROPSETFLAG_DEFAULT;
  2107. cPropertiesAll = CPROPERTIES_ALL_SIMPLE;
  2108. }
  2109. else
  2110. {
  2111. propsetflag = PROPSETFLAG_NONSIMPLE;
  2112. cPropertiesAll = CPROPERTIES_ALL;
  2113. }
  2114. Check( S_OK, pPropSetStg->Create( fmtidStgPropSetStg,
  2115. &CLSID_NULL,
  2116. propsetflag,
  2117. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2118. &pPropStg ));
  2119. // Write to the property set.
  2120. Check( S_OK, pPropStg->WriteMultiple( cPropertiesAll,
  2121. g_rgcpropspecAll,
  2122. g_rgcpropvarAll,
  2123. PID_FIRST_USABLE ));
  2124. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  2125. //-----------------------------------------------------------------------
  2126. // Close it all up and then open it again.
  2127. // This will exercise the g_pfnStgOpenStorageEx API
  2128. //
  2129. pPropStg->Commit(STGC_DEFAULT);
  2130. pPropStg->Release();
  2131. pPropStg = NULL;
  2132. pPropSetStg->Release();
  2133. pPropSetStg = NULL;
  2134. pstg->Release();
  2135. pstg = NULL;
  2136. Check( S_OK, g_pfnStgOpenStorageEx( ocsFile,
  2137. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2138. STGFMT_ANY, //DetermineStgFmt( g_enumImplementation ), // BUGBUG: Use STGFMT_ANY when StgEx can handle it
  2139. 0L,
  2140. NULL,
  2141. NULL,
  2142. IID_IPropertySetStorage,
  2143. (void**) &pPropSetStg ));
  2144. Check( S_OK, pPropSetStg->Open( fmtidStgPropSetStg,
  2145. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2146. &pPropStg));
  2147. //pPropSetStg->Release();
  2148. //
  2149. //-----------------------------------------------------------------------
  2150. //
  2151. // Read from the property set
  2152. //
  2153. Check( S_OK, pPropStg->ReadMultiple( cPropertiesAll,
  2154. g_rgcpropspecAll,
  2155. rgcpropvar ));
  2156. // Compare the properties
  2157. for( ulIndex = 0; ulIndex < cPropertiesAll; ulIndex++ )
  2158. {
  2159. Check( TRUE, rgcpropvar[ulIndex] == g_rgcpropvarAll[ulIndex] );
  2160. rgcpropvar[ulIndex].Clear();
  2161. }
  2162. // Clean up
  2163. RELEASE_INTERFACE( pPropStg );
  2164. RELEASE_INTERFACE( pPropSetStg );
  2165. }
  2166. //
  2167. // IPropertySetStorage tests
  2168. //
  2169. void
  2170. test_IPropertySetStorage_IUnknown(IStorage *pStorage)
  2171. {
  2172. // Only use this an IStorage-based property set, since this test
  2173. // assumes that IStorage & IPropertySetStorage are on the same
  2174. // object.
  2175. if( PROPIMP_DOCFILE_IPROP == g_enumImplementation )
  2176. {
  2177. return;
  2178. }
  2179. Status( "IPropertySetStorage::IUnknown\n" );
  2180. // Check ref counting through different interfaces on object
  2181. //
  2182. // QI to IPropertySetStorage
  2183. // QI to IUnknown on IStorage
  2184. // QI to IUnknown on IPropertySetStorage
  2185. // QI back to IPropertySetStorage from IUnknown
  2186. // QI back to IStorage from IPropertySetStorage
  2187. //
  2188. // Release all.
  2189. //
  2190. IStorage *pStorage2;
  2191. IPropertySetStorage *ppss1, *ppss2, *ppss3;
  2192. IUnknown *punk1,*punk2;
  2193. HRESULT hr=S_OK;
  2194. Check(S_OK, pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&ppss1));
  2195. Check(S_OK, pStorage->QueryInterface(IID_IUnknown, (void **)&punk1));
  2196. Check(S_OK, ppss1->QueryInterface(IID_IUnknown, (void **)&punk2));
  2197. Check(S_OK, ppss1->QueryInterface(DetermineStgIID( g_enumImplementation ), (void **)&pStorage2));
  2198. Check(S_OK, ppss1->QueryInterface(IID_IPropertySetStorage, (void **)&ppss2));
  2199. Check(S_OK, punk1->QueryInterface(IID_IPropertySetStorage, (void **)&ppss3));
  2200. ppss1->AddRef();
  2201. ppss1->Release();
  2202. //pStorage.Release();
  2203. ppss1->Release();
  2204. punk1->Release();
  2205. punk2->Release();
  2206. pStorage2->Release();
  2207. ppss2->Release();
  2208. // void *pvVirtFuncTable = *(void**)ppss3;
  2209. ppss3->Release();
  2210. // Check(STG_E_INVALIDHANDLE, ((IPropertySetStorage*)&pvVirtFuncTable)->QueryInterface(IID_IUnknown, (void**)&punk3));
  2211. }
  2212. #define INVALID_POINTER ( (void *) 0xFFFFFFFF )
  2213. #define VTABLE_MEMBER_FN(pObj,entry) ( (*(ULONG ***)(pObj))[ (entry) ] )
  2214. //+---------------------------------------------------------
  2215. //
  2216. // Template: Alloc2PageVector
  2217. //
  2218. // Purpose: This function template allocates two pages
  2219. // of memory, and then sets a vector pointer
  2220. // so that its first element is wholy within
  2221. // the first page, and the second element is
  2222. // wholy within the second. Then, the protection
  2223. // of the second page is set according to the
  2224. // caller-provided parameter.
  2225. //
  2226. //
  2227. // Inputs: [TYPE**] ppBase
  2228. // Points to the beginning of the two pages.
  2229. // [TYPE**] ppVector
  2230. // Points to the beginning of the vector of TYPEs.
  2231. // [DWORD] dwProtect
  2232. // The desired protection on the second page
  2233. // (from the PAGE_* enumeration).
  2234. // [LPWSTR] lpwstr (optional)
  2235. // If not NULL, used to initialize the vector
  2236. // elements.
  2237. //
  2238. // Output: TRUE iff successful.
  2239. //
  2240. //+---------------------------------------------------------
  2241. template< class TYPE > BOOL Alloc2PageVector( TYPE** ppBase,
  2242. TYPE** ppVector,
  2243. DWORD dwProtect,
  2244. TYPE* pInit )
  2245. {
  2246. DWORD dwOldProtect;
  2247. SYSTEM_INFO si;
  2248. GetSystemInfo( &si );
  2249. *ppBase = (TYPE*) VirtualAlloc( NULL, 2 * si.dwPageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  2250. if( NULL == *ppBase )
  2251. return( FALSE );
  2252. *ppVector = (TYPE*) ( (BYTE*) *ppBase + si.dwPageSize - sizeof(TYPE) );
  2253. if( NULL != pInit )
  2254. {
  2255. memcpy( &((LPWSTR*)*ppVector)[0], pInit, sizeof(TYPE) );
  2256. memcpy( &((LPWSTR*)*ppVector)[1], pInit, sizeof(TYPE) );
  2257. }
  2258. if( !VirtualProtect( (BYTE*) *ppBase + si.dwPageSize, si.dwPageSize, dwProtect, &dwOldProtect ) )
  2259. return( FALSE );
  2260. return( TRUE );
  2261. }
  2262. void
  2263. test_PropVariantValidation( IStorage *pStg )
  2264. {
  2265. Status( "PropVariant Validation\n" );
  2266. IPropertySetStorage *pPSStg = NULL; // TSafeStorage< IPropertySetStorage > pPSStg( pStg );
  2267. IPropertyStorage *pPStg = NULL; // TSafeStorage< IPropertyStorage > pPStg;
  2268. CPropVariant cpropvar;
  2269. CLIPDATA clipdata;
  2270. PROPSPEC propspec;
  2271. const LPWSTR wszText = L"Unicode Text String";
  2272. FMTID fmtid;
  2273. UuidCreate( &fmtid );
  2274. Check( S_OK, StgToPropSetStg( pStg, &pPSStg ));
  2275. Check(S_OK, pPSStg->Create( fmtid,
  2276. NULL,
  2277. PROPSETFLAG_DEFAULT,
  2278. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2279. &pPStg ));
  2280. propspec.ulKind = PRSPEC_PROPID;
  2281. propspec.propid = 2;
  2282. // -------------------------------
  2283. // Test invalid VT_CF Propvariants
  2284. // -------------------------------
  2285. // NULL clip format.
  2286. clipdata.cbSize = 4;
  2287. clipdata.ulClipFmt = (ULONG) -1;
  2288. clipdata.pClipData = NULL;
  2289. cpropvar = clipdata;
  2290. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  2291. // Too short cbSize.
  2292. ((PROPVARIANT*)&cpropvar)->pclipdata->cbSize = 3;
  2293. Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  2294. // Too short pClipData (it should be 1 byte, but the pClipData is NULL).
  2295. ((PROPVARIANT*)&cpropvar)->pclipdata->cbSize = 5;
  2296. Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  2297. Check( 0, RELEASE_INTERFACE(pPStg) );
  2298. RELEASE_INTERFACE(pPSStg);
  2299. }
  2300. void
  2301. test_ParameterValidation(IStorage *pStg)
  2302. {
  2303. // We only run this test on WIN32 builds, because we need
  2304. // the VirtualAlloc routine.
  2305. #ifdef WIN32
  2306. Status( "Parameter Validation\n" );
  2307. IPropertySetStorage *pPSStg = NULL;
  2308. IPropertyStorage *pPStg = NULL;
  2309. FMTID fmtid;
  2310. UuidCreate( &fmtid );
  2311. LPFMTID pfmtidNULL = NULL;
  2312. LPFMTID pfmtidInvalid = (LPFMTID) INVALID_POINTER;
  2313. PAPP_COMPAT_INFO pAppCompatInfo = NULL;
  2314. DWORD dwOldProtect;
  2315. Check( S_OK, StgToPropSetStg( pStg, &pPSStg ));
  2316. // By default, pointer validation is turned off in ole32 (as of Whistler).
  2317. // Enable it for our process so that we can test the checks.
  2318. PAPP_COMPAT_INFO pAppCompatInfoSave = (PAPP_COMPAT_INFO) NtCurrentPeb()->AppCompatInfo;
  2319. APP_COMPAT_INFO AppCompatInfoNew;
  2320. memset( &AppCompatInfoNew, 0, sizeof(AppCompatInfoNew) );
  2321. AppCompatInfoNew.CompatibilityFlags.QuadPart |= KACF_OLE32VALIDATEPTRS;
  2322. NtCurrentPeb()->AppCompatInfo = &AppCompatInfoNew;
  2323. NtCurrentPeb()->AppCompatFlags.QuadPart = AppCompatInfoNew.CompatibilityFlags.QuadPart;
  2324. // Define two invalid property names
  2325. OLECHAR oszTooLongName[ CCH_MAXPROPNAMESZ + 1 ];
  2326. LPOLESTR poszTooLongName = oszTooLongName;
  2327. OLECHAR oszTooShortName[] = { L"" };
  2328. LPOLESTR poszTooShortName = oszTooShortName;
  2329. PROPSPEC propspecTooLongName = { PRSPEC_LPWSTR };
  2330. PROPSPEC propspecTooShortName = { PRSPEC_LPWSTR };
  2331. propspecTooLongName.lpwstr = oszTooLongName;
  2332. propspecTooShortName.lpwstr = oszTooShortName;
  2333. for( int i = 0; i < sizeof(oszTooLongName)/sizeof(oszTooLongName[0]); i++ )
  2334. oszTooLongName[i] = OLESTR('a');
  2335. oszTooLongName[ sizeof(oszTooLongName)/sizeof(oszTooLongName[0]) ] = OLESTR('\0');
  2336. // Define several arrays which will be created with special
  2337. // protections. For all of this vectors, the first element
  2338. // will be in a page to which we have all access rights. The
  2339. // second element will be in a page for which we have no access,
  2340. // read access, or all access. The variables are named
  2341. // according to the access rights in the second element.
  2342. // The '...Base' variables are pointers to the base of
  2343. // the allocated memory (and must therefore be freed).
  2344. // The corresponding variables without the "Base" postfix
  2345. // are the vector pointers.
  2346. PROPSPEC *rgpropspecNoAccessBase, *rgpropspecNoAccess;
  2347. CPropVariant *rgcpropvarReadAccessBase, *rgcpropvarReadAccess;
  2348. CPropVariant *rgcpropvarNoAccessBase, *rgcpropvarNoAccess;
  2349. PROPID *rgpropidNoAccessBase, *rgpropidNoAccess;
  2350. PROPID *rgpropidReadAccessBase, *rgpropidReadAccess;
  2351. LPWSTR *rglpwstrNoAccessBase, *rglpwstrNoAccess;
  2352. LPWSTR *rglpwstrReadAccessBase, *rglpwstrReadAccess;
  2353. STATPROPSETSTG *rgStatPSStgReadAccessBase, *rgStatPSStgReadAccess;
  2354. STATPROPSTG *rgStatPStgReadAccessBase, *rgStatPStgReadAccess;
  2355. PROPSPEC rgpropspecAllAccess[1];
  2356. CPropVariant rgcpropvarAllAccess[1];
  2357. PROPID rgpropidAllAccess[1];
  2358. LPWSTR rglpwstrAllAccess[1];
  2359. LPWSTR rglpwstrInvalid[1];
  2360. STATPROPSETSTG rgStatPSStgAllAccess[1];
  2361. STATPROPSTG rgStatPStgAllAccess[1];
  2362. // Allocate memory for the vectors and set the vector
  2363. // pointers.
  2364. PROPID propidDefault = PID_FIRST_USABLE;
  2365. LPWSTR lpwstrNameDefault = L"Property Name";
  2366. Check(TRUE, Alloc2PageVector( &rgpropspecNoAccessBase,
  2367. &rgpropspecNoAccess,
  2368. (ULONG) PAGE_NOACCESS,
  2369. (PROPSPEC*) NULL ));
  2370. Check(TRUE, Alloc2PageVector( &rgcpropvarReadAccessBase,
  2371. &rgcpropvarReadAccess,
  2372. (ULONG) PAGE_READONLY,
  2373. (CPropVariant*) NULL ));
  2374. Check(TRUE, Alloc2PageVector( &rgcpropvarNoAccessBase,
  2375. &rgcpropvarNoAccess,
  2376. (ULONG) PAGE_NOACCESS,
  2377. (CPropVariant*) NULL ));
  2378. Check(TRUE, Alloc2PageVector( &rgpropidNoAccessBase,
  2379. &rgpropidNoAccess,
  2380. (ULONG) PAGE_NOACCESS,
  2381. &propidDefault ));
  2382. Check(TRUE, Alloc2PageVector( &rgpropidReadAccessBase,
  2383. &rgpropidReadAccess,
  2384. (ULONG) PAGE_READONLY,
  2385. &propidDefault ));
  2386. Check(TRUE, Alloc2PageVector( &rglpwstrNoAccessBase,
  2387. &rglpwstrNoAccess,
  2388. (ULONG) PAGE_NOACCESS,
  2389. &lpwstrNameDefault ));
  2390. Check(TRUE, Alloc2PageVector( &rglpwstrReadAccessBase,
  2391. &rglpwstrReadAccess,
  2392. (ULONG) PAGE_READONLY,
  2393. &lpwstrNameDefault ));
  2394. Check(TRUE, Alloc2PageVector( &rgStatPSStgReadAccessBase,
  2395. &rgStatPSStgReadAccess,
  2396. (ULONG) PAGE_READONLY,
  2397. (STATPROPSETSTG*) NULL ));
  2398. Check(TRUE, Alloc2PageVector( &rgStatPStgReadAccessBase,
  2399. &rgStatPStgReadAccess,
  2400. (ULONG) PAGE_READONLY,
  2401. (STATPROPSTG*) NULL ));
  2402. rglpwstrAllAccess[0] = rglpwstrNoAccess[0] = rglpwstrReadAccess[0] = L"Property Name";
  2403. // Create restricted buffers for misc tests
  2404. BYTE *pbReadOnly = (BYTE*) VirtualAlloc( NULL, 1, MEM_COMMIT, PAGE_READONLY );
  2405. Check( TRUE, pbReadOnly != NULL );
  2406. BYTE *pbNoAccess = (BYTE*) VirtualAlloc( NULL, 1, MEM_COMMIT, PAGE_NOACCESS );
  2407. // ----------------------------------------
  2408. // Test IPropertySetStorage::QueryInterface
  2409. // ----------------------------------------
  2410. IUnknown *pUnk = NULL;
  2411. #if 0
  2412. // This test cannot run because CPropertySetStorage::QueryInterface is a virtual
  2413. // function, and since CExposedDocFile is derived from CPropertySetStorage,
  2414. // it is inaccessibl.
  2415. // Invalid REFIID
  2416. Check(E_INVALIDARG, ((CExposedDocFile*)&pPSStg)->CPropertySetStorage::QueryInterface( (REFIID) *pfmtidNULL, (void**)&pUnk ));
  2417. Check(E_INVALIDARG, pPSStg->QueryInterface( (REFIID) *pfmtidInvalid, (void**)&pUnk ));
  2418. // Invalid IUnknown*
  2419. Check(E_INVALIDARG, pPSStg->QueryInterface( IID_IUnknown, NULL ));
  2420. Check(E_INVALIDARG, pPSStg->QueryInterface( IID_IUnknown, (void**) INVALID_POINTER ));
  2421. #endif
  2422. // --------------------------------
  2423. // Test IPropertySetStorage::Create
  2424. // --------------------------------
  2425. // Invalid REFFMTID
  2426. Check(E_INVALIDARG, pPSStg->Create( *pfmtidNULL,
  2427. NULL,
  2428. PROPSETFLAG_DEFAULT,
  2429. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2430. &pPStg ));
  2431. Check(E_INVALIDARG, pPSStg->Create( *pfmtidInvalid,
  2432. NULL,
  2433. PROPSETFLAG_DEFAULT,
  2434. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2435. &pPStg ));
  2436. // Invalid Class ID pointer
  2437. Check(E_INVALIDARG, pPSStg->Create( FMTID_NULL,
  2438. (GUID*) INVALID_POINTER,
  2439. PROPSETFLAG_DEFAULT,
  2440. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2441. &pPStg ));
  2442. // Invalid PropSetFlag
  2443. Check(STG_E_INVALIDFLAG, pPSStg->Create( FMTID_NULL,
  2444. &CLSID_NULL,
  2445. PROPSETFLAG_UNBUFFERED, // Only supported in APIs
  2446. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2447. &pPStg ));
  2448. Check(STG_E_INVALIDFLAG, pPSStg->Create( FMTID_NULL,
  2449. &CLSID_NULL,
  2450. 0xffffffff,
  2451. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2452. &pPStg ));
  2453. // Invalid mode
  2454. Check(STG_E_INVALIDFLAG, pPSStg->Create( FMTID_NULL,
  2455. &CLSID_NULL,
  2456. PROPSETFLAG_DEFAULT,
  2457. STGM_DIRECT | STGM_SHARE_DENY_NONE,
  2458. &pPStg ));
  2459. // Invalid IPropertyStorage**
  2460. Check(E_INVALIDARG, pPSStg->Create( FMTID_NULL,
  2461. &CLSID_NULL,
  2462. PROPSETFLAG_DEFAULT,
  2463. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2464. NULL ));
  2465. Check(E_INVALIDARG, pPSStg->Create( FMTID_NULL,
  2466. &CLSID_NULL,
  2467. PROPSETFLAG_DEFAULT,
  2468. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2469. (IPropertyStorage **) INVALID_POINTER ));
  2470. // ------------------------------
  2471. // Test IPropertySetStorage::Open
  2472. // ------------------------------
  2473. // Invalid REFFMTID
  2474. Check(E_INVALIDARG, pPSStg->Open( *pfmtidNULL,
  2475. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2476. &pPStg ));
  2477. Check(E_INVALIDARG, pPSStg->Open( *pfmtidInvalid,
  2478. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2479. &pPStg ));
  2480. Check(STG_E_INVALIDFLAG, pPSStg->Open( FMTID_NULL, STGM_DIRECT | STGM_SHARE_DENY_NONE, &pPStg ));
  2481. // Invalid IPropertyStorage**
  2482. Check(E_INVALIDARG, pPSStg->Open( FMTID_NULL,
  2483. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2484. NULL ));
  2485. Check(E_INVALIDARG, pPSStg->Open( FMTID_NULL,
  2486. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2487. (IPropertyStorage**) INVALID_POINTER ));
  2488. // --------------------------------
  2489. // Test IPropertySetStorage::Delete
  2490. // --------------------------------
  2491. // Invalid REFFMTID.
  2492. Check(E_INVALIDARG, pPSStg->Delete( *pfmtidNULL ));
  2493. Check(E_INVALIDARG, pPSStg->Delete( (REFFMTID) *pfmtidInvalid ));
  2494. // ------------------------------
  2495. // Test IPropertySetStorage::Enum
  2496. // ------------------------------
  2497. // Invalid IEnumSTATPROPSETSTG
  2498. Check(E_INVALIDARG, pPSStg->Enum( (IEnumSTATPROPSETSTG **) NULL ));
  2499. Check(E_INVALIDARG, pPSStg->Enum( (IEnumSTATPROPSETSTG **) INVALID_POINTER ));
  2500. // -------------
  2501. // Test PROPSPEC
  2502. // -------------
  2503. // Create a PropertyStorage
  2504. Check(S_OK, pPSStg->Create( fmtid,
  2505. NULL,
  2506. PROPSETFLAG_DEFAULT,
  2507. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2508. &pPStg ));
  2509. // Invalid ulKind
  2510. rgpropspecAllAccess[0].ulKind = (ULONG) -1;
  2511. rgpropspecAllAccess[0].lpwstr = NULL;
  2512. Check(E_INVALIDARG, pPStg->ReadMultiple( 1,
  2513. rgpropspecAllAccess,
  2514. rgcpropvarAllAccess ));
  2515. Check(E_INVALIDARG, pPStg->WriteMultiple( 1,
  2516. rgpropspecAllAccess,
  2517. rgcpropvarAllAccess,
  2518. 2 ));
  2519. Check(E_INVALIDARG, pPStg->DeleteMultiple( 1,
  2520. rgpropspecAllAccess ));
  2521. // Too short PROPSPEC
  2522. rgpropspecNoAccess[0].ulKind = PRSPEC_PROPID;
  2523. rgpropspecNoAccess[0].propid = 2;
  2524. Check(E_INVALIDARG, pPStg->ReadMultiple( 2,
  2525. rgpropspecNoAccess,
  2526. rgcpropvarAllAccess ));
  2527. Check(E_INVALIDARG, pPStg->WriteMultiple( 2,
  2528. rgpropspecNoAccess,
  2529. rgcpropvarAllAccess,
  2530. 2 ));
  2531. Check(E_INVALIDARG, pPStg->DeleteMultiple( 2,
  2532. rgpropspecNoAccess ));
  2533. // -------------------------------------
  2534. // Test IPropertyStorage::QueryInterface
  2535. // -------------------------------------
  2536. // Invalid REFIID
  2537. Check(E_INVALIDARG, pPStg->QueryInterface( (REFIID) *pfmtidNULL, (void**)&pUnk ));
  2538. Check(E_INVALIDARG, pPStg->QueryInterface( (REFIID) *pfmtidInvalid, (void**)&pUnk ));
  2539. // Invalid IUnknown*
  2540. Check(E_INVALIDARG, pPStg->QueryInterface( IID_IUnknown, NULL ));
  2541. Check(E_INVALIDARG, pPStg->QueryInterface( IID_IUnknown, (void**) INVALID_POINTER ));
  2542. // -----------------------------------
  2543. // Test IPropertyStorage::ReadMultiple
  2544. // -----------------------------------
  2545. rgpropspecAllAccess[0].ulKind = PRSPEC_LPWSTR;
  2546. rgpropspecAllAccess[0].lpwstr = OLESTR("Test Property");
  2547. // Too short count
  2548. Check(S_FALSE, pPStg->ReadMultiple( 0,
  2549. rgpropspecAllAccess,
  2550. rgcpropvarAllAccess));
  2551. // Too long a count for the PropVariant
  2552. Check(E_INVALIDARG, pPStg->ReadMultiple( 2,
  2553. rgpropspecAllAccess,
  2554. (PROPVARIANT*) (void*) rgcpropvarReadAccess ));
  2555. // Invalid PropVariant[]
  2556. Check(E_INVALIDARG, pPStg->ReadMultiple( 1,
  2557. rgpropspecAllAccess,
  2558. NULL ));
  2559. Check(E_INVALIDARG, pPStg->ReadMultiple( 1,
  2560. rgpropspecAllAccess,
  2561. (LPPROPVARIANT) INVALID_POINTER ));
  2562. // Bad PROPSPECs
  2563. // If we ever add a version-0 property set compatibility mode, we should add this test back.
  2564. // Check(STG_E_INVALIDPARAMETER, pPStg->ReadMultiple( 1, &propspecTooLongName, rgcpropvarAllAccess ));
  2565. Check(STG_E_INVALIDPARAMETER, pPStg->ReadMultiple( 1, &propspecTooShortName, rgcpropvarAllAccess ));
  2566. // ------------------------------------
  2567. // Test IPropertyStorage::WriteMultiple
  2568. // ------------------------------------
  2569. rgpropspecAllAccess[0].ulKind = PRSPEC_LPWSTR;
  2570. rgpropspecAllAccess[0].lpwstr = L"Test Property";
  2571. rgcpropvarAllAccess[0] = (long) 1;
  2572. // Too short count
  2573. Check(S_OK, pPStg->WriteMultiple( 0,
  2574. rgpropspecAllAccess,
  2575. (PROPVARIANT*)(void*)rgcpropvarAllAccess,
  2576. 2));
  2577. // Too short PropVariant
  2578. Check(E_INVALIDARG, pPStg->WriteMultiple( 2,
  2579. rgpropspecAllAccess,
  2580. (PROPVARIANT*)(void*)rgcpropvarNoAccess,
  2581. PID_FIRST_USABLE ));
  2582. // Invalid PropVariant[]
  2583. Check(E_INVALIDARG, pPStg->WriteMultiple( 1,
  2584. rgpropspecAllAccess,
  2585. NULL,
  2586. 2));
  2587. Check(E_INVALIDARG, pPStg->WriteMultiple( 1,
  2588. rgpropspecAllAccess,
  2589. (LPPROPVARIANT) INVALID_POINTER,
  2590. PID_FIRST_USABLE));
  2591. // Bad PROPSPECs
  2592. // If we ever add a version-0 property set compatibility mode, we should add this test back.
  2593. // Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspecTooLongName, rgcpropvarAllAccess,
  2594. // PID_FIRST_USABLE ));
  2595. Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspecTooShortName, rgcpropvarAllAccess,
  2596. PID_FIRST_USABLE ));
  2597. // -------------------------------------
  2598. // Test IPropertyStorage::DeleteMultiple
  2599. // -------------------------------------
  2600. // Invalid count
  2601. Check(S_OK, pPStg->DeleteMultiple( 0,
  2602. rgpropspecAllAccess ));
  2603. // Bad PROPSPECs
  2604. // If we ever add a version-0 property set compatibility mode, we should add this test back.
  2605. // Check(STG_E_INVALIDPARAMETER, pPStg->DeleteMultiple( 1, &propspecTooLongName ));
  2606. Check(STG_E_INVALIDPARAMETER, pPStg->DeleteMultiple( 1, &propspecTooShortName ));
  2607. // ----------------------------------------
  2608. // Test IPropertyStorage::ReadPropertyNames
  2609. // ----------------------------------------
  2610. // Create a property with the name we're going to use.
  2611. rgpropspecAllAccess[0].ulKind = PRSPEC_LPWSTR;
  2612. rgpropspecAllAccess[0].lpwstr = rglpwstrAllAccess[0];
  2613. Check(S_OK, pPStg->WriteMultiple( 1,
  2614. rgpropspecAllAccess,
  2615. &rgcpropvarAllAccess[0],
  2616. PID_FIRST_USABLE ));
  2617. // Invalid count
  2618. Check(S_FALSE, pPStg->ReadPropertyNames( 0,
  2619. rgpropidAllAccess,
  2620. rglpwstrAllAccess ));
  2621. // Too short PROPID[] or LPWSTR[]
  2622. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 2,
  2623. rgpropidNoAccess,
  2624. rglpwstrAllAccess ));
  2625. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 2,
  2626. rgpropidAllAccess,
  2627. rglpwstrReadAccess ));
  2628. // Invalid rgpropid[]
  2629. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 1,
  2630. NULL,
  2631. rglpwstrAllAccess ));
  2632. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 1,
  2633. (PROPID*) INVALID_POINTER,
  2634. rglpwstrAllAccess ));
  2635. // Invalid rglpwstr[]
  2636. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 1,
  2637. rgpropidAllAccess,
  2638. NULL ));
  2639. Check(E_INVALIDARG, pPStg->ReadPropertyNames( 1,
  2640. rgpropidAllAccess,
  2641. (LPWSTR*) INVALID_POINTER ));
  2642. // -----------------------------------------
  2643. // Test IPropertyStorage::WritePropertyNames
  2644. // -----------------------------------------
  2645. // Invalid count
  2646. Check(S_OK, pPStg->WritePropertyNames( 0,
  2647. NULL,
  2648. rglpwstrAllAccess ));
  2649. // Too short PROPID[] or LPWSTR[]
  2650. Check(E_INVALIDARG, pPStg->WritePropertyNames( 2,
  2651. rgpropidNoAccess,
  2652. rglpwstrAllAccess ));
  2653. Check(E_INVALIDARG, pPStg->WritePropertyNames( 2,
  2654. rgpropidAllAccess,
  2655. rglpwstrNoAccess ));
  2656. Check(S_OK, pPStg->WritePropertyNames( 2,
  2657. rgpropidAllAccess,
  2658. rglpwstrReadAccess ));
  2659. // Invalid rgpropid[]
  2660. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2661. NULL,
  2662. rglpwstrAllAccess ));
  2663. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2664. (PROPID*) INVALID_POINTER,
  2665. rglpwstrAllAccess ));
  2666. // Invalid rglpwstr[]
  2667. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2668. rgpropidAllAccess,
  2669. NULL ));
  2670. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2671. rgpropidAllAccess,
  2672. (LPWSTR*) INVALID_POINTER ));
  2673. // Invalid name.
  2674. rglpwstrInvalid[0] = NULL;
  2675. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2676. rgpropidAllAccess,
  2677. rglpwstrInvalid ));
  2678. rglpwstrInvalid[0] = (LPWSTR) INVALID_POINTER;
  2679. Check(E_INVALIDARG, pPStg->WritePropertyNames( 1,
  2680. rgpropidAllAccess,
  2681. rglpwstrInvalid ));
  2682. // Invalid length names
  2683. // If we ever add a version-0 property set compatibility mode, we should add this test back.
  2684. // Check(STG_E_INVALIDPARAMETER, pPStg->WritePropertyNames( 1, rgpropidAllAccess, &poszTooLongName ));
  2685. Check(STG_E_INVALIDPARAMETER, pPStg->WritePropertyNames( 1, rgpropidAllAccess, &poszTooShortName ));
  2686. // ------------------------------------------
  2687. // Test IPropertyStorage::DeletePropertyNames
  2688. // ------------------------------------------
  2689. // Invalid count
  2690. Check(S_OK, pPStg->DeletePropertyNames( 0,
  2691. rgpropidAllAccess ));
  2692. // Too short PROPID[]
  2693. Check(E_INVALIDARG, pPStg->DeletePropertyNames( 2,
  2694. rgpropidNoAccess ));
  2695. Check(S_OK, pPStg->DeletePropertyNames( 2,
  2696. rgpropidReadAccess ));
  2697. // Invalid rgpropid[]
  2698. Check(E_INVALIDARG, pPStg->DeletePropertyNames( 1,
  2699. NULL ));
  2700. Check(E_INVALIDARG, pPStg->DeletePropertyNames( 1,
  2701. (PROPID*) INVALID_POINTER ));
  2702. // ---------------------------
  2703. // Test IPropertyStorage::Enum
  2704. // ---------------------------
  2705. // Invalid IEnumSTATPROPSTG
  2706. Check(E_INVALIDARG, pPStg->Enum( NULL ));
  2707. Check(E_INVALIDARG, pPStg->Enum( (IEnumSTATPROPSTG**) INVALID_POINTER ));
  2708. // --------------------------------------
  2709. // Test IPropertyStorage::SetElementTimes
  2710. // --------------------------------------
  2711. Check(E_INVALIDARG, pPStg->SetTimes( (FILETIME*) INVALID_POINTER,
  2712. NULL, NULL ));
  2713. Check(E_INVALIDARG, pPStg->SetTimes( NULL,
  2714. (FILETIME*) INVALID_POINTER,
  2715. NULL ));
  2716. Check(E_INVALIDARG, pPStg->SetTimes( NULL, NULL,
  2717. (FILETIME*) INVALID_POINTER ));
  2718. // -------------------------------
  2719. // Test IPropertyStorage::SetClass
  2720. // -------------------------------
  2721. Check(E_INVALIDARG, pPStg->SetClass( (REFCLSID) *pfmtidNULL ));
  2722. Check(E_INVALIDARG, pPStg->SetClass( (REFCLSID) *pfmtidInvalid ));
  2723. // ---------------------------
  2724. // Test IPropertyStorage::Stat
  2725. // ---------------------------
  2726. Check(E_INVALIDARG, pPStg->Stat( NULL ));
  2727. Check(E_INVALIDARG, pPStg->Stat( (STATPROPSETSTG*) INVALID_POINTER ));
  2728. // ------------------------------
  2729. // Test IEnumSTATPROPSETSTG::Next
  2730. // ------------------------------
  2731. ULONG cEltFound;
  2732. IEnumSTATPROPSETSTG *pESPSStg = NULL; // TSafeStorage< IEnumSTATPROPSETSTG > pESPSStg;
  2733. Check(S_OK, pPSStg->Enum( &pESPSStg ));
  2734. // Invalid STATPROPSETSTG*
  2735. Check(E_INVALIDARG, pESPSStg->Next( 1, NULL, &cEltFound ));
  2736. Check(E_INVALIDARG, pESPSStg->Next( 1, (STATPROPSETSTG*) INVALID_POINTER, &cEltFound ));
  2737. // Invalid pceltFound
  2738. Check(S_OK, pESPSStg->Next( 1, rgStatPSStgAllAccess, NULL ));
  2739. Check(STG_E_INVALIDPARAMETER, pESPSStg->Next( 2, rgStatPSStgAllAccess, NULL ));
  2740. Check(E_INVALIDARG, pESPSStg->Next( 2, rgStatPSStgAllAccess, (ULONG*) INVALID_POINTER ));
  2741. // Too short STATPROPSETSTG[]
  2742. Check(E_INVALIDARG, pESPSStg->Next( 2, rgStatPSStgReadAccess, &cEltFound ));
  2743. // -------------------------------
  2744. // Test IEnumSTATPROPSETSTG::Clone
  2745. // -------------------------------
  2746. // Invalid IEnumSTATPROPSETSTG**
  2747. Check(E_INVALIDARG, pESPSStg->Clone( NULL ));
  2748. Check(E_INVALIDARG, pESPSStg->Clone( (IEnumSTATPROPSETSTG**) INVALID_POINTER ));
  2749. // ---------------------------
  2750. // Test IEnumSTATPROPSTG::Next
  2751. // ---------------------------
  2752. IEnumSTATPROPSTG *pESPStg = NULL; // TSafeStorage< IEnumSTATPROPSTG > pESPStg;
  2753. Check(S_OK, pPStg->Enum( &pESPStg ));
  2754. // Invalid STATPROPSETSTG*
  2755. Check(E_INVALIDARG, pESPStg->Next( 1, NULL, &cEltFound ));
  2756. Check(E_INVALIDARG, pESPStg->Next( 1, (STATPROPSTG*) INVALID_POINTER, &cEltFound ));
  2757. // Invalid pceltFound
  2758. Check(S_OK, pESPStg->Next( 1, rgStatPStgAllAccess, NULL ));
  2759. Check(STG_E_INVALIDPARAMETER, pESPStg->Next( 2, rgStatPStgAllAccess, NULL ));
  2760. Check(E_INVALIDARG, pESPStg->Next( 2, rgStatPStgAllAccess, (ULONG*) INVALID_POINTER ));
  2761. // Too short STATPROPSTG[]
  2762. Check(E_INVALIDARG, pESPStg->Next( 2, rgStatPStgReadAccess, &cEltFound ));
  2763. // ----------------------------
  2764. // Test IEnumSTATPROPSTG::Clone
  2765. // ----------------------------
  2766. // Invalid IEnumSTATPROPSETSTG**
  2767. Check(E_INVALIDARG, pESPStg->Clone( NULL ));
  2768. Check(E_INVALIDARG, pESPStg->Clone( (IEnumSTATPROPSTG**) INVALID_POINTER ));
  2769. // --------------------------------------------
  2770. // Test PropStgNameToFmtId & FmtIdToPropStgName
  2771. // --------------------------------------------
  2772. // We're done with the IPropertyStorage and IPropertySetStorage
  2773. // now, but we need the pointers for some calls below, so let's
  2774. // free them now.
  2775. RELEASE_INTERFACE(pPStg);
  2776. RELEASE_INTERFACE(pPSStg);
  2777. RELEASE_INTERFACE(pESPStg);
  2778. // In some cases we can't test these APIs, so only test them
  2779. // if we have the function pointers.
  2780. if( g_pfnPropStgNameToFmtId && g_pfnFmtIdToPropStgName )
  2781. {
  2782. OLECHAR oszPropStgName[ CCH_MAX_PROPSTG_NAME+1 ];
  2783. FMTID fmtidPropStgName = FMTID_NULL;
  2784. // Validate the FMTID parm
  2785. Check( E_INVALIDARG, g_pfnPropStgNameToFmtId( oszPropStgName, pfmtidNULL ));
  2786. Check( E_INVALIDARG, g_pfnPropStgNameToFmtId( oszPropStgName, pfmtidInvalid ));
  2787. Check( E_INVALIDARG, g_pfnPropStgNameToFmtId( oszPropStgName, (FMTID*) pbReadOnly ));
  2788. Check( E_INVALIDARG, g_pfnFmtIdToPropStgName( pfmtidNULL, oszPropStgName ));
  2789. Check( E_INVALIDARG, g_pfnFmtIdToPropStgName( pfmtidInvalid, oszPropStgName ));
  2790. Check( S_OK, g_pfnFmtIdToPropStgName( (FMTID*) pbReadOnly, oszPropStgName ));
  2791. // Validate the name parameter
  2792. /*
  2793. Check( STG_E_INVALIDNAME, g_pfnPropStgNameToFmtId( NULL, &fmtidPropStgName ));
  2794. Check( STG_E_INVALIDNAME, g_pfnPropStgNameToFmtId( (LPOLESTR) INVALID_POINTER, &fmtidPropStgName ));
  2795. Check( STG_E_INVALIDNAME, g_pfnPropStgNameToFmtId( (LPOLESTR) pbNoAccess, &fmtidPropStgName));
  2796. Check( S_OK, g_pfnPropStgNameToFmtId( (LPOLESTR) pbReadOnly, &fmtidPropStgName ));
  2797. Check( E_INVALIDARG, g_pfnFmtIdToPropStgName( &fmtidPropStgName, NULL ));
  2798. Check( E_INVALIDARG, g_pfnFmtIdToPropStgName( &fmtidPropStgName, (LPOLESTR) INVALID_POINTER ));
  2799. Check( E_INVALIDARG, g_pfnFmtIdToPropStgName( &fmtidPropStgName, (LPOLESTR) pbReadOnly ));
  2800. */
  2801. } // if( g_pfnPropStgNameToFmtId && g_pfnFmtIdToPropStgName )
  2802. // ------------------------------------------
  2803. // Test StgCreatePropStg, StgOpenPropStg APIs
  2804. // ------------------------------------------
  2805. // In some cases we can't test these APIs, so only test them
  2806. // if we have the function pointers.
  2807. if( g_pfnStgCreatePropSetStg && g_pfnStgCreatePropStg && g_pfnStgOpenPropStg
  2808. &&
  2809. !(RESTRICT_SIMPLE_ONLY & g_Restrictions) )
  2810. {
  2811. FMTID fmtidPropStgName = FMTID_NULL;
  2812. IStream *pStm = NULL; // TSafeStorage< IStream > pStm;
  2813. // We need a Stream for one of the tests.
  2814. Check( S_OK, pStg->CreateStream( OLESTR( "Parameter Validation" ),
  2815. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2816. 0L, 0L,
  2817. &pStm ));
  2818. // Test the IUnknown
  2819. Check( E_INVALIDARG, g_pfnStgCreatePropStg( NULL, fmtidPropStgName, NULL, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2820. Check( E_INVALIDARG, g_pfnStgOpenPropStg( NULL, fmtidPropStgName, PROPSETFLAG_DEFAULT, 0L, &pPStg ));
  2821. // Test the FMTID
  2822. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, *pfmtidNULL, NULL, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2823. Check( E_INVALIDARG, g_pfnStgOpenPropStg( (IUnknown*) pStm, *pfmtidNULL, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2824. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, *pfmtidInvalid, NULL, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2825. Check( E_INVALIDARG, g_pfnStgOpenPropStg( (IUnknown*) pStm, *pfmtidInvalid, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2826. // Test the CLSID
  2827. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, (CLSID*) pfmtidInvalid, PROPSETFLAG_DEFAULT, 0, &pPStg ));
  2828. // Test grfFlags
  2829. Check( STG_E_INVALIDFLAG, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, NULL, 0x8000, 0L, &pPStg ));
  2830. Check( STG_E_INVALIDFLAG, g_pfnStgOpenPropStg( (IUnknown*) pStm, fmtidPropStgName, 0x8000, 0L, &pPStg ));
  2831. Check( E_NOINTERFACE, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, NULL, PROPSETFLAG_NONSIMPLE, 0L, &pPStg ));
  2832. Check( E_NOINTERFACE, g_pfnStgCreatePropStg( (IUnknown*) pStg, fmtidPropStgName, NULL, PROPSETFLAG_DEFAULT, 0L, &pPStg ));
  2833. Check( E_NOINTERFACE, g_pfnStgOpenPropStg( (IUnknown*) pStm, fmtidPropStgName, PROPSETFLAG_NONSIMPLE, 0L, &pPStg ));
  2834. Check( E_NOINTERFACE, g_pfnStgOpenPropStg( (IUnknown*) pStg, fmtidPropStgName, PROPSETFLAG_DEFAULT , 0L, &pPStg ));
  2835. // Test IPropertyStorage**
  2836. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, NULL, PROPSETFLAG_DEFAULT, 0L, NULL ));
  2837. Check( E_INVALIDARG, g_pfnStgOpenPropStg( (IUnknown*) pStm, fmtidPropStgName, PROPSETFLAG_DEFAULT, 0L, NULL ));
  2838. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, NULL, PROPSETFLAG_DEFAULT, 0L, (IPropertyStorage**) INVALID_POINTER ));
  2839. Check( E_INVALIDARG, g_pfnStgOpenPropStg( (IUnknown*) pStm, fmtidPropStgName, PROPSETFLAG_DEFAULT, 0L, (IPropertyStorage**) INVALID_POINTER ));
  2840. Check( E_INVALIDARG, g_pfnStgCreatePropStg( (IUnknown*) pStm, fmtidPropStgName, NULL, PROPSETFLAG_DEFAULT, 0L, (IPropertyStorage**) pbReadOnly ));
  2841. Check( E_INVALIDARG, g_pfnStgOpenPropStg( (IUnknown*) pStm, fmtidPropStgName, PROPSETFLAG_DEFAULT, 0L, (IPropertyStorage**) pbReadOnly ));
  2842. RELEASE_INTERFACE(pStm);
  2843. } // if( g_pfnStgCreatePropSetStg && g_pfnStgCreatePropStg && g_pfnStgOpenPropStg )
  2844. // If we're not using IStorage::QueryInterface to get an IPropertySetStorage,
  2845. // we must be using the new APIs, so let's test them.
  2846. // ----------------------------
  2847. // Test StgCreatePropSetStg API
  2848. // ----------------------------
  2849. // In some cases we can't test these APIs, so only test them
  2850. // if we have the function pointers.
  2851. if( g_pfnStgCreatePropSetStg && g_pfnStgCreatePropStg && g_pfnStgOpenPropStg )
  2852. {
  2853. // Test the IStorage*
  2854. Check( E_INVALIDARG, g_pfnStgCreatePropSetStg( NULL, 0L, &pPSStg ));
  2855. Check( E_INVALIDARG, g_pfnStgCreatePropSetStg( (IStorage*) INVALID_POINTER, 0L, &pPSStg ));
  2856. // Test the IPropertySetStorage**
  2857. Check( E_INVALIDARG, g_pfnStgCreatePropSetStg( pStg, 0L, NULL ));
  2858. Check( E_INVALIDARG, g_pfnStgCreatePropSetStg( pStg, 0L, (IPropertySetStorage**) INVALID_POINTER ));
  2859. // -------------------------------------------------------------
  2860. // Test g_pfnPropVariantCopy, PropVariantClear & FreePropVariantArray
  2861. // -------------------------------------------------------------
  2862. // PropVariantCopy
  2863. Check( E_INVALIDARG, g_pfnPropVariantCopy( rgcpropvarAllAccess, NULL ));
  2864. Check( E_INVALIDARG, g_pfnPropVariantCopy( rgcpropvarAllAccess, (PROPVARIANT*) INVALID_POINTER ));
  2865. Check( E_INVALIDARG, g_pfnPropVariantCopy( NULL, rgcpropvarAllAccess ));
  2866. Check( E_INVALIDARG, g_pfnPropVariantCopy( (PROPVARIANT*) INVALID_POINTER, rgcpropvarAllAccess ));
  2867. Check( E_INVALIDARG, g_pfnPropVariantCopy( (PROPVARIANT*) pbReadOnly, rgcpropvarAllAccess ));
  2868. // PropVariantClear
  2869. Check( S_OK, g_pfnPropVariantClear( NULL ));
  2870. Check( E_INVALIDARG, g_pfnPropVariantClear( (PROPVARIANT*) INVALID_POINTER ));
  2871. Check( E_INVALIDARG, g_pfnPropVariantClear( (PROPVARIANT*) pbReadOnly ));
  2872. // FreePropVariantArray
  2873. Check( E_INVALIDARG, g_pfnFreePropVariantArray( 1, NULL ));
  2874. Check( E_INVALIDARG, g_pfnFreePropVariantArray( 1, (PROPVARIANT*) INVALID_POINTER ));
  2875. Check( S_OK, g_pfnFreePropVariantArray( 1, (PROPVARIANT*) (void*)rgcpropvarReadAccess ));
  2876. Check( E_INVALIDARG, g_pfnFreePropVariantArray( 2, (PROPVARIANT*) (void*)rgcpropvarReadAccess ));
  2877. } // if( g_pfnStgCreatePropSetStg && g_pfnStgCreatePropStg && g_pfnStgOpenPropStg )
  2878. // ----
  2879. // Exit
  2880. // ----
  2881. VirtualFree( rgpropspecNoAccessBase, 0, MEM_RELEASE );
  2882. VirtualFree( rgcpropvarReadAccessBase, 0, MEM_RELEASE );
  2883. VirtualFree( rgcpropvarNoAccessBase, 0, MEM_RELEASE );
  2884. VirtualFree( rgpropidNoAccessBase, 0, MEM_RELEASE );
  2885. VirtualFree( rgpropidReadAccessBase, 0, MEM_RELEASE );
  2886. VirtualFree( rglpwstrNoAccessBase, 0, MEM_RELEASE );
  2887. VirtualFree( rglpwstrReadAccessBase, 0, MEM_RELEASE );
  2888. VirtualFree( rgStatPSStgReadAccessBase, 0, MEM_RELEASE );
  2889. VirtualFree( rgStatPStgReadAccessBase, 0, MEM_RELEASE );
  2890. RELEASE_INTERFACE(pPSStg);
  2891. RELEASE_INTERFACE(pPStg);
  2892. RELEASE_INTERFACE(pESPSStg);
  2893. NtCurrentPeb()->AppCompatInfo = pAppCompatInfoSave;
  2894. #endif // #ifdef WIN32
  2895. } // test_ParameterValidation(IStorage *pStg)
  2896. // Check creation/open/deletion of property sets (check fmtid and predefined names)
  2897. // Create a property set
  2898. // Try recreate of same
  2899. // Try delete
  2900. // Close the property set
  2901. // Try recreate of same
  2902. // Reopen the property set
  2903. // Try recreate of same
  2904. // Try delete
  2905. // Close the property set
  2906. // Delete the property set
  2907. // Repeat the test once more
  2908. void
  2909. test_IPropertySetStorage_CreateOpenDelete(IStorage *pStorage)
  2910. {
  2911. Status( "IPropertySetStorage::Create/Open/Delete\n" );
  2912. FMTID fmtid;
  2913. PROPSPEC propspec;
  2914. UuidCreate(&fmtid);
  2915. for (int i=0; i<4; i++)
  2916. {
  2917. DWORD propsetflag;
  2918. if( !(g_Restrictions & RESTRICT_SIMPLE_ONLY) )
  2919. propsetflag = (i & 2) == 0 ? PROPSETFLAG_DEFAULT : PROPSETFLAG_NONSIMPLE;
  2920. else
  2921. propsetflag = PROPSETFLAG_DEFAULT;
  2922. {
  2923. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  2924. IPropertyStorage *PropStg, *PropStg2;
  2925. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  2926. Check( S_OK, pPropSetStg->Create(fmtid,
  2927. NULL,
  2928. propsetflag,
  2929. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2930. &PropStg));
  2931. Check( S_OK, pPropSetStg->Create(fmtid,
  2932. NULL,
  2933. propsetflag,
  2934. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2935. &PropStg2 ));
  2936. Check( STG_E_REVERTED, PropStg->Commit(0) );
  2937. RELEASE_INTERFACE( PropStg );
  2938. RELEASE_INTERFACE( PropStg2 );
  2939. RELEASE_INTERFACE( pPropSetStg );
  2940. }
  2941. {
  2942. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  2943. IPropertyStorage *PropStg, *PropStg2;
  2944. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  2945. // use STGM_FAILIFTHERE
  2946. Check(STG_E_FILEALREADYEXISTS, pPropSetStg->Create(fmtid,
  2947. NULL,
  2948. propsetflag,
  2949. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2950. &PropStg));
  2951. Check(S_OK, pPropSetStg->Open(fmtid,
  2952. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2953. &PropStg));
  2954. Check( STG_E_ACCESSDENIED,
  2955. pPropSetStg->Open(fmtid,
  2956. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2957. &PropStg2));
  2958. Check( STG_E_ACCESSDENIED,
  2959. pPropSetStg->Create( fmtid,
  2960. NULL,
  2961. propsetflag,
  2962. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2963. &PropStg2));
  2964. // Docfile allows an open element to be deleted (putting open objects
  2965. // in the reverted state). NTFS doesn't allow the delete though.
  2966. Check( (g_Restrictions & RESTRICT_NON_HIERARCHICAL)
  2967. ? STG_E_SHAREVIOLATION
  2968. : S_OK,
  2969. pPropSetStg->Delete(fmtid) );
  2970. propspec.ulKind = PRSPEC_PROPID;
  2971. propspec.propid = 1000;
  2972. PROPVARIANT propvar;
  2973. propvar.vt = VT_I4;
  2974. propvar.lVal = 12345;
  2975. Check((g_Restrictions & RESTRICT_NON_HIERARCHICAL) ? S_OK : STG_E_REVERTED,
  2976. PropStg->WriteMultiple(1, &propspec, &propvar, 2)); // force dirty
  2977. RELEASE_INTERFACE(PropStg);
  2978. RELEASE_INTERFACE(pPropSetStg);
  2979. //Check(S_OK, pPropSetStg->Delete(fmtid));
  2980. }
  2981. }
  2982. }
  2983. void
  2984. test_IPropertySetStorage_SummaryInformation(IStorage *pStorage)
  2985. {
  2986. if( g_Restrictions & RESTRICT_NON_HIERARCHICAL ) return;
  2987. Status( "SummaryInformation\n" );
  2988. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  2989. IPropertyStorage *PropStg;
  2990. IStream *pstm;
  2991. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  2992. Check(S_OK, pPropSetStg->Create(FMTID_SummaryInformation,
  2993. NULL,
  2994. PROPSETFLAG_DEFAULT,
  2995. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2996. &PropStg));
  2997. RELEASE_INTERFACE(PropStg);
  2998. Check(S_OK, pStorage->OpenStream(OLESTR("\005SummaryInformation"),
  2999. NULL,
  3000. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  3001. 0,
  3002. &pstm));
  3003. RELEASE_INTERFACE(pstm);
  3004. RELEASE_INTERFACE(pPropSetStg);
  3005. }
  3006. //
  3007. // Check STGM_FAILIFTHERE and ~STGM_FAILIFTHERE in following cases
  3008. // Check overwriting simple with extant non-simple
  3009. // Check overwriting simple with simple
  3010. // Check overwriting non-simple with simple
  3011. // Check overwriting non-simple with non-simple
  3012. void
  3013. test_IPropertySetStorage_FailIfThere(IStorage *pStorage)
  3014. {
  3015. // (Use "fale" instead of "fail" in this printf so the output won't
  3016. // alarm anyone with the word "fail" uncessarily).
  3017. Status( "IPropertySetStorage, FaleIfThere\n" );
  3018. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3019. ULONG cStorageRefs = GetRefCount( pStorage );
  3020. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3021. // Iter 0 1 2 3 4 5 6 7
  3022. // Create simple nonsimple simple nonsimple simple nonsimple simple nonsimple
  3023. // ReCreate simple simple nonsimple nonsimple simple simple nonsimple nonsimple
  3024. // failif failif failif failif overw overw overw overw
  3025. //
  3026. // expected exists exists exists exists ok ok ok ok
  3027. for (int i=0; i<8; i++)
  3028. {
  3029. FMTID fmtid;
  3030. IPropertyStorage *PropStg;
  3031. DWORD propsetflagNonSimple = (g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_DEFAULT : PROPSETFLAG_NONSIMPLE;
  3032. UuidCreate(&fmtid);
  3033. Check(S_OK, pPropSetStg->Create(fmtid,
  3034. NULL,
  3035. (i & 1) == 1 ? propsetflagNonSimple : 0,
  3036. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  3037. &PropStg));
  3038. PropStg->Release();
  3039. Check((i&4) == 4 ? S_OK : STG_E_FILEALREADYEXISTS,
  3040. pPropSetStg->Create(fmtid,
  3041. NULL,
  3042. (i & 2) == 2 ? propsetflagNonSimple : 0,
  3043. ( (i & 4) == 4 ? STGM_CREATE : STGM_FAILIFTHERE )
  3044. |
  3045. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  3046. &PropStg));
  3047. if (PropStg)
  3048. {
  3049. PropStg->Release();
  3050. }
  3051. }
  3052. RELEASE_INTERFACE( pPropSetStg );
  3053. Check( cStorageRefs, GetRefCount( pStorage ));
  3054. }
  3055. //
  3056. //
  3057. //
  3058. // Bad this pointer.
  3059. // Call all methods with a bad this pointer, check we get STG_E_INVALIDHANDLE
  3060. //
  3061. void
  3062. test_IPropertySetStorage_BadThis(IStorage *pIgnored)
  3063. {
  3064. Status( "Bad IPropertySetStorage 'this' pointer\n" );
  3065. IPropertySetStorage *pBad;
  3066. IID iid;
  3067. FMTID fmtid;
  3068. void *pv;
  3069. IPropertyStorage *pps;
  3070. IEnumSTATPROPSETSTG *penm;
  3071. pBad = reinterpret_cast<IPropertySetStorage*>(&iid);
  3072. Check(STG_E_INVALIDHANDLE,pBad->QueryInterface(iid, &pv));
  3073. Check(0, pBad->AddRef());
  3074. Check(0, pBad->Release());
  3075. Check(STG_E_INVALIDHANDLE,pBad->Create( fmtid, NULL, 0, 0, &pps));
  3076. Check(STG_E_INVALIDHANDLE,pBad->Open(fmtid, 0, &pps));
  3077. Check(STG_E_INVALIDHANDLE,pBad->Delete( fmtid ));
  3078. Check(STG_E_INVALIDHANDLE,pBad->Enum( &penm ));
  3079. }
  3080. // Transacted mode
  3081. // Create a non-simple property set with one VT_STREAM child, close it
  3082. // Open it in transacted mode
  3083. // Write another VT_STORAGE child
  3084. // Close and revert
  3085. // Check that the second child does not exist.
  3086. // Repeat and close and commit and check the child exists.
  3087. void
  3088. test_IPropertySetStorage_TransactedMode(IStorage *pStorage)
  3089. {
  3090. FMTID fmtid;
  3091. UuidCreate(&fmtid);
  3092. if( g_Restrictions & ( RESTRICT_DIRECT_ONLY | RESTRICT_SIMPLE_ONLY )) return;
  3093. Status( "Transacted Mode\n" );
  3094. {
  3095. //
  3096. // create a substorage "teststg" with a propset
  3097. // create a stream "src" which is then written via VT_STREAM as propid 7fffffff
  3098. CTempStorage pSubStorage(coCreate, pStorage, OLESTR("teststg"));
  3099. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pSubStorage);
  3100. Check( S_OK, StgToPropSetStg( pSubStorage, &pPropSetStg ));
  3101. IPropertyStorage *pPropSet;
  3102. IStream *pstm;
  3103. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_NONSIMPLE,
  3104. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  3105. &pPropSet));
  3106. PROPSPEC ps;
  3107. ps.ulKind = PRSPEC_PROPID;
  3108. ps.propid = 0x7ffffffd;
  3109. Check(S_OK, pStorage->CreateStream(OLESTR("src"), STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  3110. 0,0, &pstm));
  3111. Check(S_OK, pstm->Write(L"billmo", 14, NULL));
  3112. Check(S_OK, pstm->Seek(g_li0, STREAM_SEEK_SET, NULL));
  3113. PROPVARIANT pv;
  3114. pv.vt = VT_STREAM;
  3115. pv.pStream = pstm;
  3116. Check(S_OK, pPropSet->WriteMultiple(1, &ps, &pv, 2)); // copies the stream in
  3117. Check( 0, RELEASE_INTERFACE(pPropSet) );
  3118. Check( 0, RELEASE_INTERFACE(pstm) );
  3119. RELEASE_INTERFACE(pPropSetStg);
  3120. }
  3121. {
  3122. IPropertyStorage *pPropSet;
  3123. // Reopen the propset in transacted and add one with id 0x7ffffffe
  3124. CTempStorage pSubStorage(coOpen, pStorage, OLESTR("teststg"), STGM_TRANSACTED);
  3125. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pSubStorage);
  3126. Check( S_OK, StgToPropSetStg( pSubStorage, &pPropSetStg ));
  3127. // Create a storage object to copy
  3128. CTempStorage pstgSrc;
  3129. CTempStorage pTestChild(coCreate, pstgSrc, OLESTR("testchild"));
  3130. Check(S_OK, pPropSetStg->Open(fmtid,
  3131. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  3132. &pPropSet));
  3133. // copy in the storage object
  3134. PROPSPEC ps[2];
  3135. ps[0].ulKind = PRSPEC_PROPID;
  3136. ps[0].propid = 0x7ffffffe;
  3137. ps[1].ulKind = PRSPEC_PROPID;
  3138. ps[1].propid = 0x7ffffff0;
  3139. PROPVARIANT pv[2];
  3140. pv[0].vt = VT_STORAGE;
  3141. pv[0].pStorage = pTestChild;
  3142. pv[1].vt = VT_I4;
  3143. pv[1].lVal = 123;
  3144. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 2)); // copies the storage in
  3145. pSubStorage->Revert(); // throws away the storage
  3146. // check that property set operations return stg_e_reverted
  3147. Check(STG_E_REVERTED, pPropSet->WriteMultiple(2, ps, pv, 2));
  3148. Check(STG_E_REVERTED, pPropSet->ReadMultiple(1, ps+1, pv+1));
  3149. Check(STG_E_REVERTED, pPropSet->DeleteMultiple(1, ps+1));
  3150. LPOLESTR pstr = L"pstr";
  3151. Check(STG_E_REVERTED, pPropSet->ReadPropertyNames(1, &ps[1].propid, &pstr));
  3152. Check(STG_E_REVERTED, pPropSet->WritePropertyNames(1, &ps[1].propid, &pstr));
  3153. Check(STG_E_REVERTED, pPropSet->DeletePropertyNames(1, &ps[1].propid));
  3154. Check(STG_E_REVERTED, pPropSet->Commit(STGC_DEFAULT));
  3155. Check(STG_E_REVERTED, pPropSet->Revert());
  3156. IEnumSTATPROPSTG *penum;
  3157. Check(STG_E_REVERTED, pPropSet->Enum(&penum));
  3158. FILETIME ft;
  3159. Check(STG_E_REVERTED, pPropSet->SetTimes(&ft, &ft, &ft));
  3160. CLSID clsid;
  3161. Check(STG_E_REVERTED, pPropSet->SetClass(clsid));
  3162. STATPROPSETSTG statpropsetstg;
  3163. Check(STG_E_REVERTED, pPropSet->Stat(&statpropsetstg));
  3164. Check( 0, RELEASE_INTERFACE(pPropSet) );
  3165. RELEASE_INTERFACE(pPropSetStg);
  3166. }
  3167. {
  3168. IPropertyStorage *pPropSet;
  3169. // Reopen the propset in direct mode and check that the
  3170. // second child is not there.
  3171. CTempStorage pSubStorage(coOpen, pStorage, OLESTR("teststg"));
  3172. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pSubStorage);
  3173. Check( S_OK, StgToPropSetStg( pSubStorage, &pPropSetStg ));
  3174. Check(S_OK, pPropSetStg->Open(fmtid,
  3175. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  3176. &pPropSet));
  3177. // read out the storage object
  3178. PROPSPEC aps[2];
  3179. aps[0].ulKind = PRSPEC_PROPID;
  3180. aps[0].propid = 0x7ffffffe; // storage not expected
  3181. aps[1].ulKind = PRSPEC_PROPID;
  3182. aps[1].propid = 0x7ffffffd; // stream is expected
  3183. PROPVARIANT apv[2];
  3184. Check(S_FALSE, pPropSet->ReadMultiple(1, aps, apv));
  3185. Check(S_OK, pPropSet->ReadMultiple(2, aps, apv)); // opens the stream
  3186. Check(TRUE, apv[0].vt == VT_EMPTY);
  3187. Check(TRUE, apv[1].vt == VT_STREAM);
  3188. Check(TRUE, apv[1].pStream != NULL);
  3189. WCHAR wcsBillMo[7];
  3190. Check(S_OK, apv[1].pStream->Read(wcsBillMo, 14, NULL));
  3191. Check(TRUE, wcscmp(L"billmo", wcsBillMo) == 0);
  3192. Check( 0, RELEASE_INTERFACE(apv[1].pStream) );
  3193. Check( 0, RELEASE_INTERFACE(pPropSet) );
  3194. RELEASE_INTERFACE(pPropSetStg);
  3195. }
  3196. }
  3197. //
  3198. // test that the buffer is correctly reverted
  3199. //
  3200. void
  3201. test_IPropertySetStorage_TransactedMode2(IStorage *pStorage)
  3202. {
  3203. if( g_Restrictions & (RESTRICT_DIRECT_ONLY | RESTRICT_SIMPLE_ONLY )) return;
  3204. Status( "Transacted Mode 2\n" );
  3205. //
  3206. // write and commit a property A
  3207. // write and revert a property B
  3208. // write and commit a property C
  3209. // check that property B does not exist
  3210. FMTID fmtid;
  3211. PROPSPEC ps;
  3212. PROPVARIANT pv;
  3213. IPropertyStorage *pPropStg;
  3214. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3215. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3216. UuidCreate(&fmtid);
  3217. // We'll run this test twice, once with a Create and the other
  3218. // with an Open (this way, we test both of the CPropertyStorage
  3219. // constructors).
  3220. for( int i = 0; i < 2; i++ )
  3221. {
  3222. if( i == 0 )
  3223. {
  3224. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_NONSIMPLE,
  3225. STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  3226. }
  3227. else
  3228. {
  3229. Check(S_OK, pPropSetStg->Open(fmtid,
  3230. STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  3231. }
  3232. ps.ulKind = PRSPEC_PROPID;
  3233. ps.propid = 6;
  3234. pv.vt = VT_I4;
  3235. pv.lVal = 1;
  3236. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 0x2000));
  3237. Check(S_OK, pPropStg->Commit(STGC_DEFAULT));
  3238. ps.propid = 7;
  3239. pv.lVal = 2;
  3240. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 0x2000));
  3241. Check(S_OK, pPropStg->Revert());
  3242. ps.propid = 8;
  3243. pv.lVal = 3;
  3244. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 0x2000));
  3245. Check(S_OK, pPropStg->Commit(STGC_DEFAULT));
  3246. ps.propid = 6;
  3247. Check(S_OK, pPropStg->ReadMultiple(1, &ps, &pv));
  3248. Check(TRUE, pv.lVal == 1);
  3249. Check(TRUE, pv.vt == VT_I4);
  3250. ps.propid = 7;
  3251. Check(S_FALSE, pPropStg->ReadMultiple(1, &ps, &pv));
  3252. ps.propid = 8;
  3253. Check(S_OK, pPropStg->ReadMultiple(1, &ps, &pv));
  3254. Check(TRUE, pv.lVal == 3);
  3255. Check(TRUE, pv.vt == VT_I4);
  3256. RELEASE_INTERFACE(pPropStg);
  3257. } // for( int i = 0; i < 2; i++ )
  3258. RELEASE_INTERFACE(pPropSetStg);
  3259. }
  3260. void
  3261. test_IPropertySetStorage_SubPropertySet(IStorage *pStorage)
  3262. {
  3263. FMTID fmtid;
  3264. PROPSPEC ps;
  3265. PROPVARIANT pv;
  3266. IPropertyStorage *pPropStg;
  3267. IPropertySetStorage *pSubSetStg;
  3268. IPropertyStorage *pPropStg2;
  3269. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  3270. Status( "Sub Property Set\n" );
  3271. for (int i=0; i<2; i++)
  3272. {
  3273. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3274. ULONG cStorageRefs = GetRefCount( pStorage );
  3275. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3276. UuidCreate(&fmtid);
  3277. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_NONSIMPLE,
  3278. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  3279. ps.ulKind = PRSPEC_PROPID;
  3280. ps.propid = 6;
  3281. pv.vt = VT_STORAGE;
  3282. pv.pStorage = NULL;
  3283. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 0x2000));
  3284. Check(S_OK, pPropStg->ReadMultiple(1, &ps, &pv));
  3285. Check(S_OK, StgToPropSetStg( pv.pStorage, &pSubSetStg ));
  3286. Check(S_OK, pSubSetStg->Create(fmtid, NULL, i==0 ? PROPSETFLAG_NONSIMPLE : PROPSETFLAG_DEFAULT,
  3287. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg2));
  3288. IStorage *pstgTmp = pv.pStorage;
  3289. pv.pStorage = NULL;
  3290. if (i==1)
  3291. {
  3292. pv.vt = VT_I4;
  3293. }
  3294. Check(S_OK, pPropStg2->WriteMultiple(1, &ps, &pv, 0x2000));
  3295. pPropStg->Release();
  3296. pstgTmp->Release();
  3297. pSubSetStg->Release();
  3298. pPropStg2->Release();
  3299. RELEASE_INTERFACE(pPropSetStg);
  3300. Check( cStorageRefs, GetRefCount(pStorage) );
  3301. }
  3302. }
  3303. /*
  3304. The following sequence of operations:
  3305. - open transacted docfile
  3306. - open property set inside docfile
  3307. - write properties
  3308. - commit docfile
  3309. - release property set
  3310. results in a STG_E_REVERTED error being detected
  3311. */
  3312. void
  3313. test_IPropertySetStorage_CommitAtRoot(IStorage *pStorage)
  3314. {
  3315. if( g_Restrictions & RESTRICT_DIRECT_ONLY ) return;
  3316. Status( "Commit at root\n" );
  3317. for (int i=0; i<6; i++)
  3318. {
  3319. FMTID fmtid;
  3320. IStorage *pstgT = NULL;
  3321. Check(S_OK, g_pfnStgCreateStorageEx(NULL,
  3322. STGM_CREATE | STGM_DELETEONRELEASE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  3323. STGFMT_STORAGE,
  3324. 0, NULL, NULL,
  3325. IID_IStorage,
  3326. reinterpret_cast<void**>(&pstgT) ));
  3327. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3328. Check( S_OK, StgToPropSetStg( pstgT, &pPropSetStg ));
  3329. UuidCreate(&fmtid);
  3330. IPropertyStorage *pPropStg = NULL;
  3331. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_DEFAULT,
  3332. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  3333. PROPSPEC propspec;
  3334. propspec.ulKind = PRSPEC_PROPID;
  3335. propspec.propid = 1000;
  3336. PROPVARIANT propvar;
  3337. propvar.vt = VT_I4;
  3338. propvar.lVal = 12345;
  3339. Check(S_OK, pPropStg->WriteMultiple(1, &propspec, &propvar, 2)); // force dirty
  3340. switch (i)
  3341. {
  3342. case 0:
  3343. Check(S_OK, pstgT->Commit(STGC_DEFAULT));
  3344. pstgT->Release();
  3345. pPropStg->Release();
  3346. break;
  3347. case 1:
  3348. Check(S_OK, pstgT->Commit(STGC_DEFAULT));
  3349. pPropStg->Release();
  3350. pstgT->Release();
  3351. break;
  3352. case 2:
  3353. pstgT->Release();
  3354. pPropStg->Release();
  3355. break;
  3356. case 3:
  3357. pPropStg->Commit(STGC_DEFAULT);
  3358. pPropStg->Release();
  3359. pstgT->Release();
  3360. break;
  3361. case 4:
  3362. pPropStg->Commit(STGC_DEFAULT);
  3363. pstgT->Release();
  3364. pPropStg->Release();
  3365. break;
  3366. case 5:
  3367. pPropStg->Release();
  3368. pstgT->Release();
  3369. break;
  3370. }
  3371. Check( 0, RELEASE_INTERFACE(pstgT) );
  3372. }
  3373. }
  3374. void
  3375. test_IPropertySetStorage(IStorage *pStorage)
  3376. {
  3377. // Check ref counting through different interfaces on object
  3378. test_IPropertySetStorage_IUnknown(pStorage);
  3379. test_IPropertySetStorage_CreateOpenDelete(pStorage);
  3380. test_IPropertySetStorage_SummaryInformation(pStorage);
  3381. test_IPropertySetStorage_FailIfThere(pStorage);
  3382. test_IPropertySetStorage_TransactedMode(pStorage);
  3383. test_IPropertySetStorage_TransactedMode2(pStorage);
  3384. test_IPropertySetStorage_SubPropertySet(pStorage);
  3385. test_IPropertySetStorage_CommitAtRoot(pStorage);
  3386. }
  3387. // IEnumSTATPROPSETSTG
  3388. //
  3389. // Check enumeration of property sets
  3390. //
  3391. // Check refcounting and IUnknown
  3392. //
  3393. // Create some property sets, predefined and not, simple and not, one through IStorage
  3394. // Enumerate them and check
  3395. // (check fmtid, grfFlags)
  3396. // (check when asking for more than there is: S_FALSE, S_OK)
  3397. // Delete one
  3398. // Reset the enumerator
  3399. // Enumerate them and check
  3400. // Delete one
  3401. //
  3402. // Reset the enumeratorA
  3403. // Read one from enumeratorA
  3404. // Clone enumerator -> enumeratorB
  3405. // Loop comparing rest of enumerator contents
  3406. //
  3407. // Reset the enumerator
  3408. // Skip all
  3409. // Check none left
  3410. //
  3411. // Reset the enumerator
  3412. // Skip all but one
  3413. // Check one left
  3414. //
  3415. void test_IEnumSTATPROPSETSTG(IStorage *pStorage)
  3416. {
  3417. Status( "IEnumSTATPROPSETSTG\n" );
  3418. FMTID afmtid[8];
  3419. CLSID aclsid[8];
  3420. IPropertyStorage *pPropSet;
  3421. memset( afmtid, 0, sizeof(afmtid) );
  3422. memset( aclsid, 0, sizeof(aclsid) );
  3423. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3424. FILETIME ftStart;
  3425. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3426. CoFileTimeNow(&ftStart);
  3427. IEnumSTATPROPSETSTG *penum, *penum2;
  3428. STATPROPSETSTG StatBuffer[6];
  3429. Check(S_OK, pPropSetStg->Enum(&penum));
  3430. while( S_OK == penum->Next( 1, &StatBuffer[0], NULL ))
  3431. pPropSetStg->Delete( StatBuffer[0].fmtid );
  3432. RELEASE_INTERFACE( penum );
  3433. Check(S_OK, pPropSetStg->Enum(&penum));
  3434. Check( S_FALSE, penum->Next( 1, &StatBuffer[0], NULL ));
  3435. RELEASE_INTERFACE( penum );
  3436. for (int i=0; i<5; i++)
  3437. {
  3438. ULONG cFetched;
  3439. if (i & 4)
  3440. afmtid[i] = FMTID_SummaryInformation;
  3441. else
  3442. UuidCreate(&afmtid[i]);
  3443. UuidCreate(&aclsid[i]);
  3444. Check(S_OK, pPropSetStg->Create(
  3445. afmtid[i],
  3446. aclsid+i,
  3447. ( (i & 1) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0)
  3448. |
  3449. ( (i & 2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : 0),
  3450. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  3451. &pPropSet));
  3452. pPropSet->Release();
  3453. Check(S_OK, pPropSetStg->Enum(&penum));
  3454. Check( S_FALSE, penum->Next( i+2, &StatBuffer[0], &cFetched ));
  3455. Check( S_OK, penum->Reset() );
  3456. Check( S_OK, penum->Next( i+1, &StatBuffer[0], &cFetched ));
  3457. RELEASE_INTERFACE( penum );
  3458. }
  3459. ULONG celt;
  3460. Check(S_OK, pPropSetStg->Enum(&penum));
  3461. IUnknown *punk, *punk2;
  3462. IEnumSTATPROPSETSTG *penum3;
  3463. Check(S_OK, penum->QueryInterface(IID_IUnknown, (void**)&punk));
  3464. Check(S_OK, punk->QueryInterface(IID_IEnumSTATPROPSETSTG, (void**)&penum3));
  3465. Check(S_OK, penum->QueryInterface(IID_IEnumSTATPROPSETSTG, (void**)&punk2));
  3466. Check(TRUE, punk == punk2);
  3467. punk->Release();
  3468. penum3->Release();
  3469. punk2->Release();
  3470. // test S_FALSE
  3471. Check(S_FALSE, penum->Next(6, StatBuffer, &celt));
  3472. Check(TRUE, celt == 5);
  3473. penum->Reset();
  3474. // test reading half out, then cloning, then comparing
  3475. // rest of enumeration with other clone.
  3476. Check(S_OK, penum->Next(3, StatBuffer, &celt));
  3477. Check(TRUE, celt == 3);
  3478. celt = 0;
  3479. Check(S_OK, penum->Clone(&penum2));
  3480. Check(S_OK, penum->Next(2, StatBuffer, &celt));
  3481. Check(TRUE, celt == 2);
  3482. // check the clone
  3483. for (int c=0; c<2; c++)
  3484. {
  3485. STATPROPSETSTG CloneStat;
  3486. Check(S_OK, penum2->Next(1, &CloneStat, NULL));
  3487. Check(TRUE, 0 == memcmp(&CloneStat, StatBuffer+c, sizeof(CloneStat)));
  3488. Check(TRUE, CloneStat.dwOSVersion == PROPSETHDR_OSVERSION_UNKNOWN);
  3489. }
  3490. // check both empty
  3491. celt = 0;
  3492. Check(S_FALSE, penum->Next(1, StatBuffer, &celt));
  3493. Check(TRUE, celt == 0);
  3494. Check(S_FALSE, penum2->Next(1, StatBuffer, &celt));
  3495. Check(TRUE, celt == 0);
  3496. penum->Reset();
  3497. //
  3498. // loop deleting one propset at a time
  3499. // enumerate the propsets checking that correct ones appear.
  3500. //
  3501. for (ULONG d = 0; d<5; d++)
  3502. {
  3503. // d is for delete
  3504. BOOL afFound[5];
  3505. Check(S_FALSE, penum->Next(5+1-d, StatBuffer, &celt));
  3506. Check(TRUE, celt == 5-d );
  3507. penum->Reset();
  3508. memset(afFound, 0, sizeof(afFound));
  3509. for (ULONG iPropSet=0; iPropSet<5; iPropSet++)
  3510. {
  3511. for (ULONG iSearch=0; iSearch<5-d; iSearch++)
  3512. {
  3513. if (0 == memcmp(&StatBuffer[iSearch].fmtid, &afmtid[iPropSet], sizeof(StatBuffer[0].fmtid)))
  3514. {
  3515. Check(FALSE, afFound[iPropSet]);
  3516. afFound[iPropSet] = TRUE;
  3517. break;
  3518. }
  3519. }
  3520. if (iPropSet < d)
  3521. Check(FALSE, afFound[iPropSet]);
  3522. if (iSearch == 5-d)
  3523. {
  3524. Check(TRUE, iPropSet < d);
  3525. continue;
  3526. }
  3527. Check(TRUE, ( (StatBuffer[iSearch].grfFlags & PROPSETFLAG_NONSIMPLE) ? 1u : 0u )
  3528. ==
  3529. ( (!(g_Restrictions & RESTRICT_SIMPLE_ONLY) && (iPropSet & 1)) ? 1u : 0u)
  3530. );
  3531. Check(TRUE, (StatBuffer[iSearch].grfFlags & PROPSETFLAG_ANSI) == 0);
  3532. // We should have a clsid if this is a non-simple property set and we're not disallowing
  3533. // hierarchical storages (i.e. it's not NTFS).
  3534. if( (PROPSETFLAG_NONSIMPLE & StatBuffer[iSearch].grfFlags) && !(RESTRICT_NON_HIERARCHICAL & g_Restrictions) )
  3535. Check(TRUE, StatBuffer[iSearch].clsid == aclsid[iPropSet]);
  3536. else
  3537. Check(TRUE, StatBuffer[iSearch].clsid == CLSID_NULL);
  3538. CheckTime(ftStart, StatBuffer[iSearch].mtime);
  3539. CheckTime(ftStart, StatBuffer[iSearch].atime);
  3540. CheckTime(ftStart, StatBuffer[iSearch].ctime);
  3541. }
  3542. Check(S_OK, pPropSetStg->Delete(afmtid[d]));
  3543. penum->Release();
  3544. Check(S_OK, pPropSetStg->Enum(&penum));
  3545. // Check(S_OK, penum->Reset());
  3546. }
  3547. penum->Release();
  3548. penum2->Release();
  3549. pPropSetStg->Release();
  3550. }
  3551. // Creation tests
  3552. //
  3553. // Access flags/Valid parameters/Permissions
  3554. // Check readonly cannot be written -
  3555. // WriteProperties, WritePropertyNames
  3556. void
  3557. test_IPropertyStorage_Access(IStorage *pStorage)
  3558. {
  3559. Status( "IPropertyStorage creation (access) tests\n" );
  3560. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3561. FMTID fmtid;
  3562. ULONG cStorageRefs = GetRefCount(pStorage);
  3563. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3564. UuidCreate(&fmtid);
  3565. // check by name
  3566. IPropertyStorage *pPropStg;
  3567. Check(S_OK, pPropSetStg->Create(fmtid, NULL, 0,
  3568. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  3569. // QueryInterface tests
  3570. // QI to IPropertyStorage
  3571. // QI to IUnknown on IPropertyStorage
  3572. // QI back to IPropertyStorage from IUnknown
  3573. //
  3574. // Release all.
  3575. IPropertyStorage *pPropStg2,*pPropStg3;
  3576. IUnknown *punk;
  3577. Check(S_OK, pPropStg->QueryInterface(IID_IPropertyStorage,
  3578. (void**)&pPropStg2));
  3579. Check(S_OK, pPropStg->QueryInterface(IID_IUnknown,
  3580. (void**)&punk));
  3581. Check(S_OK, punk->QueryInterface(IID_IPropertyStorage,
  3582. (void**)&pPropStg3));
  3583. pPropStg3->Release();
  3584. pPropStg2->Release();
  3585. punk->Release();
  3586. PROPSPEC ps;
  3587. ps.ulKind = PRSPEC_LPWSTR;
  3588. ps.lpwstr = OLESTR("testprop");
  3589. PROPVARIANT pv;
  3590. pv.vt = VT_LPSTR;
  3591. pv.pszVal = (LPSTR) "testval";
  3592. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 2));
  3593. pPropStg->Release();
  3594. Check(S_OK, pPropSetStg->Open(fmtid, STGM_SHARE_EXCLUSIVE | STGM_READ, &pPropStg));
  3595. Check(STG_E_ACCESSDENIED, pPropStg->WriteMultiple(1, &ps, &pv, 2));
  3596. Check(STG_E_ACCESSDENIED, pPropStg->DeleteMultiple(1, &ps));
  3597. PROPID propid=3;
  3598. Check(STG_E_ACCESSDENIED, pPropStg->WritePropertyNames(1, &propid, (LPOLESTR*) &pv.pszVal));
  3599. Check(STG_E_ACCESSDENIED, pPropStg->DeletePropertyNames(1, &propid));
  3600. FILETIME ft;
  3601. Check(STG_E_ACCESSDENIED, pPropStg->SetTimes(&ft, &ft, &ft));
  3602. CLSID clsid;
  3603. Check(STG_E_ACCESSDENIED, pPropStg->SetClass(clsid));
  3604. RELEASE_INTERFACE(pPropStg);
  3605. RELEASE_INTERFACE(pPropSetStg);
  3606. }
  3607. // Creation tests
  3608. // Check VT_STREAM etc not usable with simple.
  3609. //
  3610. void
  3611. test_IPropertyStorage_Create(IStorage *pStorage)
  3612. {
  3613. Status( "IPropertyStorage creation (simple/non-simple) tests\n" );
  3614. IPropertySetStorage *pPropSetStg = NULL;
  3615. FMTID fmtid;
  3616. ULONG cStorageRefs = GetRefCount( pStorage );
  3617. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3618. UuidCreate(&fmtid);
  3619. // check by name
  3620. IPropertyStorage *pPropStg;
  3621. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_DEFAULT,
  3622. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3623. &pPropStg));
  3624. PROPSPEC ps;
  3625. ps.ulKind = PRSPEC_PROPID;
  3626. ps.propid = 2;
  3627. PROPVARIANT pv;
  3628. pv.vt = VT_STREAM;
  3629. pv.pStream = NULL;
  3630. Check(STG_E_PROPSETMISMATCHED, pPropStg->WriteMultiple(1, &ps, &pv, 2000));
  3631. pPropStg->Release();
  3632. Check( cStorageRefs, RELEASE_INTERFACE(pStorage) );
  3633. }
  3634. //
  3635. //
  3636. // Stat (Create four combinations)
  3637. // Check non-simple/simple flag
  3638. // Check ansi/wide fflag
  3639. // Also test clsid on propset
  3640. void test_IPropertyStorage_Stat(IStorage *pStorage)
  3641. {
  3642. Status( "IPropertyStorage::Stat\n" );
  3643. DWORD dwOSVersion = 0;
  3644. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3645. FMTID fmtid;
  3646. UuidCreate(&fmtid);
  3647. IPropertyStorage *pPropSet;
  3648. STATPROPSETSTG StatPropSetStg;
  3649. ULONG cStorageRefs = GetRefCount( pStorage );
  3650. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3651. // Calculate the OS Version
  3652. #ifdef _MAC
  3653. {
  3654. // Get the Mac System Version (e.g., 7.53).
  3655. OSErr oserr;
  3656. SysEnvRec theWorld;
  3657. oserr = SysEnvirons( curSysEnvVers, &theWorld );
  3658. Check( TRUE, noErr == oserr );
  3659. dwOSVersion = MAKEPSVER( OSKIND_MACINTOSH,
  3660. HIBYTE(theWorld.systemVersion),
  3661. LOBYTE(theWorld.systemVersion) );
  3662. }
  3663. #else
  3664. dwOSVersion = MAKELONG( LOWORD(GetVersion()), OSKIND_WIN32 );
  3665. #endif
  3666. for (ULONG i=0; i<4; i++)
  3667. {
  3668. FILETIME ftStart;
  3669. CoFileTimeNow(&ftStart);
  3670. memset(&StatPropSetStg, 0, sizeof(StatPropSetStg));
  3671. CLSID clsid;
  3672. UuidCreate(&clsid);
  3673. Check(S_OK, pPropSetStg->Create(fmtid, &clsid,
  3674. ((i & 1) && 0 == (g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0)
  3675. |
  3676. ((i & 2) && 0 == (g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : 0),
  3677. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3678. &pPropSet));
  3679. CheckStat(pPropSet, fmtid,
  3680. clsid,
  3681. (
  3682. ((i & 1) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0)
  3683. |
  3684. ((i & 2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : 0)
  3685. ),
  3686. ftStart, dwOSVersion );
  3687. pPropSet->Release();
  3688. Check(S_OK, pPropSetStg->Open(fmtid,
  3689. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3690. &pPropSet));
  3691. CheckStat(pPropSet, fmtid, clsid,
  3692. ((i & 1) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0) |
  3693. ((i & 2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY)? PROPSETFLAG_ANSI : 0), ftStart, dwOSVersion );
  3694. UuidCreate(&clsid);
  3695. Check(S_OK, pPropSet->SetClass(clsid));
  3696. pPropSet->Release();
  3697. Check(S_OK, pPropSetStg->Open(fmtid,
  3698. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3699. &pPropSet));
  3700. CheckStat(pPropSet, fmtid, clsid,
  3701. ((i & 1) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0)
  3702. |
  3703. ((i & 2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : 0), ftStart, dwOSVersion );
  3704. pPropSet->Release();
  3705. }
  3706. RELEASE_INTERFACE(pPropSetStg);
  3707. }
  3708. // ReadMultiple
  3709. // Check none found S_FALSE
  3710. //
  3711. // Success case non-simple readmultiple
  3712. // Create a non-simple property set
  3713. // Create two sub non-simples
  3714. // Close all
  3715. // Open the non-simple
  3716. // Query for the two sub-nonsimples
  3717. // Try writing to them
  3718. // Close all
  3719. // Open the non-simple
  3720. // Query for the two sub-nonsimples
  3721. // Check read back
  3722. // Close all
  3723. void
  3724. test_IPropertyStorage_ReadMultiple_Normal(IStorage *pStorage)
  3725. {
  3726. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  3727. Status( "IPropertyStorage::ReadMultiple (normal)\n" );
  3728. IPropertySetStorage *pPropSetStg = NULL;
  3729. FMTID fmtid;
  3730. UuidCreate(&fmtid);
  3731. IPropertyStorage *pPropSet;
  3732. ULONG cStorageRefs = GetRefCount( pStorage );
  3733. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3734. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  3735. PROPSETFLAG_NONSIMPLE,
  3736. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3737. &pPropSet));
  3738. // none found
  3739. PROPSPEC ps[2];
  3740. ps[0].ulKind = PRSPEC_LPWSTR;
  3741. ps[0].lpwstr = L"testname";
  3742. ps[1].ulKind = PRSPEC_PROPID;
  3743. ps[1].propid = 1000;
  3744. PROPVARIANT pv[2];
  3745. PROPVARIANT pvSave[2];
  3746. PROPVARIANT pvExtra[2];
  3747. Check(S_FALSE, pPropSet->ReadMultiple(2, ps, pv));
  3748. PropVariantInit( &pv[0] );
  3749. pv[0].vt = VT_STREAM;
  3750. pv[0].pStream = NULL;
  3751. PropVariantInit( &pv[1] );
  3752. pv[1].vt = VT_STORAGE;
  3753. pv[1].pStorage = NULL;
  3754. memcpy(pvSave, pv, sizeof(pvSave));
  3755. memcpy(pvExtra, pv, sizeof(pvExtra));
  3756. // write the two sub non-simples
  3757. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 1000));
  3758. // re-open them
  3759. Check(S_OK, pPropSet->ReadMultiple(2, ps, pv));
  3760. Check(TRUE, pv[0].pStream != NULL);
  3761. Check(TRUE, pv[1].pStorage != NULL);
  3762. // check status of write when already open
  3763. Check(S_OK, pPropSet->WriteMultiple(2, ps, pvSave, 1000));
  3764. Check(STG_E_REVERTED, pv[0].pStream->Commit(0));
  3765. Check(STG_E_REVERTED, pv[1].pStorage->Commit(0));
  3766. Check(S_OK, pPropSet->ReadMultiple(2, ps, pvExtra));
  3767. Check(TRUE, pvExtra[0].pStream != NULL);
  3768. Check(TRUE, pvExtra[1].pStorage != NULL);
  3769. Check(S_OK, pvExtra[0].pStream->Commit(0));
  3770. Check(S_OK, pvExtra[1].pStorage->Commit(0));
  3771. pvExtra[0].pStream->Release();
  3772. pvExtra[1].pStorage->Release();
  3773. pv[0].pStream->Release();
  3774. pv[1].pStorage->Release();
  3775. Check(S_OK, pPropSet->ReadMultiple(2, ps, pv));
  3776. Check(TRUE, pv[0].pStream != NULL);
  3777. Check(TRUE, pv[1].pStorage != NULL);
  3778. Check(S_OK, pv[0].pStream->Write("billmotest", sizeof("billmotest"), NULL));
  3779. IStream *pStm;
  3780. Check(S_OK, pv[1].pStorage->CreateStream(OLESTR("teststream"),
  3781. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  3782. 0, 0, &pStm));
  3783. pStm->Release();
  3784. pv[0].pStream->Release();
  3785. pv[1].pStorage->Release();
  3786. pPropSet->Release();
  3787. // re-re-open them
  3788. Check(S_OK, pPropSetStg->Open(fmtid,
  3789. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3790. &pPropSet));
  3791. Check(S_OK, pPropSet->ReadMultiple(2, ps, pv));
  3792. Check(TRUE, pv[0].pStream != NULL);
  3793. Check(TRUE, pv[0].pStorage != NULL);
  3794. // read the stream and storage and check the contents.
  3795. char szBillMo[32];
  3796. Check(S_OK, pv[0].pStream->Read(szBillMo, 11, NULL));
  3797. Check(TRUE, 0 == strcmp(szBillMo, "billmotest"));
  3798. Check(S_OK, pv[1].pStorage->OpenStream(OLESTR("teststream"), NULL,
  3799. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStm));
  3800. pStm->Release();
  3801. pv[1].pStorage->Release();
  3802. pv[0].pStream->Release();
  3803. pPropSet->Release();
  3804. RELEASE_INTERFACE(pPropSetStg);
  3805. }
  3806. //
  3807. // CleanupOpenedObjects for ReadMultiple (two iterations one for "VT_STORAGE then VT_STREAM", one for
  3808. // "VT_STREAM then VT_STORAGE")
  3809. // Create property set
  3810. // Create a "VT_STREAM then VT_STORAGE"
  3811. // Open the second one exclusive
  3812. // Formulate a query so that both are read - > will fail but ...
  3813. // Check that the first one is still openable
  3814. //
  3815. void
  3816. test_IPropertyStorage_ReadMultiple_Cleanup(IStorage *pStorage)
  3817. {
  3818. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  3819. Status( "IPropertyStorage::ReadMultiple (cleanup)\n" );
  3820. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  3821. FMTID fmtid;
  3822. ULONG cStorageRefs = GetRefCount( pStorage );
  3823. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3824. UuidCreate(&fmtid);
  3825. for (LONG i=0;i<2;i++)
  3826. {
  3827. IPropertyStorage * pPropSet;
  3828. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  3829. PROPSETFLAG_NONSIMPLE,
  3830. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3831. &pPropSet));
  3832. // none found
  3833. PROPSPEC ps[2];
  3834. ps[0].ulKind = PRSPEC_PROPID;
  3835. ps[0].propid = 1000;
  3836. ps[1].ulKind = PRSPEC_PROPID;
  3837. ps[1].propid = 2000;
  3838. PROPVARIANT pv[2];
  3839. pv[0].vt = (i == 0) ? VT_STREAM : VT_STORAGE;
  3840. pv[0].pStream = NULL;
  3841. pv[1].vt = (i == 1) ? VT_STORAGE : VT_STREAM;
  3842. pv[1].pStorage = NULL;
  3843. // write the two sub non-simples
  3844. // OFS gives driver internal error when overwriting a stream with a storage.
  3845. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 1000));
  3846. // open both
  3847. Check(S_OK, pPropSet->ReadMultiple(2, ps, pv)); // **
  3848. // close the first ONLY and reopen both
  3849. PROPVARIANT pv2[2];
  3850. if (i==0)
  3851. pv[0].pStream->Release();
  3852. else
  3853. pv[0].pStorage->Release();
  3854. // reading both should fail because second is still open
  3855. Check(STG_E_ACCESSDENIED, pPropSet->ReadMultiple(2, ps, pv2));
  3856. // failure should not prevent this from succeeding
  3857. Check(S_OK, pPropSet->ReadMultiple(1, ps, pv2)); // ***
  3858. // cleanup from ** and ***
  3859. if (i==0)
  3860. {
  3861. pv2[0].pStream->Release(); // ***
  3862. pv[1].pStorage->Release(); // **
  3863. }
  3864. else
  3865. {
  3866. pv2[0].pStorage->Release(); // ***
  3867. pv[1].pStream->Release(); // **
  3868. }
  3869. pPropSet->Release();
  3870. }
  3871. RELEASE_INTERFACE(pPropSetStg);
  3872. }
  3873. // Reading an inconsistent non-simple
  3874. // Create a non-simple
  3875. // Create a sub-stream/storage
  3876. // Close all
  3877. // Delete the actual stream
  3878. // Read the indirect property -> should not exist.
  3879. //
  3880. void
  3881. test_IPropertyStorage_ReadMultiple_Inconsistent(IStorage *pStorage)
  3882. {
  3883. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  3884. if( PROPIMP_NTFS == g_enumImplementation ) return;
  3885. Status( "IPropertyStorage::ReadMultiple (inconsistent test)\n" );
  3886. IPropertySetStorage *pPropSetStg = NULL;
  3887. FMTID fmtid;
  3888. ULONG cStorageRefs = GetRefCount( pStorage );
  3889. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3890. UuidCreate(&fmtid);
  3891. IPropertyStorage * pPropSet;
  3892. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  3893. PROPSETFLAG_NONSIMPLE,
  3894. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3895. &pPropSet));
  3896. // none found
  3897. PROPSPEC ps[3];
  3898. ps[0].ulKind = PRSPEC_PROPID;
  3899. ps[0].propid = 1000;
  3900. ps[1].ulKind = PRSPEC_PROPID;
  3901. ps[1].propid = 2000;
  3902. ps[2].ulKind = PRSPEC_PROPID;
  3903. ps[2].propid = 3000;
  3904. PROPVARIANT pv[3];
  3905. pv[0].vt = VT_STREAM;
  3906. pv[0].pStream = NULL;
  3907. pv[1].vt = VT_STORAGE;
  3908. pv[1].pStorage = NULL;
  3909. pv[2].vt = VT_UI4;
  3910. pv[2].ulVal = 12345678;
  3911. // write the two sub non-simples
  3912. Check(S_OK, pPropSet->WriteMultiple(3, ps, pv, 1000));
  3913. pPropSet->Release();
  3914. Check(S_OK, pStorage->Commit(STGC_DEFAULT));
  3915. // delete the propsets
  3916. OLECHAR ocsPropsetName[48];
  3917. // get name of the propset storage
  3918. RtlGuidToPropertySetName(&fmtid, ocsPropsetName);
  3919. // open it
  3920. CTempStorage pStgPropSet(coOpen, pStorage, ocsPropsetName);
  3921. // enumerate the non-simple properties.
  3922. IEnumSTATSTG *penum;
  3923. STATSTG stat[4];
  3924. ULONG celt;
  3925. Check(S_OK, pStgPropSet->EnumElements(0, NULL, 0, &penum));
  3926. Check(S_OK, penum->Next(3, stat, &celt));
  3927. penum->Release();
  3928. for (ULONG i=0;i<celt;i++)
  3929. {
  3930. if (ocscmp(OLESTR("CONTENTS"), stat[i].pwcsName) != 0)
  3931. pStgPropSet->DestroyElement(stat[i].pwcsName);
  3932. delete [] stat[i].pwcsName;
  3933. }
  3934. pStgPropSet.Release();
  3935. Check(S_OK, pPropSetStg->Open(fmtid,
  3936. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3937. &pPropSet));
  3938. Check(S_OK, pPropSet->ReadMultiple(3, ps, pv));
  3939. Check(TRUE, pv[0].vt == VT_EMPTY);
  3940. Check(TRUE, pv[1].vt == VT_EMPTY);
  3941. Check(TRUE, pv[2].vt == VT_UI4);
  3942. Check(TRUE, pv[2].ulVal == 12345678);
  3943. pPropSet->Release();
  3944. RELEASE_INTERFACE(pPropSetStg);
  3945. }
  3946. void
  3947. test_IPropertyStorage_ReadMultiple(IStorage *pStorage)
  3948. {
  3949. test_IPropertyStorage_ReadMultiple_Normal(pStorage);
  3950. test_IPropertyStorage_ReadMultiple_Cleanup(pStorage);
  3951. test_IPropertyStorage_ReadMultiple_Inconsistent(pStorage);
  3952. }
  3953. // Overwrite a non-simple property with a simple in a simple propset
  3954. void
  3955. test_IPropertyStorage_WriteMultiple_Overwrite1(IStorage *pStgBase)
  3956. {
  3957. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  3958. if( PROPIMP_NTFS == g_enumImplementation ) return;
  3959. Status( "IPropertyStorage::WriteMultiple (overwrite 1)\n" );
  3960. CTempStorage pStgSimple(coCreate, pStgBase, OLESTR("ov1_simp"));
  3961. CTempStorage pStorage(coCreate, pStgBase, OLESTR("ov1_stg"));
  3962. IPropertySetStorage *pPropSetStg = NULL;
  3963. IPropertySetStorage *pPropSetSimpleStg = NULL;
  3964. FMTID fmtid, fmtidSimple;
  3965. UuidCreate(&fmtid);
  3966. UuidCreate(&fmtidSimple);
  3967. ULONG cStorageRefs = GetRefCount( pStorage );
  3968. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  3969. Check( S_OK, StgToPropSetStg( pStgSimple, &pPropSetSimpleStg ));
  3970. // create a simple set with a non-simple child by copying the contents
  3971. // stream a non-simple to a property set stream (simple)
  3972. // create a nonsimple propset (will contain the contents stream)
  3973. IPropertyStorage * pPropSet;
  3974. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  3975. PROPSETFLAG_NONSIMPLE,
  3976. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  3977. &pPropSet));
  3978. // none found
  3979. PROPSPEC ps[2];
  3980. ps[0].ulKind = PRSPEC_PROPID;
  3981. ps[0].propid = 1000;
  3982. ps[1].ulKind = PRSPEC_LPWSTR;
  3983. ps[1].lpwstr = OLESTR("foobar");
  3984. PROPVARIANT pv[2];
  3985. pv[0].vt = VT_STREAM;
  3986. pv[0].pStream = NULL;
  3987. pv[1].vt = VT_UI1;
  3988. pv[1].bVal = 66;
  3989. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 100));
  3990. // invalid parameter
  3991. PROPVARIANT pvInvalid[2];
  3992. PROPSPEC psInvalid[2];
  3993. psInvalid[0].ulKind = PRSPEC_PROPID;
  3994. psInvalid[0].propid = 1000;
  3995. psInvalid[1].ulKind = PRSPEC_PROPID;
  3996. psInvalid[1].propid = 1001;
  3997. pvInvalid[0].vt = (VARTYPE)-99;
  3998. pvInvalid[1].vt = (VARTYPE)-100;
  3999. Check(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), pPropSet->WriteMultiple(1, psInvalid, pvInvalid, 100));
  4000. Check(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), pPropSet->WriteMultiple(2, psInvalid, pvInvalid, 100));
  4001. pPropSet->Release();
  4002. // create a simple propset (will be overwritten)
  4003. IPropertyStorage * pPropSetSimple;
  4004. Check(S_OK, pPropSetSimpleStg->Create(fmtidSimple, NULL,
  4005. 0,
  4006. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4007. &pPropSetSimple));
  4008. pPropSetSimple->Release();
  4009. OLECHAR ocsNonSimple[48];
  4010. OLECHAR ocsSimple[48];
  4011. // get the name of the simple propset
  4012. RtlGuidToPropertySetName(&fmtidSimple, ocsSimple);
  4013. // get the name of the non-simple propset
  4014. RtlGuidToPropertySetName(&fmtid, ocsNonSimple);
  4015. // open non-simple as a storage (will copy the simple to this)
  4016. IStorage *pstgPropSet;
  4017. Check(S_OK, pStorage->OpenStorage(ocsNonSimple, NULL,
  4018. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &pstgPropSet));
  4019. // copy the contents of the non-simple to the propset of the simple
  4020. IStream *pstmNonSimple;
  4021. Check(S_OK, pstgPropSet->OpenStream(OLESTR("CONTENTS"), NULL,
  4022. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &pstmNonSimple));
  4023. IStream *pstmSimple;
  4024. Check(S_OK, pStgSimple->OpenStream(ocsSimple,
  4025. NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pstmSimple));
  4026. ULARGE_INTEGER uli;
  4027. memset(&uli, 0xff, sizeof(uli));
  4028. Check(S_OK, pstmNonSimple->CopyTo(pstmSimple, uli, NULL, NULL));
  4029. pstmSimple->Release();
  4030. pstmNonSimple->Release();
  4031. pstgPropSet->Release();
  4032. // But now the FMTID *in* the simple property set doesn't
  4033. // match the string-ized FMTID which is the Stream's name. So,
  4034. // rename the Stream to match the property set's FMTID.
  4035. Check(S_OK, pStgSimple->RenameElement( ocsSimple, ocsNonSimple ));
  4036. // now we have a simple propset with a non-simple VT type
  4037. Check(S_OK, pPropSetSimpleStg->Open(fmtid, // Use the non-simple FMTID now
  4038. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4039. &pPropSetSimple));
  4040. Check(S_FALSE, pPropSetSimple->ReadMultiple(1, ps, pv));
  4041. Check(S_OK, pPropSetSimple->ReadMultiple(2, ps, pv));
  4042. Check(TRUE, pv[0].vt == VT_EMPTY);
  4043. Check(TRUE, pv[1].vt == VT_UI1);
  4044. Check(TRUE, pv[1].bVal == 66);
  4045. RELEASE_INTERFACE( pPropSetSimpleStg );
  4046. pPropSetSimple->Release();
  4047. RELEASE_INTERFACE(pPropSetStg);
  4048. }
  4049. // Overwrite a non-simple with a simple in a non-simple
  4050. // check that the non-simple is actually deleted
  4051. // Delete a non-simple
  4052. // check that the non-simple is actually deleted
  4053. void
  4054. test_IPropertyStorage_WriteMultiple_Overwrite2(IStorage *pStorage)
  4055. {
  4056. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  4057. if( PROPIMP_NTFS == g_enumImplementation ) return;
  4058. Status( "IPropertyStorage::WriteMultiple (overwrite 2)\n" );
  4059. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  4060. FMTID fmtid;
  4061. ULONG cStorageRefs = GetRefCount( pStorage );
  4062. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  4063. UuidCreate(&fmtid);
  4064. IPropertyStorage *pPropSet;
  4065. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_NONSIMPLE,
  4066. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropSet));
  4067. // create the non-simple
  4068. PROPSPEC ps[5];
  4069. ps[0].ulKind = PRSPEC_PROPID;
  4070. ps[0].propid = 1000;
  4071. ps[1].ulKind = PRSPEC_PROPID;
  4072. ps[1].propid = 1001;
  4073. ps[2].ulKind = PRSPEC_PROPID;
  4074. ps[2].propid = 1002;
  4075. ps[3].ulKind = PRSPEC_PROPID;
  4076. ps[3].propid = 1003;
  4077. ps[4].ulKind = PRSPEC_PROPID;
  4078. ps[4].propid = 1004;
  4079. PROPVARIANT pv[5];
  4080. pv[0].vt = VT_STORAGE;
  4081. pv[0].pStorage = NULL;
  4082. pv[1].vt = VT_STREAM;
  4083. pv[1].pStream = NULL;
  4084. pv[2].vt = VT_STORAGE;
  4085. pv[2].pStorage = NULL;
  4086. pv[3].vt = VT_STREAM;
  4087. pv[3].pStream = NULL;
  4088. pv[4].vt = VT_STREAM;
  4089. pv[4].pStream = NULL;
  4090. Check(S_OK, pPropSet->WriteMultiple(5, ps, pv, 2000));
  4091. pPropSet->Release();
  4092. // get the name of the propset
  4093. OLECHAR ocsPropsetName[48];
  4094. RtlGuidToPropertySetName(&fmtid, ocsPropsetName);
  4095. IStorage *pstgPropSet;
  4096. Check(S_OK, pStorage->OpenStorage(ocsPropsetName, NULL,
  4097. STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  4098. NULL, 0, &pstgPropSet));
  4099. // get the names of the non-simple property
  4100. IEnumSTATSTG *penum;
  4101. STATSTG statProp[6];
  4102. ULONG celt;
  4103. Check(S_OK, pstgPropSet->EnumElements(0, NULL, 0, &penum));
  4104. Check(S_OK, penum->Next(5, statProp, &celt));
  4105. Check(TRUE, celt == 5);
  4106. delete [] statProp[0].pwcsName;
  4107. delete [] statProp[1].pwcsName;
  4108. delete [] statProp[2].pwcsName;
  4109. delete [] statProp[3].pwcsName;
  4110. delete [] statProp[4].pwcsName;
  4111. penum->Release();
  4112. // reopen the property set and delete the non-simple
  4113. pstgPropSet->Release();
  4114. Check(S_OK, pPropSetStg->Open(fmtid, STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4115. &pPropSet));
  4116. pv[0].vt = VT_LPWSTR;
  4117. pv[0].pwszVal = L"Overwrite1";
  4118. pv[1].vt = VT_LPWSTR;
  4119. pv[1].pwszVal = L"Overwrite2";
  4120. pv[2].vt = VT_LPWSTR;
  4121. pv[2].pwszVal = L"Overwrite3";
  4122. pv[3].vt = VT_LPWSTR;
  4123. pv[3].pwszVal = L"Overwrite4";
  4124. pv[4].vt = VT_LPWSTR;
  4125. pv[4].pwszVal = L"Overwrite5";
  4126. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 2000));
  4127. Check(S_OK, pPropSet->DeleteMultiple(1, ps+2));
  4128. Check(S_OK, pPropSet->DeleteMultiple(2, ps+3));
  4129. pPropSet->Release();
  4130. // open the propset as storage again and check that the VT_STORAGE is gone.
  4131. Check(S_OK, pStorage->OpenStorage(ocsPropsetName, NULL,
  4132. STGM_SHARE_EXCLUSIVE|STGM_READWRITE,
  4133. NULL, 0, &pstgPropSet));
  4134. // check they were removed
  4135. STATSTG statProp2[5];
  4136. Check(S_OK, pstgPropSet->EnumElements(0, NULL, 0, &penum));
  4137. Check(S_FALSE, penum->Next(5, statProp2, &celt));
  4138. Check(TRUE, celt == 1); // contents
  4139. delete [] statProp2[0].pwcsName;
  4140. penum->Release();
  4141. pstgPropSet->Release();
  4142. RELEASE_INTERFACE(pPropSetStg);
  4143. }
  4144. // Write a VT_STORAGE over a VT_STREAM
  4145. // check for cases: when not already open, when already open(access denied)
  4146. // Write a VT_STREAM over a VT_STORAGE
  4147. // check for cases: when not already open, when already open(access denied)
  4148. void
  4149. test_IPropertyStorage_WriteMultiple_Overwrite3(IStorage *pStorage)
  4150. {
  4151. if( g_Restrictions & RESTRICT_SIMPLE_ONLY ) return;
  4152. Status( "IPropertyStorage::WriteMultiple (overwrite 3)\n" );
  4153. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  4154. FMTID fmtid;
  4155. ULONG cStorageRefs = GetRefCount( pStorage );
  4156. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  4157. UuidCreate(&fmtid);
  4158. IPropertyStorage *pPropSet;
  4159. Check(S_OK, pPropSetStg->Create(fmtid, NULL, PROPSETFLAG_NONSIMPLE,
  4160. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4161. &pPropSet));
  4162. PROPSPEC ps[2];
  4163. ps[0].ulKind = PRSPEC_LPWSTR;
  4164. ps[0].lpwstr = OLESTR("stream_storage");
  4165. ps[1].ulKind = PRSPEC_LPWSTR;
  4166. ps[1].lpwstr = OLESTR("storage_stream");
  4167. PROPVARIANT pv[2];
  4168. pv[0].vt = VT_STREAMED_OBJECT;
  4169. pv[0].pStream = NULL;
  4170. pv[1].vt = VT_STORED_OBJECT;
  4171. pv[1].pStorage = NULL;
  4172. PROPVARIANT pvSave[2];
  4173. pvSave[0] = pv[0];
  4174. pvSave[1] = pv[1];
  4175. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 1000));
  4176. // swap them around
  4177. PROPVARIANT pvTemp;
  4178. pvTemp = pv[0];
  4179. pv[0] = pv[1];
  4180. pv[1] = pvTemp;
  4181. Check(S_OK, pPropSet->WriteMultiple(2, ps, pv, 1000));
  4182. memset(pv, 0, sizeof(pv));
  4183. Check(S_OK, pPropSet->ReadMultiple(2, ps, pv));
  4184. Check(TRUE, pv[0].vt == VT_STORED_OBJECT);
  4185. Check(TRUE, pv[1].vt == VT_STREAMED_OBJECT);
  4186. Check(TRUE, pv[0].pStorage != NULL);
  4187. Check(TRUE, pv[1].pStream != NULL);
  4188. STATSTG stat; stat.type = 0;
  4189. Check(S_OK, pv[0].pStorage->Stat(&stat, STATFLAG_NONAME));
  4190. Check(TRUE, stat.type == STGTY_STORAGE);
  4191. Check(S_OK, pv[1].pStream->Stat(&stat, STATFLAG_NONAME));
  4192. Check(TRUE, stat.type == STGTY_STREAM);
  4193. STATSTG stat2; stat2.type = 0;
  4194. // swap them around again, but this time with access denied
  4195. Check(S_OK, pPropSet->WriteMultiple(2, ps, pvSave, 1000));
  4196. Check(STG_E_REVERTED, pv[0].pStorage->Stat(&stat, STATFLAG_NONAME));
  4197. pv[0].pStorage->Release();
  4198. Check(S_OK, pPropSet->WriteMultiple(2, ps, pvSave, 1000));
  4199. Check(STG_E_REVERTED, pv[1].pStream->Stat(&stat, STATFLAG_NONAME));
  4200. pv[1].pStream->Release();
  4201. pPropSet->Release();
  4202. RELEASE_INTERFACE(pPropSetStg);
  4203. }
  4204. //
  4205. // test using IStorage::Commit to commit the changes in a nested
  4206. // property set
  4207. //
  4208. void
  4209. test_IPropertyStorage_Commit(IStorage *pStorage)
  4210. {
  4211. if( g_Restrictions & ( RESTRICT_SIMPLE_ONLY | RESTRICT_DIRECT_ONLY) ) return;
  4212. Status( "IPropertyStorage::Commit\n" );
  4213. // 8 scenarios: (simple+non-simple) * (direct+transacted) * (release only + commit storage + commit propset)
  4214. for (int i=0; i<32; i++)
  4215. {
  4216. CTempStorage pDeeper(coCreate, pStorage, GetNextTest(), (i & 1) ? STGM_TRANSACTED : STGM_DIRECT);
  4217. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pDeeper);
  4218. FMTID fmtid;
  4219. ULONG cDeeperRefs = GetRefCount( pDeeper );
  4220. Check( S_OK, StgToPropSetStg( pDeeper, &pPropSetStg ));
  4221. UuidCreate(&fmtid);
  4222. IPropertyStorage *pPropSet;
  4223. Check(S_OK, pPropSetStg->Create(fmtid, NULL, (i&8) ? PROPSETFLAG_NONSIMPLE : PROPSETFLAG_DEFAULT,
  4224. STGM_SHARE_EXCLUSIVE | STGM_READWRITE | ((i&16) && (i&8) ? STGM_TRANSACTED : STGM_DIRECT),
  4225. &pPropSet));
  4226. PROPSPEC ps;
  4227. ps.ulKind = PRSPEC_PROPID;
  4228. ps.propid = 100;
  4229. PROPVARIANT pv;
  4230. pv.vt = VT_I4;
  4231. pv.lVal = 1234;
  4232. Check(S_OK, pPropSet->WriteMultiple(1, &ps, &pv, 1000));
  4233. memset(&pv, 0, sizeof(pv));
  4234. Check(S_OK, pPropSet->ReadMultiple(1, &ps, &pv));
  4235. Check(TRUE, pv.lVal == 1234);
  4236. pv.lVal = 2345; // no size changes
  4237. Check(S_OK, pPropSet->WriteMultiple(1, &ps, &pv, 1000));
  4238. if (i & 4)
  4239. Check(S_OK, pPropSet->Commit(0));
  4240. if (i & 2)
  4241. Check(S_OK, pStorage->Commit(0));
  4242. Check(0, pPropSet->Release()); // implicit commit if i&2 is false
  4243. if (S_OK == pPropSetStg->Open(fmtid, STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4244. &pPropSet))
  4245. {
  4246. memset(&pv, 0, sizeof(pv));
  4247. Check( !((i&16) && (i&8)) || (i&0x1c)==0x1c ? S_OK : S_FALSE, pPropSet->ReadMultiple(1, &ps, &pv));
  4248. if (!((i&16) && (i&8)) || (i&0x1c)==0x1c)
  4249. Check(TRUE, pv.lVal == 2345);
  4250. pPropSet->Release();
  4251. }
  4252. RELEASE_INTERFACE(pPropSetStg);
  4253. Check( cDeeperRefs, GetRefCount( pDeeper ));
  4254. }
  4255. }
  4256. void
  4257. test_IPropertyStorage_WriteMultiple(IStorage *pStorage)
  4258. {
  4259. test_IPropertyStorage_WriteMultiple_Overwrite1(pStorage);
  4260. test_IPropertyStorage_WriteMultiple_Overwrite2(pStorage);
  4261. test_IPropertyStorage_WriteMultiple_Overwrite3(pStorage);
  4262. test_IPropertyStorage_Commit(pStorage);
  4263. }
  4264. // this serves as a test for WritePropertyNames, ReadPropertyNames, DeletePropertyNames
  4265. // DeleteMultiple, PropVariantCopy, FreePropVariantArray.
  4266. void
  4267. test_IPropertyStorage_DeleteMultiple(IStorage *pStorage)
  4268. {
  4269. Status( "IPropertyStorage::DeleteMultiple\n" );
  4270. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  4271. FMTID fmtid;
  4272. ULONG cStorageRefs = GetRefCount( pStorage );
  4273. Check( S_OK, StgToPropSetStg( pStorage, &pPropSetStg ));
  4274. UuidCreate(&fmtid);
  4275. IPropertyStorage *pPropSet;
  4276. int PropId = 3;
  4277. for (int type=0; type<2; type++)
  4278. {
  4279. BOOL fSimple = ( type == 0 || (g_Restrictions & RESTRICT_SIMPLE_ONLY) );
  4280. UuidCreate(&fmtid);
  4281. Check(S_OK, pPropSetStg->Create(fmtid,
  4282. NULL,
  4283. fSimple ? PROPSETFLAG_DEFAULT : PROPSETFLAG_NONSIMPLE,
  4284. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4285. &pPropSet));
  4286. // create and delete each type.
  4287. PROPVARIANT *pVar;
  4288. for (int AtOnce=1; AtOnce <3; AtOnce++)
  4289. {
  4290. CGenProps gp;
  4291. int Actual;
  4292. while (pVar = gp.GetNext(AtOnce, &Actual, FALSE, fSimple ))
  4293. {
  4294. PROPSPEC ps[3];
  4295. PROPID rgpropid[3];
  4296. LPOLESTR rglpostrName[3];
  4297. OLECHAR aosz[3][16];
  4298. for (int s=0; s<3; s++)
  4299. {
  4300. PROPGENPROPERTYNAME( &aosz[s][0], PropId );
  4301. rgpropid[s] = PropId++;
  4302. rglpostrName[s] = &aosz[s][0];
  4303. ps[s].ulKind = PRSPEC_LPWSTR;
  4304. ps[s].lpwstr = &aosz[s][0];
  4305. }
  4306. for (int l=1; l<Actual; l++)
  4307. {
  4308. PROPVARIANT VarRead[3];
  4309. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  4310. Check(S_OK, pPropSet->WritePropertyNames(l, rgpropid, rglpostrName));
  4311. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  4312. Check(S_OK, pPropSet->WriteMultiple(l, ps, pVar, 1000));
  4313. Check(S_OK, pPropSet->ReadMultiple(l, ps, VarRead));
  4314. Check(S_OK, g_pfnFreePropVariantArray(l, VarRead));
  4315. Check(S_OK, pPropSet->DeleteMultiple(l, ps));
  4316. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  4317. Check(S_OK, g_pfnFreePropVariantArray(l, VarRead));
  4318. LPOLESTR rglpostrNameCheck[3];
  4319. Check(S_OK, pPropSet->ReadPropertyNames(l, rgpropid, rglpostrNameCheck));
  4320. for (int c=0; c<l; c++)
  4321. {
  4322. Check( 0, ocscmp(rglpostrNameCheck[c], rglpostrName[c]) );
  4323. delete [] rglpostrNameCheck[c];
  4324. }
  4325. Check(S_OK, pPropSet->DeletePropertyNames(l, rgpropid));
  4326. Check(S_FALSE, pPropSet->ReadPropertyNames(l, rgpropid, rglpostrNameCheck));
  4327. }
  4328. g_pfnFreePropVariantArray(Actual, pVar);
  4329. delete pVar;
  4330. }
  4331. }
  4332. pPropSet->Release();
  4333. }
  4334. RELEASE_INTERFACE(pPropSetStg);
  4335. }
  4336. void
  4337. test_IPropertyStorage(IStorage *pStorage)
  4338. {
  4339. test_IPropertyStorage_Access(pStorage);
  4340. test_IPropertyStorage_Create(pStorage);
  4341. test_IPropertyStorage_Stat(pStorage);
  4342. test_IPropertyStorage_ReadMultiple(pStorage);
  4343. test_IPropertyStorage_WriteMultiple(pStorage);
  4344. test_IPropertyStorage_DeleteMultiple(pStorage);
  4345. }
  4346. //
  4347. // Word6.0 summary information
  4348. // Open
  4349. // Read fields
  4350. // Stat
  4351. //
  4352. void test_Word6(IStorage *pStorage, CHAR *pszTemporaryDirectory)
  4353. {
  4354. Status( "Word 6.0 compatibility test\n" );
  4355. extern unsigned char g_achTestDoc[];
  4356. extern unsigned g_cbTestDoc;
  4357. OLECHAR oszTempFile[ MAX_PATH + 1 ];
  4358. CHAR szTempFile[ MAX_PATH + 1 ];
  4359. strcpy( szTempFile, pszTemporaryDirectory );
  4360. strcat( szTempFile, "word6.doc" );
  4361. PropTest_mbstoocs( oszTempFile, sizeof(oszTempFile), szTempFile );
  4362. PROPTEST_FILE_HANDLE hFile = PropTest_CreateFile( szTempFile );
  4363. #ifdef _MAC
  4364. Check(TRUE, (PROPTEST_FILE_HANDLE) -1 != hFile);
  4365. #else
  4366. Check(TRUE, INVALID_HANDLE_VALUE != hFile);
  4367. #endif
  4368. DWORD cbWritten;
  4369. PropTest_WriteFile(hFile, g_achTestDoc, g_cbTestDoc, &cbWritten);
  4370. Check(TRUE, cbWritten == g_cbTestDoc);
  4371. PropTest_CloseHandle(hFile);
  4372. IStorage *pStg;
  4373. Check(S_OK, g_pfnStgOpenStorageEx(oszTempFile,
  4374. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4375. STGFMT_ANY,
  4376. 0, NULL, NULL,
  4377. IID_IStorage,
  4378. reinterpret_cast<void**>(&pStg) ));
  4379. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pStg);
  4380. IPropertyStorage *pPropStg;
  4381. ULONG cStorageRefs = GetRefCount( pStg );
  4382. Check( S_OK, StgToPropSetStg( pStg, &pPropSetStg ));
  4383. Check(S_OK, pPropSetStg->Open(FMTID_SummaryInformation,
  4384. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READ,
  4385. &pPropStg));
  4386. #define WORDPROPS 18
  4387. static struct tagWordTest {
  4388. VARENUM vt;
  4389. void *pv;
  4390. } avt[WORDPROPS] = {
  4391. VT_LPSTR, "Title of the document.", // PID_TITLE
  4392. VT_LPSTR, "Subject of the document.", // PID_SUBJECT
  4393. VT_LPSTR, "Author of the document.", // PID_AUTHOR
  4394. VT_LPSTR, "Keywords of the document.", // PID_KEYWORDS
  4395. VT_LPSTR, "Comments of the document.", // PID_COMMENTS
  4396. VT_LPSTR, "Normal.dot", // PID_TEMPLATE -- Normal.dot
  4397. VT_LPSTR, "Bill Morel", // PID_LASTAUTHOR --
  4398. VT_LPSTR, "3", // PID_REVNUMBER -- '3'
  4399. VT_EMPTY, 0, // PID_EDITTIME -- 3 Minutes FILETIME
  4400. VT_EMPTY, 0, // PID_LASTPRINTED -- 04/07/95 12:04 FILETIME
  4401. VT_EMPTY, 0, // PID_CREATE_DTM
  4402. VT_EMPTY, 0, // PID_LASTSAVE_DTM
  4403. VT_I4, (void*) 1, // PID_PAGECOUNT
  4404. VT_I4, (void*) 7, // PID_WORDCOUNT
  4405. VT_I4, (void*) 65, // PID_CHARCOUNT
  4406. VT_EMPTY, 0, // PID_THUMBNAIL
  4407. VT_LPSTR, "Microsoft Word 6.0", // PID_APPNAME
  4408. VT_I4, 0 }; // PID_SECURITY
  4409. PROPSPEC propspec[WORDPROPS+2];
  4410. for (int i=2; i<WORDPROPS+2; i++)
  4411. {
  4412. propspec[i].ulKind = PRSPEC_PROPID;
  4413. propspec[i].propid = (PROPID)i;
  4414. }
  4415. PROPVARIANT propvar[WORDPROPS+2];
  4416. Check(S_OK, pPropStg->ReadMultiple(WORDPROPS, propspec+2, propvar+2));
  4417. for (i=2; i<WORDPROPS+2; i++)
  4418. {
  4419. if ( propvar[i].vt != avt[i-2].vt )
  4420. {
  4421. PRINTF( " PROPTEST: 0x%x retrieved type 0x%x, expected type 0x%x\n",
  4422. i, propvar[i].vt, avt[i-2].vt );
  4423. Check(TRUE, propvar[i].vt == avt[i-2].vt);
  4424. }
  4425. switch (propvar[i].vt)
  4426. {
  4427. case VT_LPSTR:
  4428. Check(TRUE, strcmp(propvar[i].pszVal, (char*)avt[i-2].pv)==0);
  4429. break;
  4430. case VT_I4:
  4431. Check(TRUE, (ULONG_PTR) propvar[i].lVal == (ULONG_PTR)avt[i-2].pv);
  4432. break;
  4433. }
  4434. }
  4435. g_pfnFreePropVariantArray( WORDPROPS, propvar+2 );
  4436. RELEASE_INTERFACE( pPropStg );
  4437. RELEASE_INTERFACE( pPropSetStg );
  4438. Check( 0, RELEASE_INTERFACE(pStg) );
  4439. }
  4440. void
  4441. test_IEnumSTATPROPSTG(IStorage *pstgTemp)
  4442. {
  4443. Status( "IEnumSTATPROPSTG\n" );
  4444. PROPID apropid[8];
  4445. LPOLESTR alpostrName[8];
  4446. OLECHAR aosz[8][32];
  4447. PROPID PropId=2;
  4448. PROPSPEC ps[8];
  4449. FMTID fmtid;
  4450. IPropertyStorage *pPropStg;
  4451. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pstgTemp);
  4452. ULONG cStorageRefs = GetRefCount( pstgTemp );
  4453. Check( S_OK, StgToPropSetStg( pstgTemp, &pPropSetStg ));
  4454. UuidCreate(&fmtid);
  4455. for (int setup=0; setup<8; setup++)
  4456. {
  4457. alpostrName[setup] = &aosz[setup][0];
  4458. }
  4459. CGenProps gp;
  4460. // simple/non-simple, ansi/wide, named/not named
  4461. for (int outer=0; outer<8; outer++)
  4462. {
  4463. UuidCreate(&fmtid);
  4464. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  4465. ((outer&4) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : 0)
  4466. |
  4467. ((outer&2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : 0),
  4468. STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  4469. &pPropStg));
  4470. for (int i=0; i<CPROPERTIES; i++)
  4471. {
  4472. apropid[i] = PropId++;
  4473. if (outer & 1)
  4474. {
  4475. ps[i].ulKind = PRSPEC_LPWSTR;
  4476. PROPGENPROPERTYNAME( aosz[i], apropid[i] );
  4477. ps[i].lpwstr = aosz[i];
  4478. }
  4479. else
  4480. {
  4481. ps[i].ulKind = PRSPEC_PROPID;
  4482. ps[i].propid = apropid[i];
  4483. }
  4484. }
  4485. if (outer & 1)
  4486. {
  4487. Check(S_OK, pPropStg->WritePropertyNames(CPROPERTIES, apropid, alpostrName));
  4488. }
  4489. PROPVARIANT *pVar = gp.GetNext(CPROPERTIES, NULL, TRUE, (outer&4)==0); // no non-simple
  4490. Check(TRUE, pVar != NULL);
  4491. Check(S_OK, pPropStg->WriteMultiple(CPROPERTIES, ps, pVar, 1000));
  4492. g_pfnFreePropVariantArray(CPROPERTIES, pVar);
  4493. delete pVar;
  4494. // Allocate enough STATPROPSTGs for one more than the actual properties
  4495. // in the set.
  4496. STATPROPSTG StatBuffer[CPROPERTIES+1];
  4497. ULONG celt;
  4498. IEnumSTATPROPSTG *penum, *penum2;
  4499. Check(S_OK, pPropStg->Enum(&penum));
  4500. IUnknown *punk, *punk2;
  4501. IEnumSTATPROPSTG *penum3;
  4502. Check(S_OK, penum->QueryInterface(IID_IUnknown, (void**)&punk));
  4503. Check(S_OK, punk->QueryInterface(IID_IEnumSTATPROPSTG, (void**)&penum3));
  4504. Check(S_OK, penum->QueryInterface(IID_IEnumSTATPROPSTG, (void**)&punk2));
  4505. Check(TRUE, punk == punk2);
  4506. punk->Release();
  4507. penum3->Release();
  4508. punk2->Release();
  4509. // test S_FALSE
  4510. Check(S_FALSE, penum->Next( CPROPERTIES+1, StatBuffer, &celt));
  4511. Check(TRUE, celt == CPROPERTIES);
  4512. CleanStat(celt, StatBuffer);
  4513. penum->Reset();
  4514. // test reading half out, then cloning, then comparing
  4515. // rest of enumeration with other clone.
  4516. Check(S_OK, penum->Next(CPROPERTIES/2, StatBuffer, &celt));
  4517. Check(TRUE, celt == CPROPERTIES/2);
  4518. CleanStat(celt, StatBuffer);
  4519. celt = 0;
  4520. Check(S_OK, penum->Clone(&penum2));
  4521. Check(S_OK, penum->Next(CPROPERTIES - CPROPERTIES/2, StatBuffer, &celt));
  4522. Check(TRUE, celt == CPROPERTIES - CPROPERTIES/2);
  4523. // check the clone
  4524. for (int c=0; c<CPROPERTIES - CPROPERTIES/2; c++)
  4525. {
  4526. STATPROPSTG CloneStat;
  4527. Check(S_OK, penum2->Next(1, &CloneStat, NULL));
  4528. Check(TRUE, IsEqualSTATPROPSTG(&CloneStat, StatBuffer+c));
  4529. CleanStat(1, &CloneStat);
  4530. }
  4531. CleanStat(celt, StatBuffer);
  4532. // check both empty
  4533. celt = 0;
  4534. Check(S_FALSE, penum->Next(1, StatBuffer, &celt));
  4535. Check(TRUE, celt == 0);
  4536. Check(S_FALSE, penum2->Next(1, StatBuffer, &celt));
  4537. Check(TRUE, celt == 0);
  4538. penum->Reset();
  4539. //
  4540. // loop deleting one property at a time
  4541. // enumerate the propertys checking that correct ones appear.
  4542. //
  4543. for (ULONG d = 0; d<CPROPERTIES; d++)
  4544. {
  4545. // d is for delete
  4546. BOOL afFound[CPROPERTIES];
  4547. ULONG cTotal = 0;
  4548. Check(S_OK, penum->Next(CPROPERTIES-d, StatBuffer, &celt));
  4549. Check(TRUE, celt == CPROPERTIES-d);
  4550. penum->Reset();
  4551. memset(afFound, 0, sizeof(afFound));
  4552. for (ULONG iProperty=0; iProperty<CPROPERTIES; iProperty++)
  4553. {
  4554. // Search the StatBuffer for this property.
  4555. for (ULONG iSearch=0; iSearch<CPROPERTIES-d; iSearch++)
  4556. {
  4557. // Compare this entry in the StatBuffer to the property for which we're searching.
  4558. // Use the lpstrName or propid, whichever is appropriate for this pass (indicated
  4559. // by 'outer').
  4560. if ( ( (outer & 1) == 1 && 0 == ocscmp(StatBuffer[iSearch].lpwstrName, ps[iProperty].lpwstr) )
  4561. ||
  4562. ( (outer & 1) == 0 && StatBuffer[iSearch].propid == apropid[iProperty] )
  4563. )
  4564. {
  4565. ASSERT (!afFound[iSearch]);
  4566. afFound[iSearch] = TRUE;
  4567. cTotal++;
  4568. break;
  4569. }
  4570. }
  4571. }
  4572. CleanStat(celt, StatBuffer);
  4573. Check(TRUE, cTotal == CPROPERTIES-d);
  4574. Check(S_OK, pPropStg->DeleteMultiple(1, ps+d));
  4575. Check(S_OK, penum->Reset());
  4576. }
  4577. penum->Release();
  4578. penum2->Release();
  4579. pPropStg->Release();
  4580. }
  4581. RELEASE_INTERFACE( pPropSetStg );
  4582. Check( cStorageRefs, GetRefCount(pstgTemp) );
  4583. }
  4584. void
  4585. test_MaxPropertyName(IStorage *pstgTemp)
  4586. {
  4587. if( PROPIMP_NTFS == g_enumImplementation ) return;
  4588. Status( "Max Property Name length\n" );
  4589. // ----------
  4590. // Initialize
  4591. // ----------
  4592. CPropVariant cpropvar;
  4593. // Create a new storage, because we're going to create
  4594. // well-known property sets, and this way we can be sure
  4595. // that they don't already exist.
  4596. IStorage *pstg = NULL; // TSafeStorage< IStorage > pstg;
  4597. Check(S_OK, pstgTemp->CreateStorage( OLESTR("MaxPropNameTest"),
  4598. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4599. 0L, 0L,
  4600. &pstg ));
  4601. // Generate a new Format ID.
  4602. FMTID fmtid;
  4603. UuidCreate(&fmtid);
  4604. // Get a IPropertySetStorage from the IStorage.
  4605. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pstg);
  4606. IPropertyStorage *pPropStg = NULL; // TSafeStorage< IPropertyStorage > pPropStg;
  4607. Check( S_OK, StgToPropSetStg( pstg, &pPropSetStg ));
  4608. // ----------------------------------
  4609. // Test the non-SumInfo property set.
  4610. // ----------------------------------
  4611. // Create a new PropertyStorage.
  4612. Check(S_OK, pPropSetStg->Create(fmtid,
  4613. NULL,
  4614. PROPSETFLAG_DEFAULT,
  4615. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  4616. &pPropStg));
  4617. // Generate a property name which greater than the old max length
  4618. // (NT5 removes the name length limitation, was 255 not including the terminator).
  4619. OLECHAR *poszPropertyName;
  4620. poszPropertyName = new OLECHAR[ (CCH_MAXPROPNAMESZ+1) * sizeof(OLECHAR) ];
  4621. Check(TRUE, poszPropertyName != NULL );
  4622. for( ULONG ulIndex = 0; ulIndex < CCH_MAXPROPNAMESZ; ulIndex++ )
  4623. poszPropertyName[ ulIndex ] = OLESTR('a') + (OLECHAR) ( ulIndex % 26 );
  4624. poszPropertyName[ CCH_MAXPROPNAMESZ ] = OLESTR('\0');
  4625. // Write out a property with this oldmax+1 name.
  4626. PROPSPEC propspec;
  4627. propspec.ulKind = PRSPEC_LPWSTR;
  4628. propspec.lpwstr = poszPropertyName;
  4629. cpropvar = (long) 0x1234;
  4630. Check(S_OK, pPropStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  4631. // Write out a property with a minimum-character name.
  4632. propspec.lpwstr = OLESTR("X");
  4633. Check(S_OK, pPropStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  4634. // Write out a property with a below-minimum-character name.
  4635. propspec.lpwstr = OLESTR("");
  4636. Check(STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, &propspec, &cpropvar, PID_FIRST_USABLE ));
  4637. delete [] poszPropertyName;
  4638. Check( 0, RELEASE_INTERFACE(pPropStg ));
  4639. RELEASE_INTERFACE(pPropSetStg);
  4640. Check( 0, RELEASE_INTERFACE(pstg) );
  4641. }
  4642. void
  4643. test_CodePages( LPOLESTR poszDirectory )
  4644. {
  4645. if( g_Restrictions & RESTRICT_UNICODE_ONLY ) return;
  4646. Status( "Code Page compatibility\n" );
  4647. // --------------
  4648. // Initialization
  4649. // --------------
  4650. OLECHAR oszBadFile[ MAX_PATH ];
  4651. OLECHAR oszGoodFile[ MAX_PATH ];
  4652. OLECHAR oszUnicodeFile[ MAX_PATH ];
  4653. OLECHAR oszMacFile[ MAX_PATH ];
  4654. HRESULT hr = S_OK;
  4655. IStorage *pStgBad = NULL, *pStgGood = NULL, *pStgUnicode = NULL, *pStgMac = NULL; // TSafeStorage< IStorage > pStgBad, pStgGood, pStgUnicode, pStgMac;
  4656. CPropVariant cpropvarWrite, cpropvarRead;
  4657. Check( TRUE, GetACP() == CODEPAGE_DEFAULT );
  4658. // ------------------------------
  4659. // Create test ANSI property sets
  4660. // ------------------------------
  4661. // Create a property set with a bad codepage.
  4662. ocscpy( oszBadFile, poszDirectory );
  4663. ocscat( oszBadFile, OLESTR( "\\BadCP.stg" ));
  4664. CreateCodePageTestFile( oszBadFile, &pStgBad );
  4665. ModifyPropSetCodePage( pStgBad, FMTID_NULL, CODEPAGE_BAD );
  4666. // Create a property set with a good codepage.
  4667. ocscpy( oszGoodFile, poszDirectory );
  4668. ocscat( oszGoodFile, OLESTR("\\GoodCP.stg") );
  4669. CreateCodePageTestFile( oszGoodFile, &pStgGood );
  4670. ModifyPropSetCodePage( pStgGood, FMTID_NULL, CODEPAGE_GOOD );
  4671. // Create a property set that has the OS Kind (in the
  4672. // header) set to "Mac".
  4673. ocscpy( oszMacFile, poszDirectory );
  4674. ocscat( oszMacFile, OLESTR("\\MacKind.stg") );
  4675. CreateCodePageTestFile( oszMacFile, &pStgMac );
  4676. ModifyOSVersion( pStgMac, 0x00010904 );
  4677. // ---------------------------
  4678. // Open the Ansi property sets
  4679. // ---------------------------
  4680. IPropertySetStorage *pPropSetStgBad = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgBad(pStgBad);
  4681. Check( S_OK, StgToPropSetStg( pStgBad, &pPropSetStgBad ));
  4682. IPropertySetStorage *pPropSetStgGood = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgGood(pStgGood);
  4683. Check( S_OK, StgToPropSetStg( pStgGood, &pPropSetStgGood ));
  4684. IPropertySetStorage *pPropSetStgMac = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgMac(pStgMac);
  4685. Check( S_OK, StgToPropSetStg( pStgMac, &pPropSetStgMac ));
  4686. IPropertyStorage *pPropStgBad = NULL, *pPropStgGood = NULL, *pPropStgMac = NULL;
  4687. Check(S_OK, pPropSetStgBad->Open(FMTID_NULL,
  4688. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  4689. &pPropStgBad));
  4690. Check(S_OK, pPropSetStgGood->Open(FMTID_NULL,
  4691. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  4692. &pPropStgGood));
  4693. Check(S_OK, pPropSetStgMac->Open(FMTID_NULL,
  4694. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  4695. &pPropStgMac));
  4696. // ------------------------------------------
  4697. // Test BSTRs in the three ANSI property sets
  4698. // ------------------------------------------
  4699. PROPSPEC propspec;
  4700. PROPVARIANT propvar;
  4701. PropVariantInit( &propvar );
  4702. // Attempt to read by name.
  4703. propspec.ulKind = PRSPEC_LPWSTR;
  4704. propspec.lpwstr = CODEPAGE_TEST_NAMED_PROPERTY;
  4705. Check(S_OK,
  4706. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  4707. g_pfnPropVariantClear( &propvar );
  4708. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4709. Check(
  4710. HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4711. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  4712. #endif
  4713. Check(S_OK,
  4714. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  4715. // Attempt to write by name. If this test fails, it may be because
  4716. // the machine doesn't support CODEPAGE_GOOD (this is the case by default
  4717. // on Win95). To remedy this situation, go to control panel, add/remove
  4718. // programs, windows setup (tab), check MultiLanguage support, then
  4719. // click OK. You'll have to restart the computer after this.
  4720. Check(S_OK,
  4721. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4722. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4723. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4724. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4725. #endif
  4726. Check(S_OK,
  4727. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4728. g_pfnPropVariantClear( &propvar );
  4729. // Attempt to read the BSTR property
  4730. propspec.ulKind = PRSPEC_PROPID;
  4731. propspec.propid = CODEPAGE_TEST_UNNAMED_BSTR_PROPID;
  4732. Check(S_OK,
  4733. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  4734. g_pfnPropVariantClear( &propvar );
  4735. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4736. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4737. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  4738. #endif
  4739. Check(S_OK,
  4740. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  4741. // Attempt to write the BSTR property
  4742. Check(S_OK,
  4743. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4744. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4745. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4746. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4747. #endif
  4748. Check(S_OK,
  4749. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4750. g_pfnPropVariantClear( &propvar );
  4751. // Attempt to read the BSTR Vector property
  4752. propspec.ulKind = PRSPEC_PROPID;
  4753. propspec.propid = CODEPAGE_TEST_VBSTR_PROPID;
  4754. Check(S_OK,
  4755. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  4756. g_pfnPropVariantClear( &propvar );
  4757. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4758. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4759. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  4760. #endif
  4761. Check(S_OK,
  4762. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  4763. // Attempt to write the BSTR Vector property
  4764. Check(S_OK,
  4765. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4766. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4767. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4768. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4769. #endif
  4770. Check(S_OK,
  4771. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4772. g_pfnPropVariantClear( &propvar );
  4773. // Attempt to read the Variant Vector which has a BSTR
  4774. propspec.ulKind = PRSPEC_PROPID;
  4775. propspec.propid = CODEPAGE_TEST_VPROPVAR_BSTR_PROPID;
  4776. Check(S_OK,
  4777. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  4778. g_pfnPropVariantClear( &propvar );
  4779. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4780. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4781. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  4782. #endif
  4783. Check(S_OK,
  4784. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  4785. // Attempt to write the Variant Vector which has a BSTR
  4786. Check(S_OK,
  4787. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4788. #ifndef OLE2ANSI // No error is generated if BSTRs are Ansi
  4789. Check(HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION),
  4790. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4791. #endif
  4792. Check(S_OK,
  4793. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4794. g_pfnPropVariantClear( &propvar );
  4795. // Attempt to read the I4 property. Reading the bad property set
  4796. // takes special handling, because it will return a different result
  4797. // depending on whether NTDLL is checked or free (the free will work,
  4798. // the checked generates an error in its validation checking).
  4799. propspec.ulKind = PRSPEC_PROPID;
  4800. propspec.propid = 4;
  4801. Check(S_OK,
  4802. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  4803. g_pfnPropVariantClear( &propvar );
  4804. hr = pPropStgBad->ReadMultiple( 1, &propspec, &propvar );
  4805. Check(TRUE, S_OK == hr || HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION) == hr );
  4806. g_pfnPropVariantClear( &propvar );
  4807. Check(S_OK,
  4808. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  4809. // Attempt to write the I4 property
  4810. Check(S_OK,
  4811. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4812. hr = pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE );
  4813. Check(TRUE, S_OK == hr || HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION) == hr );
  4814. Check(S_OK,
  4815. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  4816. g_pfnPropVariantClear( &propvar );
  4817. // ---------------------------------------
  4818. // Test LPSTRs in the Unicode property set
  4819. // ---------------------------------------
  4820. // This test doesn't verify that the LPSTRs are actually
  4821. // written in Unicode. A manual test is required for that.
  4822. // Create a Unicode property set. We'll make it
  4823. // non-simple so that we can test a VT_STREAM (which
  4824. // is stored like an LPSTR).
  4825. ocscpy( oszUnicodeFile, poszDirectory );
  4826. ocscat( oszUnicodeFile, OLESTR("\\UnicodCP.stg") );
  4827. Check(S_OK, g_pfnStgCreateStorageEx(oszUnicodeFile,
  4828. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4829. DetermineStgFmt( g_enumImplementation ),
  4830. 0, NULL, NULL,
  4831. DetermineStgIID( g_enumImplementation ),
  4832. reinterpret_cast<void**>(&pStgUnicode) ));
  4833. IPropertySetStorage *pPropSetStgUnicode = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgUnicode(pStgUnicode);
  4834. Check( S_OK, StgToPropSetStg( pStgUnicode, &pPropSetStgUnicode ));
  4835. IPropertyStorage *pPropStgUnicode = NULL; // TSafeStorage< IPropertyStorage > pPropStgUnicode;
  4836. Check(S_OK, pPropSetStgUnicode->Create(FMTID_NULL,
  4837. &CLSID_NULL,
  4838. PROPSETFLAG_NONSIMPLE,
  4839. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4840. &pPropStgUnicode));
  4841. // Write/verify an LPSTR property.
  4842. propspec.ulKind = PRSPEC_LPWSTR;
  4843. propspec.lpwstr = OLESTR("LPSTR Property");
  4844. cpropvarWrite = "An LPSTR Property";
  4845. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, &cpropvarWrite, PID_FIRST_USABLE ));
  4846. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, &cpropvarRead ));
  4847. Check(0, strcmp( (LPSTR) cpropvarWrite, (LPSTR) cpropvarRead ));
  4848. cpropvarRead.Clear();
  4849. // Write/verify a vector of LPSTR properties
  4850. propspec.lpwstr = OLESTR("Vector of LPSTR properties");
  4851. cpropvarWrite[1] = "LPSTR Property #1";
  4852. cpropvarWrite[0] = "LPSTR Property #0";
  4853. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, &cpropvarWrite, PID_FIRST_USABLE ));
  4854. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, &cpropvarRead ));
  4855. Check(0, strcmp( (LPSTR) cpropvarWrite[1], (LPSTR) cpropvarRead[1] ));
  4856. Check(0, strcmp( (LPSTR) cpropvarWrite[0], (LPSTR) cpropvarRead[0] ));
  4857. cpropvarRead.Clear();
  4858. // Write/verify a vector of variants which has an LPSTR
  4859. propspec.lpwstr = OLESTR("Variant Vector with an LPSTR");
  4860. cpropvarWrite[1] = (PROPVARIANT) CPropVariant("LPSTR in a Variant Vector");
  4861. cpropvarWrite[0] = (PROPVARIANT) CPropVariant((long) 22); // an I4
  4862. Check(TRUE, (VT_VECTOR | VT_VARIANT) == cpropvarWrite.VarType() );
  4863. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, &cpropvarWrite, PID_FIRST_USABLE ));
  4864. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, &cpropvarRead ));
  4865. Check(0, strcmp( (LPSTR) cpropvarWrite[1], (LPSTR) cpropvarRead[1] ));
  4866. cpropvarRead.Clear();
  4867. // Write/verify a Stream.
  4868. cpropvarWrite = (IStream*) NULL;
  4869. propspec.lpwstr = OLESTR("An IStream");
  4870. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, &cpropvarWrite, PID_FIRST_USABLE ));
  4871. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, &cpropvarRead ));
  4872. cpropvarRead.Clear();
  4873. // There's nothing more we can check for the VT_STREAM property, a manual
  4874. // check is required to verify that it was written correctly.
  4875. RELEASE_INTERFACE(pStgBad);
  4876. RELEASE_INTERFACE(pStgGood);
  4877. RELEASE_INTERFACE(pStgUnicode);
  4878. RELEASE_INTERFACE(pStgMac);
  4879. RELEASE_INTERFACE(pPropSetStgBad);
  4880. RELEASE_INTERFACE(pPropStgBad);
  4881. RELEASE_INTERFACE(pPropStgGood);
  4882. RELEASE_INTERFACE(pPropStgMac);
  4883. RELEASE_INTERFACE(pPropSetStgGood);
  4884. RELEASE_INTERFACE(pPropSetStgMac);
  4885. RELEASE_INTERFACE(pPropSetStgUnicode);
  4886. RELEASE_INTERFACE(pPropStgUnicode);
  4887. }
  4888. void
  4889. test_PropertyInterfaces(IStorage *pstgTemp)
  4890. {
  4891. Status( "Property Interface\n" );
  4892. g_nIndent++;
  4893. // this test depends on being first for enumerator
  4894. test_IEnumSTATPROPSETSTG(pstgTemp);
  4895. test_MaxPropertyName(pstgTemp);
  4896. test_IPropertyStorage(pstgTemp);
  4897. test_IPropertySetStorage(pstgTemp);
  4898. test_IEnumSTATPROPSTG(pstgTemp);
  4899. --g_nIndent;
  4900. }
  4901. //===================================================================
  4902. //
  4903. // Function: test_CopyTo
  4904. //
  4905. // Synopsis: Verify that IStorage::CopyTo copies an
  4906. // un-flushed property set.
  4907. //
  4908. // This test creates and writes to a simple property set,
  4909. // a non-simple property set, and a new Storage & Stream,
  4910. // all within the source (caller-provided) Storage.
  4911. //
  4912. // It then copies the entire source Storage to the
  4913. // destination Storage, and verifies that all commited
  4914. // data in the Source is also in the destination.
  4915. //
  4916. // All new Storages and property sets are created
  4917. // under a new base storage. The caller can specify
  4918. // if this base Storage is direct or transacted, and
  4919. // can specify if the property sets are direct or
  4920. // transacted.
  4921. //
  4922. //===================================================================
  4923. void test_CopyTo(IStorage *pstgSource, // Source of the CopyTo
  4924. IStorage *pstgDestination, // Destination of the CopyTo
  4925. ULONG ulBaseStgTransaction, // Transaction bit for the base storage.
  4926. ULONG ulPropSetTransaction, // Transaction bit for the property sets.
  4927. LPOLESTR oszBaseStorageName )
  4928. {
  4929. if( g_Restrictions & RESTRICT_NON_HIERARCHICAL ) return;
  4930. char szMessage[ 128 ];
  4931. sprintf( szMessage, "IStorage::CopyTo (Base Storage is %s, PropSets are %s)\n",
  4932. ulBaseStgTransaction & STGM_TRANSACTED ? "transacted" : "direct",
  4933. ulPropSetTransaction & STGM_TRANSACTED ? "transacted" : "direct" );
  4934. Status( szMessage );
  4935. // ---------------
  4936. // Local Variables
  4937. // ---------------
  4938. OLECHAR const *poszTestSubStorage = OLESTR( "TestStorage" );
  4939. OLECHAR const *poszTestSubStream = OLESTR( "TestStream" );
  4940. OLECHAR const *poszTestDataPreCommit = OLESTR( "Test Data (pre-commit)" );
  4941. OLECHAR const *poszTestDataPostCommit = OLESTR( "Test Data (post-commit)" );
  4942. long lSimplePreCommit = 0x0123;
  4943. long lSimplePostCommit = 0x4567;
  4944. long lNonSimplePreCommit = 0x89AB;
  4945. long lNonSimplePostCommit = 0xCDEF;
  4946. BYTE acReadBuffer[ 80 ];
  4947. ULONG cbRead;
  4948. FMTID fmtidSimple, fmtidNonSimple;
  4949. // Base Storages for the Source & Destination. All
  4950. // new Streams/Storages/PropSets will be created below here.
  4951. IStorage *pstgBaseSource = NULL;
  4952. IStorage *pstgBaseDestination = NULL;
  4953. IStorage *pstgSub = NULL; // A sub-storage of the base.
  4954. IStream *pstmSub = NULL; // A Stream in the sub-storage (pstgSub)
  4955. PROPSPEC propspec;
  4956. PROPVARIANT propvarSourceSimple,
  4957. propvarSourceNonSimple,
  4958. propvarDestination;
  4959. // -----
  4960. // Begin
  4961. // -----
  4962. // Create new format IDs
  4963. UuidCreate(&fmtidSimple);
  4964. UuidCreate(&fmtidNonSimple);
  4965. // -----------------------
  4966. // Create the base Storage
  4967. // -----------------------
  4968. // Create a base Storage for the Source. All of this test will be under
  4969. // that Storage.
  4970. // In the source Storage.
  4971. Check( S_OK, pstgSource->CreateStorage(
  4972. oszBaseStorageName,
  4973. STGM_CREATE | ulBaseStgTransaction | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4974. 0L, 0L,
  4975. &pstgBaseSource ));
  4976. // And in the destination Storage.
  4977. Check( S_OK, pstgDestination->CreateStorage(
  4978. oszBaseStorageName,
  4979. STGM_CREATE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4980. 0L, 0L,
  4981. &pstgBaseDestination ));
  4982. // -------------------------------------------
  4983. // Write data to a new Stream in a new Storage
  4984. // -------------------------------------------
  4985. // We'll partially verify the CopyTo by checking that this data
  4986. // makes it into the destination Storage.
  4987. // Create a Storage, and then a Stream within it.
  4988. Check( S_OK, pstgBaseSource->CreateStorage(
  4989. poszTestSubStorage,
  4990. STGM_CREATE | ulPropSetTransaction | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4991. 0L, 0L,
  4992. &pstgSub ));
  4993. Check( S_OK, pstgSub->CreateStream(
  4994. poszTestSubStream,
  4995. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4996. 0L, 0L,
  4997. &pstmSub ));
  4998. // Write data to the Stream.
  4999. Check( S_OK, pstmSub->Write(
  5000. poszTestDataPreCommit,
  5001. ( sizeof(OLECHAR)
  5002. *
  5003. (ocslen( poszTestDataPreCommit ) + sizeof(OLECHAR))
  5004. ),
  5005. NULL ));
  5006. // ---------------------------------------------------------
  5007. // Write to a new simple property set in the Source storage.
  5008. // ---------------------------------------------------------
  5009. IPropertySetStorage *pPropSetStgSource = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgSource(pstgBaseSource);
  5010. Check( S_OK, StgToPropSetStg( pstgBaseSource, &pPropSetStgSource ));
  5011. IPropertyStorage *pPropStgSource1 = NULL, *pPropStgSource2 = NULL, *pPropStgDestination = NULL;
  5012. // Create a property set mode.
  5013. Check(S_OK, pPropSetStgSource->Create(fmtidSimple,
  5014. NULL,
  5015. PROPSETFLAG_DEFAULT,
  5016. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  5017. &pPropStgSource1));
  5018. // Write the property set name (just to test this functionality).
  5019. PROPID pidDictionary = 0;
  5020. OLECHAR *poszPropSetName = OLESTR("Property Set for CopyTo Test");
  5021. Check(TRUE, CWC_MAXPROPNAMESZ >= ocslen(poszPropSetName) + sizeof(OLECHAR) );
  5022. Check(S_OK, pPropStgSource1->WritePropertyNames( 1, &pidDictionary, &poszPropSetName ));
  5023. // Create a PROPSPEC. We'll use this throughout the rest of the routine.
  5024. propspec.ulKind = PRSPEC_PROPID;
  5025. propspec.propid = 1000;
  5026. // Create a PROPVARIANT for this test of the Simple case.
  5027. propvarSourceSimple.vt = VT_I4;
  5028. propvarSourceSimple.lVal = lSimplePreCommit;
  5029. // Write the PROPVARIANT to the property set.
  5030. Check(S_OK, pPropStgSource1->WriteMultiple(1, &propspec, &propvarSourceSimple, 2));
  5031. // ---------------------------------------------------------------
  5032. // Write to a new *non-simple* property set in the Source storage.
  5033. // ---------------------------------------------------------------
  5034. // Create a property set.
  5035. Check(S_OK, pPropSetStgSource->Create(fmtidNonSimple,
  5036. NULL,
  5037. PROPSETFLAG_NONSIMPLE,
  5038. STGM_CREATE | STGM_SHARE_EXCLUSIVE | ulPropSetTransaction | STGM_READWRITE,
  5039. &pPropStgSource2));
  5040. // Set data in the PROPVARIANT for the non-simple test.
  5041. propvarSourceNonSimple.vt = VT_I4;
  5042. propvarSourceNonSimple.lVal = lNonSimplePreCommit;
  5043. // Write the PROPVARIANT to the property set.
  5044. Check(S_OK, pPropStgSource2->WriteMultiple(1, &propspec, &propvarSourceNonSimple, 2));
  5045. // -------------------------
  5046. // Commit everything so far.
  5047. // -------------------------
  5048. // Commit the sub-Storage.
  5049. Check(S_OK, pstgSub->Commit( STGC_DEFAULT ));
  5050. // Commit the simple property set.
  5051. Check(S_OK, pPropStgSource1->Commit( STGC_DEFAULT ));
  5052. // Commit the non-simple property set.
  5053. Check(S_OK, pPropStgSource2->Commit( STGC_DEFAULT ));
  5054. // Commit the base Storage which holds all of the above.
  5055. Check(S_OK, pstgBaseSource->Commit( STGC_DEFAULT ));
  5056. // -------------------------------------------------
  5057. // Write new data to everything but don't commit it.
  5058. // -------------------------------------------------
  5059. // Write to the sub-storage.
  5060. Check(S_OK, pstmSub->Seek(g_li0, STREAM_SEEK_SET, NULL));
  5061. Check( S_OK, pstmSub->Write(
  5062. poszTestDataPostCommit,
  5063. ( sizeof(OLECHAR)
  5064. *
  5065. (ocslen( poszTestDataPostCommit ) + sizeof(OLECHAR))
  5066. ),
  5067. NULL ));
  5068. // Write to the simple property set.
  5069. propvarSourceSimple.lVal = lSimplePostCommit;
  5070. Check(S_OK, pPropStgSource1->WriteMultiple(1, &propspec, &propvarSourceSimple, 2));
  5071. // Write to the non-simple property set.
  5072. propvarSourceNonSimple.lVal = lNonSimplePostCommit;
  5073. Check(S_OK, pPropStgSource2->WriteMultiple(1, &propspec, &propvarSourceNonSimple, PID_FIRST_USABLE ));
  5074. // -------------------------------------------
  5075. // Copy the source Storage to the destination.
  5076. // -------------------------------------------
  5077. // Release the sub-Storage (which is below the base Storage, and has
  5078. // a Stream with data in it), just to test that the CopyTo can
  5079. // handle it.
  5080. pstgSub->Release();
  5081. pstgSub = NULL;
  5082. Check(S_OK, pstgBaseSource->CopyTo( 0, NULL, NULL, pstgBaseDestination ));
  5083. // ----------------------------------------------------------
  5084. // Verify the simple property set in the destination Storage.
  5085. // ----------------------------------------------------------
  5086. IPropertySetStorage *pPropSetStgDestination = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStgDestination(pstgBaseDestination);
  5087. Check( S_OK, StgToPropSetStg( pstgBaseDestination, &pPropSetStgDestination ));
  5088. // Open the simple property set.
  5089. Check(S_OK, pPropSetStgDestination->Open(fmtidSimple,
  5090. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  5091. &pPropStgDestination));
  5092. // Verify the property set name.
  5093. OLECHAR *poszPropSetNameDestination;
  5094. BOOL bReadPropertyNamePassed = FALSE;
  5095. Check(S_OK, pPropStgDestination->ReadPropertyNames( 1, &pidDictionary,
  5096. &poszPropSetNameDestination ));
  5097. if( poszPropSetNameDestination // Did we get a name back?
  5098. && // If so, was it the correct name?
  5099. !ocscmp( poszPropSetName, poszPropSetNameDestination )
  5100. )
  5101. {
  5102. bReadPropertyNamePassed = TRUE;
  5103. }
  5104. delete [] poszPropSetNameDestination;
  5105. poszPropSetNameDestination = NULL;
  5106. Check( TRUE, bReadPropertyNamePassed );
  5107. // Read the PROPVARIANT that we wrote earlier.
  5108. Check(S_OK, pPropStgDestination->ReadMultiple(1, &propspec, &propvarDestination));
  5109. // Verify that it's correct.
  5110. Check(TRUE, propvarDestination.vt == propvarSourceSimple.vt );
  5111. Check(TRUE, propvarDestination.lVal == lSimplePostCommit);
  5112. Check(S_OK, pPropStgDestination->Commit( STGC_DEFAULT ));
  5113. Check(S_OK, pPropStgDestination->Release());
  5114. pPropStgDestination = NULL;
  5115. // ----------------------------------------------------------------
  5116. // Verify the *non-simple* property set in the destination Storage.
  5117. // ----------------------------------------------------------------
  5118. // Open the non-simple property set.
  5119. Check(S_OK,
  5120. pPropSetStgDestination->Open(fmtidNonSimple,
  5121. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5122. &pPropStgDestination));
  5123. // Read the PROPVARIANT that we wrote earlier.
  5124. Check(S_OK, pPropStgDestination->ReadMultiple(1, &propspec, &propvarDestination));
  5125. // Verify that they're the same.
  5126. Check(TRUE, propvarDestination.vt == propvarSourceNonSimple.vt );
  5127. Check(TRUE, propvarDestination.lVal
  5128. ==
  5129. ( STGM_TRANSACTED & ulPropSetTransaction
  5130. ?
  5131. lNonSimplePreCommit
  5132. :
  5133. lNonSimplePostCommit
  5134. ));
  5135. Check(S_OK, pPropStgDestination->Commit( STGC_DEFAULT ));
  5136. Check(S_OK, pPropStgDestination->Release());
  5137. pPropStgDestination = NULL;
  5138. // ------------------------------------------------
  5139. // Verify the test data in the destination Storage.
  5140. // ------------------------------------------------
  5141. // Now we can release and re-use the Stream pointer that
  5142. // currently points to the sub-Stream in the source docfile.
  5143. Check(STG_E_REVERTED, pstmSub->Commit( STGC_DEFAULT ));
  5144. Check(S_OK, pstmSub->Release());
  5145. pstmSub = NULL;
  5146. // Get the Storage then the Stream.
  5147. Check( S_OK, pstgBaseDestination->OpenStorage(
  5148. poszTestSubStorage,
  5149. NULL,
  5150. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  5151. NULL,
  5152. 0L,
  5153. &pstgSub ));
  5154. Check( S_OK, pstgSub->OpenStream(
  5155. poszTestSubStream,
  5156. NULL,
  5157. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5158. 0L,
  5159. &pstmSub ));
  5160. // Read the data and compare it against what we wrote.
  5161. Check( S_OK, pstmSub->Read(
  5162. acReadBuffer,
  5163. sizeof( acReadBuffer ),
  5164. &cbRead ));
  5165. OLECHAR const *poszTestData = ( STGM_TRANSACTED & ulPropSetTransaction )
  5166. ?
  5167. poszTestDataPreCommit
  5168. :
  5169. poszTestDataPostCommit;
  5170. Check( TRUE, cbRead == sizeof(OLECHAR)
  5171. *
  5172. (ocslen( poszTestData ) + sizeof(OLECHAR))
  5173. );
  5174. Check( FALSE, ocscmp( poszTestData, (OLECHAR *) acReadBuffer ));
  5175. // ----
  5176. // Exit
  5177. // ----
  5178. RELEASE_INTERFACE( pPropSetStgSource );
  5179. RELEASE_INTERFACE(pPropStgSource1);
  5180. RELEASE_INTERFACE(pPropStgSource2);
  5181. RELEASE_INTERFACE(pPropStgDestination);
  5182. RELEASE_INTERFACE(pPropSetStgDestination);
  5183. RELEASE_INTERFACE(pstgBaseSource);
  5184. RELEASE_INTERFACE(pstgBaseDestination);
  5185. RELEASE_INTERFACE(pstgSub);
  5186. RELEASE_INTERFACE(pstmSub);
  5187. // We're done. Don't bother to release anything;
  5188. // they'll release themselves in their destructors.
  5189. return;
  5190. } // test_CopyTo()
  5191. //--------------------------------------------------------
  5192. //
  5193. // Function: test_OLESpecTickerExample
  5194. //
  5195. // Synopsis: This function generates the ticker property set
  5196. // example that's used in the OLE Programmer's Reference
  5197. // (when describing property ID 0 - the dictionary).
  5198. //
  5199. //--------------------------------------------------------
  5200. #define PID_SYMBOL 0x7
  5201. #define PID_OPEN 0x3
  5202. #define PID_CLOSE 0x4
  5203. #define PID_HIGH 0x5
  5204. #define PID_LOW 0x6
  5205. #define PID_LAST 0x8
  5206. #define PID_VOLUME 0x9
  5207. void test_OLESpecTickerExample( IStorage* pstg )
  5208. {
  5209. Status( "Generate the Stock Ticker example from the OLE Programmer's Ref\n" );
  5210. // ------
  5211. // Locals
  5212. // ------
  5213. FMTID fmtid;
  5214. PROPSPEC propspec;
  5215. LPOLESTR oszPropSetName = OLESTR( "Stock Quote" );
  5216. LPOLESTR oszTickerSymbolName = OLESTR( "Ticker Symbol" );
  5217. LPOLESTR oszOpenName = OLESTR( "Opening Price" );
  5218. LPOLESTR oszCloseName = OLESTR( "Last Closing Price" );
  5219. LPOLESTR oszHighName = OLESTR( "High Price" );
  5220. LPOLESTR oszLowName = OLESTR( "Low Price" );
  5221. LPOLESTR oszLastName = OLESTR( "Last Price" );
  5222. LPOLESTR oszVolumeName = OLESTR( "Volume" );
  5223. // ---------------------------------
  5224. // Create a new simple property set.
  5225. // ---------------------------------
  5226. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg(pstg);
  5227. IPropertyStorage *pPropStg;
  5228. ULONG cStorageRefs = GetRefCount( pstg );
  5229. Check( S_OK, StgToPropSetStg( pstg, &pPropSetStg ));
  5230. UuidCreate( &fmtid );
  5231. Check(S_OK, pPropSetStg->Create(fmtid,
  5232. NULL,
  5233. PROPSETFLAG_DEFAULT, // Unicode
  5234. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5235. &pPropStg));
  5236. // ---------------------------------------------
  5237. // Fill in the simply property set's dictionary.
  5238. // ---------------------------------------------
  5239. // Write the property set's name.
  5240. PROPID pidDictionary = 0;
  5241. Check(S_OK, pPropStg->WritePropertyNames(1, &pidDictionary, &oszPropSetName ));
  5242. // Write the High price, forcing the dictionary to pad.
  5243. propspec.ulKind = PRSPEC_PROPID;
  5244. propspec.propid = PID_HIGH;
  5245. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszHighName ));
  5246. // Write the ticker symbol.
  5247. propspec.propid = PID_SYMBOL;
  5248. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszTickerSymbolName));
  5249. // Write the rest of the dictionary.
  5250. propspec.propid = PID_LOW;
  5251. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszLowName));
  5252. propspec.propid = PID_OPEN;
  5253. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszOpenName));
  5254. propspec.propid = PID_CLOSE;
  5255. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszCloseName));
  5256. propspec.propid = PID_LAST;
  5257. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszLastName));
  5258. propspec.propid = PID_VOLUME;
  5259. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &oszVolumeName));
  5260. // Write out the ticker symbol.
  5261. propspec.propid = PID_SYMBOL;
  5262. PROPVARIANT propvar;
  5263. propvar.vt = VT_LPWSTR;
  5264. propvar.pwszVal = L"MSFT";
  5265. Check(S_OK, pPropStg->WriteMultiple(1, &propspec, &propvar, 2));
  5266. // ----
  5267. // Exit
  5268. // ----
  5269. Check(S_OK, pPropStg->Commit( STGC_DEFAULT ));
  5270. Check(0, pPropStg->Release());
  5271. Check(S_OK, pstg->Commit( STGC_DEFAULT ));
  5272. RELEASE_INTERFACE( pPropSetStg );
  5273. Check( cStorageRefs, GetRefCount(pstg) );
  5274. return;
  5275. } // test_OLESpecTickerExample()
  5276. void
  5277. test_Office( LPOLESTR wszTestFile )
  5278. {
  5279. Status( "Generate Office Property Sets\n" );
  5280. IStorage *pStg = NULL;
  5281. IPropertyStorage *pPStgSumInfo=NULL, *pPStgDocSumInfo=NULL, *pPStgUserDefined=NULL;
  5282. IPropertySetStorage *pPSStg = NULL; // TSafeStorage<IPropertySetStorage> pPSStg;
  5283. PROPVARIANT propvarWrite, propvarRead;
  5284. PROPSPEC propspec;
  5285. PropVariantInit( &propvarWrite );
  5286. PropVariantInit( &propvarRead );
  5287. // Create the file
  5288. Check( S_OK, g_pfnStgCreateStorageEx( wszTestFile,
  5289. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5290. DetermineStgFmt( g_enumImplementation ),
  5291. 0L,
  5292. NULL,
  5293. NULL,
  5294. IID_IPropertySetStorage,
  5295. (void**) &pPSStg ));
  5296. // Create the SummaryInformation property set.
  5297. Check(S_OK, pPSStg->Create( FMTID_SummaryInformation,
  5298. NULL,
  5299. (g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_DEFAULT : PROPSETFLAG_ANSI,
  5300. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5301. &pPStgSumInfo ));
  5302. // Write a Title to the SumInfo property set.
  5303. PropVariantInit( &propvarWrite );
  5304. propvarWrite.vt = VT_LPSTR;
  5305. propvarWrite.pszVal = "Title from PropTest";
  5306. propspec.ulKind = PRSPEC_PROPID;
  5307. propspec.propid = PID_TITLE;
  5308. Check( S_OK, pPStgSumInfo->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  5309. Check( S_OK, pPStgSumInfo->ReadMultiple( 1, &propspec, &propvarRead ));
  5310. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  5311. Check( FALSE, strcmp( propvarWrite.pszVal, propvarRead.pszVal ));
  5312. g_pfnPropVariantClear( &propvarRead );
  5313. PropVariantInit( &propvarRead );
  5314. pPStgSumInfo->Release();
  5315. pPStgSumInfo = NULL;
  5316. // Create the DocumentSummaryInformation property set.
  5317. Check(S_OK, pPSStg->Create( FMTID_DocSummaryInformation,
  5318. NULL,
  5319. (g_Restrictions & RESTRICT_UNICODE_ONLY ) ? PROPSETFLAG_DEFAULT: PROPSETFLAG_ANSI,
  5320. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5321. &pPStgDocSumInfo ));
  5322. // Write a word-count to the DocSumInfo property set.
  5323. PropVariantInit( &propvarWrite );
  5324. propvarWrite.vt = VT_I4;
  5325. propvarWrite.lVal = 100;
  5326. propspec.ulKind = PRSPEC_PROPID;
  5327. propspec.propid = PID_WORDCOUNT;
  5328. Check( S_OK, pPStgDocSumInfo->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  5329. Check( S_OK, pPStgDocSumInfo->ReadMultiple( 1, &propspec, &propvarRead ));
  5330. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  5331. Check( TRUE, propvarWrite.lVal == propvarRead.lVal );
  5332. g_pfnPropVariantClear( &propvarRead );
  5333. PropVariantInit( &propvarRead );
  5334. pPStgDocSumInfo->Release();
  5335. pPStgDocSumInfo = NULL;
  5336. // Create the UserDefined property set.
  5337. Check(S_OK, pPSStg->Create( FMTID_UserDefinedProperties,
  5338. NULL,
  5339. (g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_DEFAULT : PROPSETFLAG_ANSI,
  5340. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5341. &pPStgUserDefined ));
  5342. // Write named string to the UserDefined property set.
  5343. PropVariantInit( &propvarWrite );
  5344. propvarWrite.vt = VT_LPSTR;
  5345. propvarWrite.pszVal = "User-Defined string from PropTest";
  5346. propspec.ulKind = PRSPEC_LPWSTR;
  5347. propspec.lpwstr = OLESTR("PropTest String");
  5348. Check( S_OK, pPStgUserDefined->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  5349. Check( S_OK, pPStgUserDefined->ReadMultiple( 1, &propspec, &propvarRead ));
  5350. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  5351. Check( FALSE, strcmp( propvarWrite.pszVal, propvarRead.pszVal ));
  5352. g_pfnPropVariantClear( &propvarRead );
  5353. PropVariantInit( &propvarRead );
  5354. pPStgUserDefined->Release();
  5355. pPStgUserDefined = NULL;
  5356. RELEASE_INTERFACE(pPSStg);
  5357. // And we're done! (Everything releases automatically)
  5358. return;
  5359. }
  5360. void
  5361. test_Office2(IStorage *pStorage)
  5362. {
  5363. if( g_Restrictions & RESTRICT_NON_HIERARCHICAL ) return;
  5364. Status( "Testing Office Property Sets\n" );
  5365. IStorage *pSubStorage = NULL; // TSafeStorage< IStorage > pSubStorage;
  5366. IPropertySetStorage *pPropSetStg = NULL; // TSafeStorage< IPropertySetStorage > pPropSetStg;
  5367. IPropertyStorage *pPropStg = NULL; // TSafeStorage< IPropertyStorage > pPropStg;
  5368. CPropSpec cpropspec;
  5369. // ----------------------------------
  5370. // Create a sub-storage for this test
  5371. // ----------------------------------
  5372. Check(S_OK, pStorage->CreateStorage( OLESTR("test_Office2"),
  5373. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5374. 0, 0, &pSubStorage ));
  5375. Check(S_OK, StgToPropSetStg( pSubStorage, &pPropSetStg ));
  5376. // --------------------------------------------------------
  5377. // Test the Create/Delete of the DocumentSummaryInformation
  5378. // property set (this requires special code because it
  5379. // has two sections).
  5380. // --------------------------------------------------------
  5381. // Create & Delete a DSI propset with just the first section.
  5382. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  5383. NULL,
  5384. PROPSETFLAG_DEFAULT,
  5385. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5386. &pPropStg));
  5387. pPropStg->Release(); pPropStg = NULL;
  5388. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  5389. // Create & Delete a DSI propset with just the second section
  5390. Check(S_OK, pPropSetStg->Create(FMTID_UserDefinedProperties,
  5391. NULL,
  5392. PROPSETFLAG_DEFAULT,
  5393. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5394. &pPropStg ));
  5395. pPropStg->Release(); pPropStg = NULL;
  5396. Check(S_OK, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  5397. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  5398. // --------------------------------------------
  5399. // Test the Create/Open of the DSI property set
  5400. // --------------------------------------------
  5401. // Create & Delete a DocumentSummaryInformation propset with both sections.
  5402. // If you delete the DSI propset first, it should delete both sections.
  5403. // If you delete the UD propset first, the DSI propset should still
  5404. // remain. We'll loop twice, trying both combinations.
  5405. for( int i = 0; i < 2; i++ )
  5406. {
  5407. // Create the first section.
  5408. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  5409. NULL,
  5410. PROPSETFLAG_DEFAULT,
  5411. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5412. &pPropStg));
  5413. pPropStg->Release(); pPropStg = NULL;
  5414. // Create the second section.
  5415. Check(S_OK, pPropSetStg->Create(FMTID_UserDefinedProperties,
  5416. NULL,
  5417. PROPSETFLAG_DEFAULT,
  5418. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5419. &pPropStg));
  5420. pPropStg->Release(); pPropStg = NULL;
  5421. if( i == 0 )
  5422. {
  5423. // Delete the second section, then the first.
  5424. Check(S_OK, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  5425. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  5426. }
  5427. else
  5428. {
  5429. // Delete the first section, then *attempt* to delete the second.
  5430. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  5431. Check(STG_E_FILENOTFOUND, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  5432. }
  5433. } // for( i = 0; i < 2; i++ )
  5434. // ------------------------------------------------------------------
  5435. // Verify that we can create the UD propset (the 2nd section) without
  5436. // harming the first section.
  5437. // ------------------------------------------------------------------
  5438. {
  5439. CPropSpec rgcpropspec[2];
  5440. CPropVariant rgcpropvarWrite[2];
  5441. CPropVariant cpropvarRead;
  5442. // Create the first section.
  5443. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  5444. NULL,
  5445. PROPSETFLAG_DEFAULT,
  5446. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5447. &pPropStg));
  5448. // Write a property to the first section.
  5449. rgcpropspec[0] = OLESTR("Test DSI Property");
  5450. rgcpropvarWrite[0] = (DWORD) 1;
  5451. Check(S_OK, pPropStg->WriteMultiple( 1, rgcpropspec[0], &rgcpropvarWrite[0],
  5452. PID_FIRST_USABLE ));
  5453. pPropStg->Release(); pPropStg = NULL;
  5454. // *Create* the second section
  5455. Check(S_OK, pPropSetStg->Create(FMTID_UserDefinedProperties,
  5456. NULL,
  5457. PROPSETFLAG_DEFAULT,
  5458. STGM_SHARE_EXCLUSIVE | STGM_READWRITE | STGM_CREATE,
  5459. &pPropStg ));
  5460. // Write a property to the second section
  5461. rgcpropspec[1] = OLESTR("Test UD Property");
  5462. rgcpropvarWrite[1] = (DWORD) 2;
  5463. Check(S_OK, pPropStg->WriteMultiple( 1, rgcpropspec[1], &rgcpropvarWrite[1],
  5464. PID_FIRST_USABLE ));
  5465. pPropStg->Release(); pPropStg = NULL;
  5466. // Verify the properties from each of the sections.
  5467. Check(S_OK, pPropSetStg->Open(FMTID_DocSummaryInformation,
  5468. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  5469. &pPropStg ));
  5470. Check(S_OK, pPropStg->ReadMultiple( 1, rgcpropspec[0], &cpropvarRead ));
  5471. Check(TRUE, rgcpropvarWrite[0] == cpropvarRead );
  5472. cpropvarRead.Clear();
  5473. pPropStg->Release(); pPropStg = NULL;
  5474. Check(S_OK, pPropSetStg->Open(FMTID_UserDefinedProperties,
  5475. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  5476. &pPropStg ));
  5477. Check(S_OK, pPropStg->ReadMultiple( 1, rgcpropspec[1], &cpropvarRead ));
  5478. Check(TRUE, rgcpropvarWrite[1] == cpropvarRead );
  5479. cpropvarRead.Clear();
  5480. pPropStg->Release(); pPropStg = NULL;
  5481. }
  5482. // -------------------------------------
  5483. // Test special properties in DocSumInfo
  5484. // -------------------------------------
  5485. // This verifies that when we Create a DocSumInfo
  5486. // property set, and write a Vector or LPSTRs,
  5487. // we can read it again. We test this because
  5488. // Vectors of LPSTRs are a special case in the DocSumInfo,
  5489. // and the Create & Open path are slightly different
  5490. // in CPropertySetStream::_LoadHeader.
  5491. // Create a new property set.
  5492. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  5493. NULL,
  5494. PROPSETFLAG_DEFAULT,
  5495. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  5496. &pPropStg));
  5497. // Create a vector of LPSTRs. Make the strings
  5498. // varying lengths to ensure we get plenty of
  5499. // opportunity for alignment problems.
  5500. CPropVariant cpropvarWrite, cpropvarRead;
  5501. cpropvarWrite[3] = "12345678";
  5502. cpropvarWrite[2] = "1234567";
  5503. cpropvarWrite[1] = "123456";
  5504. cpropvarWrite[0] = "12345";
  5505. Check(TRUE, cpropvarWrite.Count() == 4 );
  5506. // Write the property
  5507. cpropspec = OLESTR("A Vector of LPSTRs");
  5508. Check(S_OK, pPropStg->WriteMultiple( 1, cpropspec, &cpropvarWrite, 2 ));
  5509. // Read the property back.
  5510. Check(S_OK, pPropStg->ReadMultiple( 1, cpropspec, &cpropvarRead ));
  5511. // Verify that we read what we wrote.
  5512. for( i = 0; i < (int) cpropvarWrite.Count(); i++ )
  5513. {
  5514. Check(0, strcmp( (LPSTR) cpropvarWrite[i], (LPSTR) cpropvarRead[i] ));
  5515. }
  5516. // ----
  5517. // Exit
  5518. // ----
  5519. RELEASE_INTERFACE(pSubStorage);
  5520. RELEASE_INTERFACE(pPropSetStg);
  5521. RELEASE_INTERFACE(pPropStg);
  5522. return;
  5523. }
  5524. void test_PropVariantCopy( )
  5525. {
  5526. Status( "PropVariantCopy\n" );
  5527. PROPVARIANT propvarCopy;
  5528. PropVariantInit( &propvarCopy );
  5529. VERSIONEDSTREAM VersionedStream;
  5530. UuidCreate( &VersionedStream.guidVersion );
  5531. VersionedStream.pStream = NULL;
  5532. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  5533. {
  5534. Check(S_OK, g_pfnPropVariantCopy( &propvarCopy, &g_rgcpropvarAll[i] )); // g_pfnPropVariantCopy( &propvarCopy, &g_rgcpropvarAll[i] ));
  5535. Check(S_OK, CPropVariant::Compare( &propvarCopy, &g_rgcpropvarAll[i] ));
  5536. g_pfnPropVariantClear( &propvarCopy );
  5537. // If this is a stream, take the opportunity to do a test of vt_versioned_stream.
  5538. if( VT_STREAM == g_rgcpropvarAll[i].vt )
  5539. {
  5540. VersionedStream.pStream = g_rgcpropvarAll[i].pStream;
  5541. CPropVariant cpropvar = VersionedStream;
  5542. Check( S_OK, g_pfnPropVariantCopy( &propvarCopy, &cpropvar ));
  5543. Check( S_OK, CPropVariant::Compare( &propvarCopy, &cpropvar ));
  5544. g_pfnPropVariantClear( &propvarCopy );
  5545. }
  5546. }
  5547. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  5548. }
  5549. #define PERFORMANCE_ITERATIONS 300
  5550. #define STABILIZATION_ITERATIONS 10
  5551. void
  5552. test_Performance( IStorage *pStg )
  5553. {
  5554. //#ifndef _MAC
  5555. if( g_Restrictions & RESTRICT_NON_HIERARCHICAL ) return;
  5556. Status( "Performance\n" );
  5557. CPropVariant rgcpropvar[2];
  5558. CPropSpec rgpropspec[2];
  5559. IPropertySetStorage *pPSStg = NULL; // TSafeStorage< IPropertySetStorage > pPSStg( pStg );
  5560. Check( S_OK, StgToPropSetStg( pStg, &pPSStg ));
  5561. IPropertyStorage *pPStg = NULL; // TSafeStorage< IPropertyStorage > pPStg;
  5562. IStream *pStm = NULL; // TSafeStorage< IStream > pStm;
  5563. FMTID fmtid;
  5564. ULONG ulCount;
  5565. DWORD dwSumTimes;
  5566. FILETIME filetimeStart, filetimeEnd;
  5567. BYTE *pPropertyBuffer;
  5568. ULONG cbPropertyBuffer;
  5569. UuidCreate( &fmtid );
  5570. rgcpropvar[0][0] = L"I wish I were an Oscar Meyer wiener,";
  5571. rgcpropvar[0][1] = L"That is what I'd truly like to be.";
  5572. rgcpropvar[1][0] = "For if I were an Oscar Meyer wiener,";
  5573. rgcpropvar[1][1] = "Everyone would be in love with me.";
  5574. Check(TRUE, (VT_LPWSTR | VT_VECTOR) == rgcpropvar[0].VarType() );
  5575. Check(TRUE, (VT_LPSTR | VT_VECTOR) == rgcpropvar[1].VarType() );
  5576. // ----------------
  5577. // Test an IStorage
  5578. // ----------------
  5579. // Create a buffer to write which is the same size as
  5580. // the properties in rgcpropvar.
  5581. cbPropertyBuffer = sizeof(WCHAR)
  5582. *
  5583. (2 + wcslen(rgcpropvar[0][0]) + wcslen(rgcpropvar[0][1]));
  5584. cbPropertyBuffer += (2 + strlen(rgcpropvar[1][0]) + strlen(rgcpropvar[1][1]));
  5585. pPropertyBuffer = new BYTE[ cbPropertyBuffer ];
  5586. PRINTF( " Docfile CreateStream/Write/Release = " );
  5587. dwSumTimes = 0;
  5588. // Perform the test iterations
  5589. for( ulCount = 0;
  5590. ulCount < PERFORMANCE_ITERATIONS + STABILIZATION_ITERATIONS;
  5591. ulCount++ )
  5592. {
  5593. if( ulCount == STABILIZATION_ITERATIONS )
  5594. CoFileTimeNow( &filetimeStart );
  5595. Check(S_OK, pStg->CreateStream( OLESTR("StoragePerformance"),
  5596. STGM_CREATE | STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5597. 0L, 0L,
  5598. &pStm ));
  5599. Check(S_OK, pStm->Write( pPropertyBuffer, cbPropertyBuffer, NULL ));
  5600. pStm->Release(); pStm = NULL;
  5601. }
  5602. CoFileTimeNow( &filetimeEnd );
  5603. filetimeEnd -= filetimeStart;
  5604. PRINTF( "%4.2f ms\n", (float)filetimeEnd.dwLowDateTime
  5605. /
  5606. 10000 // # of 100 nanosec units in 1 ms
  5607. /
  5608. PERFORMANCE_ITERATIONS );
  5609. // ------------------------------------------------------
  5610. // Try Creating a Property Set and writing two properties
  5611. // ------------------------------------------------------
  5612. rgpropspec[0] = OLESTR("First Property");
  5613. rgpropspec[1] = OLESTR("Second Property");
  5614. PRINTF( " PropSet Create(Overwrite)/WriteMultiple/Release = " );
  5615. dwSumTimes = 0;
  5616. for( ulCount = 0;
  5617. ulCount < PERFORMANCE_ITERATIONS + STABILIZATION_ITERATIONS;
  5618. ulCount++ )
  5619. {
  5620. if( ulCount == STABILIZATION_ITERATIONS )
  5621. CoFileTimeNow( &filetimeStart) ;
  5622. Check(S_OK, pPSStg->Create( fmtid,
  5623. NULL,
  5624. PROPSETFLAG_DEFAULT | PROPSETFLAG_NONSIMPLE,
  5625. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5626. &pPStg ));
  5627. Check(S_OK, pPStg->WriteMultiple( 2, rgpropspec, rgcpropvar, PID_FIRST_USABLE ));
  5628. pPStg->Release(); pPStg = NULL;
  5629. }
  5630. CoFileTimeNow( &filetimeEnd );
  5631. filetimeEnd -= filetimeStart;
  5632. PRINTF( "%4.2f ms\n", (float)filetimeEnd.dwLowDateTime
  5633. /
  5634. 10000 // 100 ns units to 1 ms units
  5635. /
  5636. PERFORMANCE_ITERATIONS );
  5637. // ------------------------------------------------------
  5638. // WriteMultiple (with named properties) Performance Test
  5639. // ------------------------------------------------------
  5640. PRINTF( " WriteMultiple (named properties) = " );
  5641. Check(S_OK, pPSStg->Create( fmtid,
  5642. NULL,
  5643. PROPSETFLAG_DEFAULT | PROPSETFLAG_NONSIMPLE,
  5644. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5645. &pPStg ));
  5646. for( ulCount = 0;
  5647. ulCount < PERFORMANCE_ITERATIONS + STABILIZATION_ITERATIONS;
  5648. ulCount++ )
  5649. {
  5650. if( ulCount == STABILIZATION_ITERATIONS )
  5651. CoFileTimeNow( &filetimeStart );
  5652. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  5653. {
  5654. Check(S_OK, pPStg->WriteMultiple( 1, &g_rgcpropspecAll[i], &g_rgcpropvarAll[i], PID_FIRST_USABLE ));
  5655. }
  5656. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  5657. }
  5658. CoFileTimeNow( &filetimeEnd );
  5659. filetimeEnd -= filetimeStart;
  5660. PRINTF( "%4.2f ms\n", (float) filetimeEnd.dwLowDateTime
  5661. /
  5662. 10000 // 100 ns units to 1 ms units
  5663. /
  5664. PERFORMANCE_ITERATIONS );
  5665. pPStg->Release();
  5666. pPStg = NULL;
  5667. // --------------------------------------------------------
  5668. // WriteMultiple (with unnamed properties) Performance Test
  5669. // --------------------------------------------------------
  5670. {
  5671. CPropSpec rgcpropspecPIDs[ CPROPERTIES_ALL ];
  5672. PRINTF( " WriteMultiple (unnamed properties) = " );
  5673. Check(S_OK, pPSStg->Create( fmtid,
  5674. NULL,
  5675. PROPSETFLAG_DEFAULT | PROPSETFLAG_NONSIMPLE,
  5676. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5677. &pPStg ));
  5678. for( ulCount = 0; ulCount < CPROPERTIES_ALL; ulCount++ )
  5679. {
  5680. rgcpropspecPIDs[ ulCount ] = ulCount + PID_FIRST_USABLE;
  5681. }
  5682. for( ulCount = 0;
  5683. ulCount < PERFORMANCE_ITERATIONS + STABILIZATION_ITERATIONS;
  5684. ulCount++ )
  5685. {
  5686. if( ulCount == STABILIZATION_ITERATIONS )
  5687. CoFileTimeNow( &filetimeStart );
  5688. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  5689. {
  5690. Check(S_OK, pPStg->WriteMultiple( 1, &rgcpropspecPIDs[i], &g_rgcpropvarAll[i], PID_FIRST_USABLE ));
  5691. }
  5692. Check( S_OK, ResetRGPropVar( g_rgcpropvarAll ));
  5693. }
  5694. CoFileTimeNow( &filetimeEnd );
  5695. filetimeEnd -= filetimeStart;
  5696. PRINTF( "%4.2f ms\n", (float) filetimeEnd.dwLowDateTime
  5697. /
  5698. 10000 // 100 ns units to 1 ms units
  5699. /
  5700. PERFORMANCE_ITERATIONS );
  5701. pPStg->Release();
  5702. pPStg = NULL;
  5703. }
  5704. //#endif // #ifndef _MAC
  5705. } // test_Performance()
  5706. //
  5707. // Function: test_CoFileTimeNow
  5708. //
  5709. // This function has nothing to do with the property set code,
  5710. // but a property test happenned to expose a bug in it, so this
  5711. // was just as good a place as any to test the fix.
  5712. //
  5713. void
  5714. test_CoFileTimeNow()
  5715. {
  5716. #ifndef _MAC // No need to test this on the Mac, and we can't
  5717. // because it doesn't support SYSTEMTIME.
  5718. Status( "CoFileTimeNow " );
  5719. FILETIME ftCoFileTimeNow;
  5720. FILETIME ftCalculated;
  5721. SYSTEMTIME stCalculated;
  5722. // Test the input validation
  5723. Check(E_INVALIDARG, CoFileTimeNow( NULL ));
  5724. Check(E_INVALIDARG, CoFileTimeNow( (FILETIME*) 0x01234567 ));
  5725. // The bug in CoFileTimeNow caused it to report a time that was
  5726. // 900 ms short, 50% of the time. So let's just bounds check
  5727. // it several times as a verification.
  5728. for( int i = 0; i < 20; i++ )
  5729. {
  5730. Check(S_OK, CoFileTimeNow( &ftCoFileTimeNow ));
  5731. GetSystemTime(&stCalculated);
  5732. Check(TRUE, SystemTimeToFileTime(&stCalculated, &ftCalculated));
  5733. Check(TRUE, ftCoFileTimeNow <= ftCalculated );
  5734. Check(S_OK, CoFileTimeNow( &ftCoFileTimeNow ));
  5735. Check(TRUE, ftCoFileTimeNow >= ftCalculated );
  5736. // The CoFileTimeNow bug caused it to report the correct
  5737. // time for a second, then the 900 ms short time for a second.
  5738. // So let's sleep in this loop and ensure that we cover both
  5739. // seconds.
  5740. if( g_fVerbose )
  5741. PRINTF( "." );
  5742. Sleep(200);
  5743. }
  5744. PRINTF( "\n" );
  5745. #endif // #ifndef _MAC
  5746. }
  5747. void
  5748. test_PROPSETFLAG_UNBUFFERED( IStorage *pStg )
  5749. {
  5750. // ----------
  5751. // Initialize
  5752. // ----------
  5753. if( PROPIMP_DOCFILE_OLE32 != g_enumImplementation
  5754. &&
  5755. PROPIMP_DOCFILE_IPROP != g_enumImplementation )
  5756. return;
  5757. Status( "PROPSETFLAG_UNBUFFERED\n" );
  5758. IStorage *pStgBase = NULL;
  5759. IPropertyStorage *pPropStgUnbuffered = NULL, *pPropStgBuffered = NULL;
  5760. IStream *pstmUnbuffered = NULL, *pstmBuffered = NULL;
  5761. CPropSpec cpropspec;
  5762. CPropVariant cpropvar;
  5763. FMTID fmtidUnbuffered, fmtidBuffered;
  5764. OLECHAR oszPropStgNameUnbuffered[ CCH_MAX_PROPSTG_NAME+1 ],
  5765. oszPropStgNameBuffered[ CCH_MAX_PROPSTG_NAME+1 ];
  5766. // Generate two FMTIDs
  5767. UuidCreate( &fmtidUnbuffered );
  5768. UuidCreate( &fmtidBuffered );
  5769. // ----------------------------
  5770. // Create the Property Storages
  5771. // ----------------------------
  5772. // Create a transacted Storage
  5773. Check( S_OK, pStg->CreateStorage(
  5774. OLESTR("test_PROPSETFLAG_UNBUFFERED"),
  5775. STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5776. 0L, 0L,
  5777. &pStgBase ));
  5778. // Verify that we have the necessary APIs
  5779. Check( TRUE, g_pfnFmtIdToPropStgName && g_pfnPropStgNameToFmtId
  5780. && g_pfnStgCreatePropSetStg && g_pfnStgCreatePropStg
  5781. && g_pfnStgOpenPropStg );
  5782. // What are the property storages' stream names?
  5783. g_pfnFmtIdToPropStgName( &fmtidUnbuffered, oszPropStgNameUnbuffered );
  5784. g_pfnFmtIdToPropStgName( &fmtidBuffered, oszPropStgNameBuffered );
  5785. // Create Streams for the property storages
  5786. Check( S_OK, pStgBase->CreateStream(
  5787. oszPropStgNameUnbuffered,
  5788. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5789. 0L, 0L,
  5790. &pstmUnbuffered ));
  5791. Check( S_OK, pStgBase->CreateStream(
  5792. oszPropStgNameBuffered,
  5793. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5794. 0L, 0L,
  5795. &pstmBuffered ));
  5796. // Create two direct-mode IPropertyStorages (one buffered, one not)
  5797. Check( S_OK, g_pfnStgCreatePropStg( (IUnknown*) pstmUnbuffered,
  5798. fmtidUnbuffered,
  5799. &CLSID_NULL,
  5800. PROPSETFLAG_UNBUFFERED,
  5801. 0L, // Reserved
  5802. &pPropStgUnbuffered ));
  5803. pPropStgUnbuffered->Commit( STGC_DEFAULT );
  5804. pstmUnbuffered->Release(); pstmUnbuffered = NULL;
  5805. Check( S_OK, g_pfnStgCreatePropStg( (IUnknown*) pstmBuffered,
  5806. fmtidBuffered,
  5807. &CLSID_NULL,
  5808. PROPSETFLAG_DEFAULT,
  5809. 0L, // Reserved
  5810. &pPropStgBuffered ));
  5811. pPropStgBuffered->Commit( STGC_DEFAULT );
  5812. pstmBuffered->Release(); pstmBuffered = NULL;
  5813. // -------------------------
  5814. // Write, Commit, and Revert
  5815. // -------------------------
  5816. // Write to both property storages
  5817. cpropvar = "A Test String";
  5818. cpropspec = OLESTR("Property Name");
  5819. Check( S_OK, pPropStgUnbuffered->WriteMultiple( 1,
  5820. cpropspec,
  5821. &cpropvar,
  5822. PID_FIRST_USABLE ));
  5823. Check( S_OK, pPropStgBuffered->WriteMultiple( 1,
  5824. cpropspec,
  5825. &cpropvar,
  5826. PID_FIRST_USABLE ));
  5827. // Commit the base Storage. This should only cause
  5828. // the Unbuffered property to be commited.
  5829. pStgBase->Commit( STGC_DEFAULT );
  5830. // Revert the base Storage, and release the property storages.
  5831. // This should cause the property in the buffered property storage
  5832. // to be lost.
  5833. pStgBase->Revert();
  5834. pPropStgUnbuffered->Release(); pPropStgUnbuffered = NULL;
  5835. pPropStgBuffered->Release(); pPropStgBuffered = NULL;
  5836. // -----------------------------
  5837. // Re-Open the property storages
  5838. // -----------------------------
  5839. // Open the property storage Streams
  5840. Check( S_OK, pStgBase->OpenStream( oszPropStgNameUnbuffered,
  5841. 0L,
  5842. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5843. 0L,
  5844. &pstmUnbuffered ));
  5845. Check( S_OK, pStgBase->OpenStream( oszPropStgNameBuffered,
  5846. 0L,
  5847. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5848. 0L,
  5849. &pstmBuffered ));
  5850. // Get IPropertyStorage interfaces
  5851. Check( S_OK, g_pfnStgOpenPropStg( (IUnknown*) pstmUnbuffered,
  5852. fmtidUnbuffered,
  5853. PROPSETFLAG_UNBUFFERED,
  5854. 0L, // Reserved
  5855. &pPropStgUnbuffered ));
  5856. pstmUnbuffered->Release(); pstmUnbuffered = NULL;
  5857. Check( S_OK, g_pfnStgOpenPropStg( (IUnknown*) pstmBuffered,
  5858. fmtidBuffered,
  5859. PROPSETFLAG_DEFAULT,
  5860. 0L, // Reserved
  5861. &pPropStgBuffered ));
  5862. pstmBuffered->Release(); pstmBuffered = NULL;
  5863. // --------------------
  5864. // Validate the results
  5865. // --------------------
  5866. // We should only find the property in the un-buffered property set.
  5867. cpropvar.Clear();
  5868. Check( S_OK, pPropStgUnbuffered->ReadMultiple( 1, cpropspec, &cpropvar ));
  5869. cpropvar.Clear();
  5870. Check( S_FALSE, pPropStgBuffered->ReadMultiple( 1, cpropspec, &cpropvar ));
  5871. cpropvar.Clear();
  5872. } // test_PROPSETFLAG_UNBUFFERED()
  5873. void
  5874. test_PropStgNameConversion2()
  5875. {
  5876. Status( "FmtIdToPropStgName & PropStgNameToFmtId\n" );
  5877. // ------
  5878. // Locals
  5879. // ------
  5880. FMTID fmtidOriginal, fmtidNew;
  5881. OLECHAR oszPropStgName[ CCH_MAX_PROPSTG_NAME+1 ];
  5882. // ----------------------------------
  5883. // Do a simple conversion and inverse
  5884. // ----------------------------------
  5885. UuidCreate( &fmtidOriginal );
  5886. fmtidNew = FMTID_NULL;
  5887. Check( S_OK, g_pfnFmtIdToPropStgName( &fmtidOriginal, oszPropStgName ));
  5888. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5889. Check( TRUE, fmtidOriginal == fmtidNew );
  5890. // -----------------------
  5891. // Check the special-cases
  5892. // -----------------------
  5893. // Summary Information
  5894. Check( S_OK, g_pfnFmtIdToPropStgName( &FMTID_SummaryInformation, oszPropStgName ));
  5895. Check( 0, ocscmp( oszPropStgName, oszSummaryInformation ));
  5896. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5897. Check( TRUE, FMTID_SummaryInformation == fmtidNew );
  5898. // DocSumInfo (first section)
  5899. Check( S_OK, g_pfnFmtIdToPropStgName( &FMTID_DocSummaryInformation, oszPropStgName ));
  5900. Check( 0, ocscmp( oszPropStgName, oszDocSummaryInformation ));
  5901. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5902. Check( TRUE, FMTID_DocSummaryInformation == fmtidNew );
  5903. // DocSumInfo (second section)
  5904. Check( S_OK, g_pfnFmtIdToPropStgName( &FMTID_UserDefinedProperties, oszPropStgName ));
  5905. Check( 0, ocscmp( oszPropStgName, oszDocSummaryInformation ));
  5906. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5907. Check( TRUE, FMTID_DocSummaryInformation == fmtidNew );
  5908. // GlobalInfo (for PictureIt!)
  5909. Check( S_OK, g_pfnFmtIdToPropStgName( &fmtidGlobalInfo, oszPropStgName ));
  5910. Check( 0, ocscmp( oszPropStgName, oszGlobalInfo ));
  5911. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5912. Check( TRUE, fmtidGlobalInfo == fmtidNew );
  5913. // ImageContents (for PictureIt!)
  5914. Check( S_OK, g_pfnFmtIdToPropStgName( &fmtidImageContents, oszPropStgName ));
  5915. Check( 0, ocscmp( oszPropStgName, oszImageContents ));
  5916. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5917. Check( TRUE, fmtidImageContents == fmtidNew );
  5918. // ImageInfo (for PictureIt!)
  5919. Check( S_OK, g_pfnFmtIdToPropStgName( &fmtidImageInfo, oszPropStgName ));
  5920. Check( 0, ocscmp( oszPropStgName, oszImageInfo ));
  5921. Check( S_OK, g_pfnPropStgNameToFmtId( oszPropStgName, &fmtidNew ));
  5922. Check( TRUE, fmtidImageInfo == fmtidNew );
  5923. } // test_PropStgNameConversion()
  5924. void
  5925. test_PropStgNameConversion( IStorage *pStg )
  5926. {
  5927. if( g_Restrictions & RESTRICT_NON_HIERARCHICAL ) return;
  5928. Status( "Special-case property set names\n" );
  5929. // ------
  5930. // Locals
  5931. // ------
  5932. IStorage *pStgSub = NULL;
  5933. IPropertyStorage *pPropStg = NULL;
  5934. IPropertySetStorage *pPropSetStg = NULL;
  5935. IEnumSTATSTG *pEnumStg = NULL;
  5936. IEnumSTATPROPSETSTG *pEnumPropSet = NULL;
  5937. STATSTG rgstatstg[ NUM_WELL_KNOWN_PROPSETS ];
  5938. STATPROPSETSTG rgstatpropsetstg[ NUM_WELL_KNOWN_PROPSETS ];
  5939. UINT i;
  5940. DWORD cEnum;
  5941. BOOL bSumInfo= FALSE,
  5942. bDocSumInfo= FALSE,
  5943. bGlobalInfo= FALSE,
  5944. bImageContents= FALSE,
  5945. bImageInfo= FALSE;
  5946. // ------------------------------
  5947. // Create a Storage for this test
  5948. // ------------------------------
  5949. Check( S_OK, pStg->CreateStorage( OLESTR("Special Cases"),
  5950. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5951. 0, 0,
  5952. &pStgSub ));
  5953. // And get an IPropertySetStorage
  5954. Check( S_OK, StgToPropSetStg( pStgSub, &pPropSetStg ));
  5955. // --------------------------------------------------
  5956. // Create one of each of the well-known property sets
  5957. // --------------------------------------------------
  5958. Check( S_OK, pPropSetStg->Create( FMTID_SummaryInformation,
  5959. &CLSID_NULL,
  5960. PROPSETFLAG_ANSI,
  5961. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5962. &pPropStg ));
  5963. RELEASE_INTERFACE( pPropStg );
  5964. Check( S_OK, pPropSetStg->Create( FMTID_DocSummaryInformation,
  5965. &CLSID_NULL,
  5966. PROPSETFLAG_ANSI,
  5967. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5968. &pPropStg ));
  5969. RELEASE_INTERFACE( pPropStg );
  5970. Check( S_OK, pPropSetStg->Create( FMTID_UserDefinedProperties,
  5971. &CLSID_NULL,
  5972. PROPSETFLAG_ANSI,
  5973. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5974. &pPropStg ));
  5975. RELEASE_INTERFACE( pPropStg );
  5976. Check( S_OK, pPropSetStg->Create( fmtidGlobalInfo,
  5977. &CLSID_NULL,
  5978. PROPSETFLAG_ANSI,
  5979. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5980. &pPropStg ));
  5981. RELEASE_INTERFACE( pPropStg );
  5982. Check( S_OK, pPropSetStg->Create( fmtidImageContents,
  5983. &CLSID_NULL,
  5984. PROPSETFLAG_ANSI,
  5985. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5986. &pPropStg ));
  5987. RELEASE_INTERFACE( pPropStg );
  5988. Check( S_OK, pPropSetStg->Create( fmtidImageInfo,
  5989. &CLSID_NULL,
  5990. PROPSETFLAG_ANSI,
  5991. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  5992. &pPropStg ));
  5993. RELEASE_INTERFACE( pPropStg );
  5994. // ---------------------------------
  5995. // Verify the FMTID->Name conversion
  5996. // ---------------------------------
  5997. // We verify this by enumerating the Storage's streams,
  5998. // and checking for the expected names (e.g., we should see
  5999. // "SummaryInformation", "DocumentSummaryInformation", etc.)
  6000. Check( S_OK, pStgSub->EnumElements( 0, NULL, 0, &pEnumStg ));
  6001. // Get all of the names.
  6002. Check( S_FALSE, pEnumStg->Next( NUM_WELL_KNOWN_PROPSETS,
  6003. rgstatstg,
  6004. &cEnum ));
  6005. // There should only be WellKnown-1 stream names, since
  6006. // the UserDefined property set is part of the
  6007. // DocumentSummaryInformation stream.
  6008. Check( TRUE, cEnum == NUM_WELL_KNOWN_PROPSETS - 1 );
  6009. for( i = 0; i < cEnum; i++ )
  6010. {
  6011. if( !ocscmp( rgstatstg[i].pwcsName, oszSummaryInformation ))
  6012. bSumInfo= TRUE;
  6013. else if( !ocscmp( rgstatstg[i].pwcsName, oszDocSummaryInformation ))
  6014. bDocSumInfo= TRUE;
  6015. else if( !ocscmp( rgstatstg[i].pwcsName, oszGlobalInfo ))
  6016. bGlobalInfo= TRUE;
  6017. else if( !ocscmp( rgstatstg[i].pwcsName, oszImageContents ))
  6018. bImageContents= TRUE;
  6019. else if( !ocscmp( rgstatstg[i].pwcsName, oszImageInfo ))
  6020. bImageInfo= TRUE;
  6021. delete [] rgstatstg[i].pwcsName;
  6022. }
  6023. // Verify that we found all the names we expected to find.
  6024. Check( TRUE, bSumInfo && bDocSumInfo
  6025. && bGlobalInfo && bImageContents && bImageInfo );
  6026. RELEASE_INTERFACE( pEnumStg );
  6027. // ---------------------------------
  6028. // Verify the Name->FMTID Conversion
  6029. // ---------------------------------
  6030. // We do this by enumerating the property sets with IPropertySetStorage,
  6031. // and verify that it correctly converts the Stream names to the
  6032. // expected FMTIDs.
  6033. bSumInfo = bDocSumInfo = bGlobalInfo = bImageContents = bImageInfo = FALSE;
  6034. // Get the enumerator.
  6035. Check( S_OK, pPropSetStg->Enum( &pEnumPropSet ));
  6036. // Get all the property sets.
  6037. Check( S_FALSE, pEnumPropSet->Next( NUM_WELL_KNOWN_PROPSETS,
  6038. rgstatpropsetstg,
  6039. &cEnum ));
  6040. Check( TRUE, cEnum == NUM_WELL_KNOWN_PROPSETS - 1 );
  6041. // Look for each of the expected FMTIDs. We only look at WellKnown-1,
  6042. // because the UserDefined property set doesn't get enumerated.
  6043. for( i = 0; i < NUM_WELL_KNOWN_PROPSETS - 1; i++ )
  6044. {
  6045. if( rgstatpropsetstg[i].fmtid == FMTID_SummaryInformation )
  6046. bSumInfo = TRUE;
  6047. else if( rgstatpropsetstg[i].fmtid == FMTID_DocSummaryInformation )
  6048. bDocSumInfo = TRUE;
  6049. else if( rgstatpropsetstg[i].fmtid == fmtidGlobalInfo )
  6050. bGlobalInfo = TRUE;
  6051. else if( rgstatpropsetstg[i].fmtid == fmtidImageContents )
  6052. bImageContents = TRUE;
  6053. else if( rgstatpropsetstg[i].fmtid == fmtidImageInfo )
  6054. bImageInfo = TRUE;
  6055. }
  6056. // NOTE: There is no way(?) to test the name-to-FMTID
  6057. // conversion for the UserDefined property set without
  6058. // calling the conversion function directly, but that
  6059. // function isn't exported on Win95.
  6060. // Verify that we found all of the expected FMTIDs
  6061. Check( TRUE, bSumInfo && bDocSumInfo
  6062. && bGlobalInfo && bImageContents && bImageInfo );
  6063. RELEASE_INTERFACE( pEnumPropSet );
  6064. RELEASE_INTERFACE( pPropSetStg );
  6065. RELEASE_INTERFACE( pStgSub );
  6066. } // test_PropStgNameConversion()
  6067. //-----------------------------------------------------------------------------
  6068. //
  6069. // Function: test_SimpleLeaks
  6070. //
  6071. // This is a simple leak test. It doesn't test all functionality for
  6072. // leaks; it just checks the common path: create, open, read, write,
  6073. // and delete.
  6074. //
  6075. //-----------------------------------------------------------------------------
  6076. void test_SimpleLeaks( LPOLESTR poszDir )
  6077. {
  6078. IStorage *pStg = NULL;
  6079. IPropertySetStorage *pPropSetStg = NULL;
  6080. SYSTEM_PROCESS_INFORMATION spiStart, spiEnd;
  6081. OLECHAR oszTempFile[ MAX_PATH + 1 ];
  6082. ocscpy( oszTempFile, poszDir );
  6083. ocscat( oszTempFile, OLESTR("SimpleLeakTest") );
  6084. Status( "Simple Leak Test " );
  6085. Check( STATUS_SUCCESS, GetProcessInfo(&spiStart) );
  6086. for( long i = 0; i < 1*1000*1000; i++ )
  6087. {
  6088. if( i % (50*1000) == 0 )
  6089. PRINTF( "x");
  6090. CPropSpec rgpropspec[2];
  6091. CPropVariant rgpropvarWrite[2], rgpropvarRead[2];
  6092. IPropertyStorage *pPropStg = NULL;
  6093. Check( S_OK, g_pfnStgCreateStorageEx( oszTempFile,
  6094. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  6095. |
  6096. ( ((i&1) && !(g_Restrictions & RESTRICT_DIRECT_ONLY)) ? STGM_TRANSACTED : STGM_DIRECT ),
  6097. DetermineStgFmt( g_enumImplementation ),
  6098. 0L,
  6099. NULL,
  6100. NULL,
  6101. IID_IPropertySetStorage,
  6102. (void**) &pPropSetStg));
  6103. Check( S_OK, pPropSetStg->Create( FMTID_NULL, NULL,
  6104. ( (i&2) && !(g_Restrictions & RESTRICT_UNICODE_ONLY) ? PROPSETFLAG_ANSI : PROPSETFLAG_DEFAULT )
  6105. |
  6106. ( (i&4) && !(g_Restrictions & RESTRICT_SIMPLE_ONLY) ? PROPSETFLAG_NONSIMPLE : PROPSETFLAG_DEFAULT ),
  6107. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  6108. |
  6109. ( (i&8) && !(g_Restrictions & RESTRICT_DIRECT_ONLY) ? STGM_TRANSACTED : STGM_DIRECT ),
  6110. &pPropStg ));
  6111. rgpropspec[0] = OLESTR("Property Name");
  6112. rgpropspec[1] = 1000;
  6113. rgpropvarWrite[0] = "Hello, world";
  6114. rgpropvarWrite[1] = (ULONG) 23;
  6115. Check( S_OK, pPropStg->WriteMultiple( 2, rgpropspec, rgpropvarWrite, PID_FIRST_USABLE ));
  6116. Check( S_OK, pPropStg->Commit( STGC_DEFAULT ));
  6117. Check( 0, pPropStg->Release() );
  6118. Check( S_OK, pPropSetStg->Open( FMTID_NULL,
  6119. ( (i&16) && !(g_Restrictions & RESTRICT_DIRECT_ONLY) ? STGM_TRANSACTED : STGM_DIRECT )
  6120. |
  6121. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6122. &pPropStg ));
  6123. Check( S_OK, pPropStg->ReadMultiple( 2, rgpropspec, rgpropvarRead ));
  6124. Check( TRUE, rgpropvarRead[0] == rgpropvarWrite[0]
  6125. &&
  6126. rgpropvarRead[1] == rgpropvarWrite[1] );
  6127. Check( S_OK, pPropStg->DeleteMultiple( 2, rgpropspec ));
  6128. Check( S_OK, pPropStg->Commit( STGC_DEFAULT ));
  6129. Check( 0, pPropStg->Release() );
  6130. Check( S_OK, pPropSetStg->Delete( FMTID_NULL ));
  6131. Check( 0, pPropSetStg->Release() );
  6132. }
  6133. Check( STATUS_SUCCESS, GetProcessInfo(&spiEnd) );
  6134. if( g_fVerbose )
  6135. {
  6136. PRINTF( "\n" );
  6137. PRINTF( " process id %I64u\n", (ULONG_PTR) spiEnd.UniqueProcessId );
  6138. PRINTF( " threads %lu, %lu\n", spiStart.NumberOfThreads, spiEnd.NumberOfThreads );
  6139. PRINTF( " handles %lu, %lu\n", spiStart.HandleCount, spiEnd.HandleCount );
  6140. PRINTF( " virtual size %lu, %lu\n", spiStart.VirtualSize, spiEnd.VirtualSize );
  6141. PRINTF( " peak virtual size %lu, %lu\n", spiStart.PeakVirtualSize, spiEnd.PeakVirtualSize );
  6142. PRINTF( " working set %lu, %lu\n", spiStart.WorkingSetSize, spiEnd.WorkingSetSize );
  6143. PRINTF( " peak working set %lu, %lu\n", spiStart.PeakWorkingSetSize, spiEnd.PeakWorkingSetSize );
  6144. PRINTF( " pagefile usage %lu, %lu\n", spiStart.PagefileUsage, spiEnd.PagefileUsage );
  6145. PRINTF( " peak pagefile usage %lu, %lu\n", spiStart.PeakPagefileUsage, spiEnd.PeakPagefileUsage );
  6146. PRINTF( " private memory %lu, %lu\n", spiStart.PrivatePageCount, spiEnd.PrivatePageCount );
  6147. PRINTF( " quota paged pool %lu, %lu\n", spiStart.QuotaPagedPoolUsage, spiEnd.QuotaPagedPoolUsage );
  6148. PRINTF( " peak quota paged pool %lu, %lu\n", spiStart.QuotaPeakPagedPoolUsage, spiEnd.QuotaPeakPagedPoolUsage );
  6149. PRINTF( " quota non-paged pool %lu, %lu\n", spiStart.QuotaNonPagedPoolUsage, spiEnd.QuotaNonPagedPoolUsage );
  6150. PRINTF( " peak quota non-paged pool %lu, %lu\n", spiStart.QuotaPeakNonPagedPoolUsage, spiEnd.QuotaPeakNonPagedPoolUsage );
  6151. }
  6152. // Ensure that the working set and pagefile usage didn't change by
  6153. // more than 5%
  6154. ULONG ulWorkingSetDifference = spiEnd.WorkingSetSize > spiStart.WorkingSetSize
  6155. ? spiEnd.WorkingSetSize - spiStart.WorkingSetSize
  6156. : spiStart.WorkingSetSize - spiEnd.WorkingSetSize;
  6157. ULONG ulPagefileUsageDifference = spiEnd.PagefileUsage > spiStart.PagefileUsage
  6158. ? spiEnd.PagefileUsage - spiStart.PagefileUsage
  6159. : spiStart.PagefileUsage - spiEnd.PagefileUsage;
  6160. Check( TRUE,
  6161. ( ulWorkingSetDifference == 0
  6162. ||
  6163. spiStart.WorkingSetSize/ulWorkingSetDifference >= 20
  6164. )
  6165. &&
  6166. ( ulPagefileUsageDifference == 0
  6167. ||
  6168. spiStart.PagefileUsage/ulPagefileUsageDifference >= 20
  6169. )
  6170. );
  6171. } // test_SimpleLeaks
  6172. //-----------------------------------------------------------------------------
  6173. //
  6174. // Function: test_SimpleDocFile
  6175. //
  6176. // This function tests PropSet functionality on Simple DocFile.
  6177. // This test comes in multiple phases:
  6178. // 1) A simple docfile is created and a minimal amount of data is stored
  6179. // in it.
  6180. // 2) The docfile is closed and opened again. The test attempts to write
  6181. // a small string to the property storage in it. This should succeed.
  6182. // Then it attempts to write a 4K string, which should fail.
  6183. // 3) The docfile is closed and opened again. The test writes 3 small
  6184. // strings to the prop storage. This should be successful.
  6185. //
  6186. // 4) The docfile is deleted. A new docfile with a property set storage is
  6187. // created, and more than 4K data is written to it.
  6188. // 5) The docfile is opened and writing additional data to it should fail.
  6189. //
  6190. //-----------------------------------------------------------------------------
  6191. #define FOUR_K_SIZE 0x1000 // Make it at least 4K.
  6192. #define THREE_H_SIZE 300 // 300 bytes
  6193. #define ONE_H_SIZE 100 // 100 bytes
  6194. void
  6195. test_SimpleDocFile(LPOLESTR oszDir)
  6196. {
  6197. IStorage *pDfStg = NULL;
  6198. IPropertySetStorage *pPropSetStg = NULL;
  6199. IPropertyStorage *pPropStg = NULL;
  6200. OLECHAR oszFile[MAX_PATH];
  6201. CPropSpec rgPropSpec[3];
  6202. CPropVariant rgPropVariant[3];
  6203. LPSTR pFourKString;
  6204. int i;
  6205. if( RESTRICT_NON_HIERARCHICAL & g_Restrictions ) return; // NFF doesn't support simp mode
  6206. Status( "Simple-mode docfile\n" );
  6207. //
  6208. // Generate a filename from the directory name.
  6209. //
  6210. ocscpy( oszFile, oszDir );
  6211. ocscat( oszFile, OLESTR( "SimpDoc.stg" ));
  6212. //
  6213. // allocate a buffer with 1 less than 4K
  6214. // and fill it with characters.
  6215. //
  6216. pFourKString = new CHAR[ FOUR_K_SIZE ];
  6217. Check(TRUE, pFourKString != NULL);
  6218. pFourKString[0] = '\0';
  6219. for (i=0; i < ((FOUR_K_SIZE/8)-1); i++)
  6220. {
  6221. strcat(pFourKString,"abcd1234");
  6222. }
  6223. strcat(pFourKString,"abcd123");
  6224. rgPropSpec[0] = 0x10;
  6225. rgPropSpec[1] = 0x11;
  6226. rgPropSpec[2] = 0x12;
  6227. //-------------------
  6228. // 1st Test - setup
  6229. //-------------------
  6230. // Create a Docfile.
  6231. //
  6232. Check( S_OK, g_pfnStgCreateStorageEx( oszFile,
  6233. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6234. DetermineStgFmt( g_enumImplementation ),
  6235. 0L, NULL, NULL,
  6236. DetermineStgIID( g_enumImplementation ),
  6237. reinterpret_cast<void**>(&pDfStg) ));
  6238. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6239. // Test that we can QI between IStorage and IPropertySetStorage
  6240. if( UsingQIImplementation() )
  6241. {
  6242. IStorage *pstg2 = NULL, *pstg3 = NULL;
  6243. IPropertySetStorage *ppropsetstg2 = NULL, *ppropsetstg3 = NULL;
  6244. ULONG cRefs = GetRefCount( pDfStg );
  6245. Check( S_OK, pDfStg->QueryInterface( IID_IStorage, reinterpret_cast<void**>(&pstg2) ));
  6246. Check( S_OK, pstg2->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&ppropsetstg2) ));
  6247. Check( S_OK, ppropsetstg2->QueryInterface( IID_IStorage, reinterpret_cast<void**>(&pstg3) ));
  6248. Check( TRUE, pstg2 == pstg3 );
  6249. Check( S_OK, pstg3->QueryInterface( IID_IPropertySetStorage, reinterpret_cast<void**>(&ppropsetstg3) ));
  6250. Check( TRUE, ppropsetstg2 == ppropsetstg3 );
  6251. RELEASE_INTERFACE(ppropsetstg3);
  6252. RELEASE_INTERFACE(ppropsetstg2);
  6253. RELEASE_INTERFACE(pstg3);
  6254. Check( cRefs, RELEASE_INTERFACE(pstg2) );
  6255. }
  6256. Check( S_OK, pPropSetStg->Create( FMTID_UserDefinedProperties,
  6257. &CLSID_NULL,
  6258. PROPSETFLAG_ANSI,
  6259. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6260. &pPropStg ));
  6261. //
  6262. // Write several strings to the property storage
  6263. //
  6264. rgPropVariant[0] = "Hello, world";
  6265. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6266. rgPropVariant[0] = "New string for offset 0";
  6267. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6268. rgPropVariant[1] = "First string for offset 1";
  6269. Check(S_OK, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6270. //
  6271. // Release the storages and docfile.
  6272. //
  6273. RELEASE_INTERFACE(pPropStg);
  6274. RELEASE_INTERFACE(pPropSetStg);
  6275. RELEASE_INTERFACE(pDfStg);
  6276. //--------------
  6277. // 2nd Test
  6278. //--------------
  6279. //
  6280. // Now Open the DocFile and storages
  6281. // and write a small stream followed by a 4K stream.
  6282. //
  6283. //
  6284. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6285. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6286. STGFMT_ANY,
  6287. 0L, NULL, NULL,
  6288. IID_IStorage,
  6289. reinterpret_cast<void**>(&pDfStg) ));
  6290. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6291. Check(S_OK, pPropSetStg->Open(FMTID_UserDefinedProperties,
  6292. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  6293. //
  6294. // Write a small string followed by a string that is at least 4K.
  6295. // The large string write should fail because the simple stream allocates
  6296. // a minimum size stream of 4K, and on an Open will not allow the stream to
  6297. // grow.
  6298. //
  6299. rgPropVariant[0] = "After Open, Hello, world";
  6300. rgPropVariant[1] = pFourKString;
  6301. rgPropVariant[2] = "Another string after the long one";
  6302. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6303. Check(STG_E_INVALIDFUNCTION, pPropStg->WriteMultiple(2, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6304. Check(STG_E_INVALIDFUNCTION, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6305. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6306. RELEASE_INTERFACE(pPropStg);
  6307. RELEASE_INTERFACE(pPropSetStg);
  6308. RELEASE_INTERFACE(pDfStg);
  6309. //--------------
  6310. // 3rd Test
  6311. //--------------
  6312. //
  6313. // Open the DocFile again, and write smaller strings to the same
  6314. // location.
  6315. //
  6316. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6317. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6318. STGFMT_ANY,
  6319. 0, NULL, NULL,
  6320. IID_IStorage,
  6321. reinterpret_cast<void**>(&pDfStg) ));
  6322. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6323. Check(S_OK, pPropSetStg->Open(FMTID_UserDefinedProperties,
  6324. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  6325. //
  6326. // The smaller strings can be written because they fit in under the 4K
  6327. // size of the simple stream buffer.
  6328. //
  6329. rgPropVariant[0] = "2nd open, small string";
  6330. rgPropVariant[1] = "small string2";
  6331. rgPropVariant[2] = "small string3";
  6332. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6333. Check(S_OK, pPropStg->WriteMultiple(2, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6334. Check(S_OK, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6335. RELEASE_INTERFACE(pPropStg);
  6336. RELEASE_INTERFACE(pPropSetStg);
  6337. RELEASE_INTERFACE(pDfStg);
  6338. //---------------------------------
  6339. // 4th Test - Create Large PropSet
  6340. //---------------------------------
  6341. //
  6342. // Create a Docfile and fill with more than 4K.
  6343. //
  6344. Check( S_OK, g_pfnStgCreateStorageEx( oszFile,
  6345. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6346. DetermineStgFmt( g_enumImplementation ),
  6347. 0L, NULL, NULL,
  6348. DetermineStgIID( g_enumImplementation ),
  6349. reinterpret_cast<void**>(&pDfStg) ));
  6350. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6351. Check( S_OK, pPropSetStg->Create( FMTID_NULL,
  6352. &CLSID_NULL,
  6353. PROPSETFLAG_ANSI,
  6354. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6355. &pPropStg ));
  6356. rgPropSpec[0] = 0x10;
  6357. rgPropSpec[1] = 0x11;
  6358. rgPropSpec[2] = 0x12;
  6359. //
  6360. // Write several strings to the property storage
  6361. // The first one is a 4K string.
  6362. //
  6363. rgPropVariant[0] = pFourKString;
  6364. rgPropVariant[1] = "First string for offset 1";
  6365. rgPropVariant[2] = "small string3";
  6366. Check(S_OK, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6367. //
  6368. // Release the storages and docfile.
  6369. //
  6370. RELEASE_INTERFACE(pPropStg);
  6371. RELEASE_INTERFACE(pPropSetStg);
  6372. RELEASE_INTERFACE(pDfStg);
  6373. //--------------
  6374. // 5th Test
  6375. //--------------
  6376. //
  6377. // Open the DocFile again, and write the same strings in a different
  6378. // order.
  6379. //
  6380. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6381. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6382. STGFMT_ANY,
  6383. 0, NULL, NULL,
  6384. IID_IStorage,
  6385. reinterpret_cast<void**>(&pDfStg) ));
  6386. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6387. Check(S_OK, pPropSetStg->Open(CLSID_NULL,
  6388. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  6389. //
  6390. // The smaller strings can be written because they fit in under the 4K
  6391. // size of the simple stream buffer.
  6392. //
  6393. rgPropVariant[0] = "small string0";
  6394. rgPropVariant[1] = "First string for offset 1";
  6395. rgPropVariant[2] = pFourKString;
  6396. Check(S_OK, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6397. RELEASE_INTERFACE(pPropStg);
  6398. RELEASE_INTERFACE(pPropSetStg);
  6399. RELEASE_INTERFACE(pDfStg);
  6400. //--------------
  6401. // 6th Test
  6402. //--------------
  6403. //
  6404. // Open the DocFile again, and write larger strings to the same
  6405. // location. This should fail.
  6406. //
  6407. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6408. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_SIMPLE,
  6409. STGFMT_ANY,
  6410. 0, NULL, NULL,
  6411. IID_IStorage,
  6412. reinterpret_cast<void**>(&pDfStg) ));
  6413. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6414. Check(S_OK, pPropSetStg->Open(CLSID_NULL,
  6415. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  6416. //
  6417. // Now write the same thing again, only with one extra character.
  6418. // This should fail.
  6419. //
  6420. rgPropVariant[0] = "First string for offset 0";
  6421. rgPropVariant[1] = pFourKString;
  6422. rgPropVariant[2] = "small string00000";
  6423. Check(STG_E_INVALIDFUNCTION, pPropStg->WriteMultiple(3, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6424. RELEASE_INTERFACE(pPropStg);
  6425. RELEASE_INTERFACE(pPropSetStg);
  6426. RELEASE_INTERFACE(pDfStg);
  6427. delete [] pFourKString;
  6428. //--------------
  6429. // 7th Test - - A NON-SIMPLE MODE TEST
  6430. //--------------
  6431. //
  6432. // Create and write to a property set with an element of 400 bytes.
  6433. // Then delete 100 bytes. Commit the changes. The property set should
  6434. // have shrunk by at least 100 bytes.
  6435. //
  6436. // allocate a buffer with 300 bytes and fill it.
  6437. // and fill it with characters.
  6438. //
  6439. LPSTR pThreeHString = NULL;
  6440. LPSTR pOneHString = NULL;
  6441. //
  6442. // Fill the 3 Hundred Byte String
  6443. //
  6444. pThreeHString = new CHAR[ THREE_H_SIZE ];
  6445. Check(TRUE, pThreeHString != NULL);
  6446. pThreeHString[0] = '\0';
  6447. for (i=0; i < ((THREE_H_SIZE/8)-1); i++)
  6448. {
  6449. strcat(pThreeHString,"abcd1234");
  6450. }
  6451. strcat(pThreeHString,"abc");
  6452. //
  6453. // Fill the 1 Hundred Byte String
  6454. //
  6455. pOneHString = new CHAR[ ONE_H_SIZE ];
  6456. Check(TRUE, pOneHString != NULL);
  6457. pOneHString[0] = '\0';
  6458. for (i=0; i < ((ONE_H_SIZE/8)-1); i++)
  6459. {
  6460. strcat(pOneHString,"xyxy8787");
  6461. }
  6462. strcat(pOneHString,"xyx");
  6463. //
  6464. // Create a Docfile and fill with the string
  6465. //
  6466. Check( S_OK, g_pfnStgCreateStorageEx( oszFile,
  6467. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6468. DetermineStgFmt( g_enumImplementation ),
  6469. 0, NULL, NULL,
  6470. DetermineStgIID( g_enumImplementation ),
  6471. reinterpret_cast<void**>(&pDfStg) ));
  6472. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6473. Check( S_OK, pPropSetStg->Create( FMTID_NULL,
  6474. &CLSID_NULL,
  6475. PROPSETFLAG_ANSI,
  6476. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6477. &pPropStg ));
  6478. rgPropSpec[0] = 0x10;
  6479. rgPropSpec[1] = 0x11;
  6480. //
  6481. // Write the string to the property storage
  6482. //
  6483. rgPropVariant[0] = pThreeHString;
  6484. rgPropVariant[1] = pOneHString;
  6485. Check(S_OK, pPropStg->WriteMultiple(2, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6486. //
  6487. // Commit the changes and close.
  6488. //
  6489. Check(S_OK, pPropStg->Commit( STGC_DEFAULT ));
  6490. RELEASE_INTERFACE(pPropStg);
  6491. RELEASE_INTERFACE(pPropSetStg);
  6492. RELEASE_INTERFACE(pDfStg);
  6493. //
  6494. // Check the size of the property set.
  6495. //
  6496. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6497. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6498. STGFMT_ANY,
  6499. 0, NULL, NULL,
  6500. IID_IStorage,
  6501. reinterpret_cast<void**>(&pDfStg) ));
  6502. IStream *pStm;
  6503. STATSTG StatBuf;
  6504. OLECHAR ocsPropSetName[30];
  6505. DWORD cbStream;
  6506. RtlGuidToPropertySetName(&FMTID_NULL, ocsPropSetName);
  6507. Check(S_OK, pDfStg->OpenStream(
  6508. ocsPropSetName,
  6509. NULL,
  6510. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  6511. 0,
  6512. &pStm));
  6513. Check(S_OK, pStm->Stat( &StatBuf,STATFLAG_NONAME));
  6514. if (StatBuf.cbSize.HighPart != 0)
  6515. {
  6516. printf("FAILURE: test_SimpleDocFile: Test 7: Size High part is not zero\n");
  6517. }
  6518. cbStream = StatBuf.cbSize.LowPart;
  6519. RELEASE_INTERFACE(pStm);
  6520. //
  6521. // Delete
  6522. //
  6523. Check(S_OK, StgToPropSetStg( pDfStg, &pPropSetStg ));
  6524. Check(S_OK, pPropSetStg->Open(CLSID_NULL,
  6525. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  6526. Check(S_OK, pPropStg->DeleteMultiple(1, &rgPropSpec[1]));
  6527. //
  6528. // Commit the changes and close.
  6529. //
  6530. Check(S_OK, pPropStg->Commit( STGC_DEFAULT ));
  6531. RELEASE_INTERFACE(pPropStg);
  6532. RELEASE_INTERFACE(pPropSetStg);
  6533. RELEASE_INTERFACE(pDfStg);
  6534. //
  6535. // Check the size of the property set.
  6536. //
  6537. Check(S_OK, g_pfnStgOpenStorageEx(oszFile,
  6538. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6539. STGFMT_ANY,
  6540. 0, NULL, NULL,
  6541. IID_IStorage,
  6542. reinterpret_cast<void**>(&pDfStg) ));
  6543. RtlGuidToPropertySetName(&FMTID_NULL, ocsPropSetName);
  6544. Check(S_OK, pDfStg->OpenStream(
  6545. ocsPropSetName,
  6546. NULL,
  6547. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  6548. 0,
  6549. &pStm));
  6550. Check(S_OK, pStm->Stat( &StatBuf,STATFLAG_NONAME));
  6551. Check(TRUE, (StatBuf.cbSize.HighPart == 0));
  6552. Check(TRUE, (cbStream - StatBuf.cbSize.LowPart > 100));
  6553. //
  6554. // Release the storages and docfile.
  6555. //
  6556. delete [] pThreeHString;
  6557. delete [] pOneHString;
  6558. RELEASE_INTERFACE(pStm);
  6559. RELEASE_INTERFACE(pDfStg);
  6560. } // test_SimpleDocFile
  6561. //-----------------------------------------------------------------------------
  6562. //
  6563. // Function: test_ex_api
  6564. //
  6565. // This function tests the StgOpenStorageEx API to make sure it correctly
  6566. // opens an NTFS flat file property set when called with STGFMT_ANY for a
  6567. // property set that was created on an NTFS flat file.
  6568. //
  6569. //-----------------------------------------------------------------------------
  6570. void
  6571. test_ex_api(LPOLESTR oszDir)
  6572. {
  6573. IStorage *pDfStg = NULL;
  6574. IPropertySetStorage *pPropSetStg = NULL;
  6575. IPropertyStorage *pPropStg = NULL;
  6576. OLECHAR oszFile[MAX_PATH];
  6577. CPropSpec rgPropSpec[3];
  6578. CPropVariant rgPropVariant[3];
  6579. LPSTR pFourKString;
  6580. int i;
  6581. HRESULT hr;
  6582. FMTID fmtidAnsi;
  6583. Status( "Ex API Tests\n" );
  6584. //
  6585. // Generate a filename from the directory name.
  6586. //
  6587. ocscpy( oszFile, oszDir );
  6588. ocscat( oszFile, OLESTR( "StgApi.dat" ));
  6589. //
  6590. // Create a property set storage and a prop storage
  6591. //
  6592. Check( S_OK, g_pfnStgCreateStorageEx( oszFile,
  6593. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6594. DetermineStgFmt( g_enumImplementation ),
  6595. 0L,
  6596. NULL,
  6597. NULL,
  6598. IID_IPropertySetStorage,
  6599. (void**) &pPropSetStg));
  6600. Check(S_OK,pPropSetStg->Create( FMTID_NULL, NULL,
  6601. PROPSETFLAG_DEFAULT,
  6602. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6603. &pPropStg ));
  6604. //
  6605. // Write a string to it.
  6606. //
  6607. rgPropSpec[0] = 0x10;
  6608. rgPropVariant[0] = "Hello, world";
  6609. Check(S_OK, pPropStg->WriteMultiple(1, rgPropSpec, rgPropVariant, PID_FIRST_USABLE));
  6610. //
  6611. // Close it
  6612. //
  6613. pPropStg->Release();
  6614. pPropStg = NULL;
  6615. pPropSetStg->Release();
  6616. pPropSetStg = NULL;
  6617. //
  6618. // Open it.
  6619. //
  6620. Check(S_OK,g_pfnStgOpenStorageEx( oszFile,
  6621. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6622. STGFMT_ANY,
  6623. 0L,
  6624. NULL,
  6625. NULL,
  6626. IID_IPropertySetStorage,
  6627. (void**) &pPropSetStg ));
  6628. UuidCreate( &fmtidAnsi );
  6629. //
  6630. // Attempt to create an ANSI prop storage
  6631. //
  6632. Check(S_OK, pPropSetStg->Create( fmtidAnsi, &CLSID_NULL,
  6633. PROPSETFLAG_ANSI,
  6634. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  6635. &pPropStg ));
  6636. //
  6637. // Clean up before exiting.
  6638. //
  6639. if (pPropStg)
  6640. {
  6641. pPropStg->Release();
  6642. pPropStg = NULL;
  6643. }
  6644. if (pPropSetStg)
  6645. {
  6646. pPropSetStg->Release();
  6647. pPropSetStg = NULL;
  6648. }
  6649. }
  6650. void
  6651. test_UnsupportedProperties( IStorage *pStg )
  6652. {
  6653. IPropertySetStorage *pPropSetStg = NULL;
  6654. IPropertyStorage *pPropStg = NULL;
  6655. CPropVariant rgcpropvarWrite[2], cpropvarRead;
  6656. CPropSpec rgcpropspec[2];
  6657. Status( "Unsupported VarTypes\n" );
  6658. FMTID fmtid;
  6659. UuidCreate(&fmtid);
  6660. // Start by creating a property set with a couple of properties in it.
  6661. Check( S_OK, StgToPropSetStg( pStg, &pPropSetStg ));
  6662. Check( S_OK, pPropSetStg->Create( fmtid, NULL,
  6663. PROPSETFLAG_DEFAULT | PROPSETFLAG_CASE_SENSITIVE,
  6664. STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  6665. &pPropStg ));
  6666. rgcpropvarWrite[0] = (long) 1234; // VT_I4
  6667. rgcpropvarWrite[1] = (short) 56; // VT_I2
  6668. rgcpropspec[0] = PID_FIRST_USABLE;
  6669. rgcpropspec[1] = PID_FIRST_USABLE + 1;
  6670. Check( S_OK, pPropStg->WriteMultiple( 2, rgcpropspec, rgcpropvarWrite, PID_FIRST_USABLE ));
  6671. // Modify the first property so that it has an invalid VT
  6672. RELEASE_INTERFACE( pPropStg );
  6673. ModifyPropertyType( pStg, fmtid, rgcpropspec[0].propid, 0x500 );
  6674. // Try to read that property back (the one with the invalid VT)
  6675. Check( S_OK, pPropSetStg->Open( fmtid, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, &pPropStg ));
  6676. Check( HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED),
  6677. pPropStg->ReadMultiple( 1, &rgcpropspec[0], &cpropvarRead ));
  6678. // Verify that we can read back the other property
  6679. Check( S_OK, pPropStg->ReadMultiple( 1, &rgcpropspec[1], &cpropvarRead ));
  6680. Check( TRUE, cpropvarRead == rgcpropvarWrite[1] );
  6681. // And verify that we can't write a property with an invalid VT
  6682. rgcpropvarWrite[0].vt = 0x500;
  6683. Check( HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED),
  6684. pPropStg->WriteMultiple( 1, &rgcpropspec[0], &rgcpropvarWrite[0], PID_FIRST_USABLE ));
  6685. RELEASE_INTERFACE( pPropStg );
  6686. RELEASE_INTERFACE( pPropSetStg );
  6687. }