Leaked source code of windows server 2003
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.

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