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.

5917 lines
172 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: proptest.cxx
  7. //
  8. // Description: This is the main file for all the tests
  9. // of Property set interfaces.
  10. //
  11. //---------------------------------------------------------------
  12. //
  13. // IPropertyStorage tests
  14. //
  15. // NOTE: we require more headers here just for convenience of
  16. // the test program, for other programs only "props.h" should be
  17. // needed.
  18. #ifndef _UNIX
  19. #define INITGUID
  20. #endif // _UNIX
  21. #include "../../props/h/windef.h"
  22. #include "../../h/props.h"
  23. #include "../../props/h/propapi.h"
  24. #include "../../props/h/propset.hxx"
  25. #include "cpropvar.hxx"
  26. #include "../../props/h/propmac.hxx"
  27. #include "../../time.hxx"
  28. #include "proptest.hxx"
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #ifdef _WIN32
  32. #include <direct.h> // _mkdir is stored here in win32
  33. #endif
  34. // -------
  35. // Globals
  36. // -------
  37. #ifndef _UNIX
  38. // again for static linkage, these symbols will be duplicated.
  39. OLECHAR aocMap[33], oszSummary[19], oszDocumentSummary[27];
  40. GUID guidSummary =
  41. { 0xf29f85e0,
  42. 0x4ff9, 0x1068,
  43. { 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 } };
  44. GUID guidDocumentSummary =
  45. { 0xd5cdd502,
  46. 0x2e9c, 0x101b,
  47. { 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
  48. GUID guidDocumentSummary2 =
  49. { 0xd5cdd505,
  50. 0x2e9c, 0x101b,
  51. { 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
  52. #else
  53. extern LPOLESTR aocMap, oszSummary, oszDocumentSummary;
  54. extern GUID guidSummary, guidDocumentSummary, guidDocumentSummary2;
  55. #endif // _UNIX
  56. LARGE_INTEGER g_li0;
  57. CPropVariant g_rgcpropvarAll[ CPROPERTIES_ALL ];
  58. CPropSpec g_rgcpropspecAll[ CPROPERTIES_ALL ];
  59. char g_szPropHeader[] = " propid/name propid cb type value\n";
  60. char g_szEmpty[] = "";
  61. BOOL g_fVerbose = FALSE;
  62. /* just a uuid that we use to create new uuids */
  63. GUID g_curUuid =
  64. { /* e4ecf7f0-e587-11cf-b10d-00aa005749e9 */
  65. 0xe4ecf7f0,
  66. 0xe587,
  67. 0x11cf,
  68. {0xb1, 0x0d, 0x00, 0xaa, 0x00, 0x57, 0x49, 0xe9}
  69. };
  70. #define TEST_STANDARD 0x1
  71. #define TEST_WORD6 0x2
  72. #define TEST_INTEROP_W 0x4
  73. #define TEST_INTEROP_R 0x8
  74. __inline OLECHAR
  75. MapChar(IN ULONG i)
  76. {
  77. return((OLECHAR) aocMap[i & CHARMASK]);
  78. }
  79. //
  80. // We simulate uuidcreate by incrementing a global uuid
  81. // each time the function is called.
  82. //
  83. void UuidCreate (
  84. OUT GUID * pUuid
  85. )
  86. {
  87. g_curUuid.Data1++;
  88. *pUuid = g_curUuid; // member to member copy
  89. }
  90. #ifndef _UNIX
  91. //+--------------------------------------------------------------------------
  92. // Function: RtlGuidToPropertySetName
  93. //
  94. // Synopsis: Map property set GUID to null-terminated OLECODE name string.
  95. //
  96. // The aocname parameter is assumed to be a buffer with room for
  97. // CCH_PROPSETSZ (28) OLECHARs. The first character
  98. // is always OC_PROPSET0 (0x05), as specified by the OLE Appendix
  99. // B documentation. The colon character normally used as an NT
  100. // stream name separator is not written to the caller's buffer.
  101. //
  102. // No error is possible.
  103. // Arguments: IN GUID *pguid -- pointer to GUID to convert
  104. // OUT OLECHAR aocname[] -- output string buffer
  105. //
  106. // Returns: count of non-NULL characters in the output string buffer
  107. //---------------------------------------------------------------------------
  108. ULONG PROPSYSAPI PROPAPI
  109. RtlGuidToPropertySetName(
  110. IN GUID const *pguid,
  111. OUT OLECHAR aocname[])
  112. {
  113. BYTE *pb = (BYTE *) pguid;
  114. BYTE *pbEnd = pb + sizeof(*pguid);
  115. ULONG cbitRemain = CBIT_BYTE;
  116. OLECHAR *poc = aocname;
  117. *poc++ = OC_PROPSET0;
  118. // Note: CCH_PROPSET includes the OC_PROPSET0, and sizeof(osz...)
  119. // includes the trailing L'\0', so sizeof(osz...) is ok because the
  120. // OC_PROPSET0 character compensates for the trailing NULL character.
  121. ASSERT(CCH_PROPSET >= sizeof(oszSummary)/sizeof(OLECHAR));
  122. if (*pguid == guidSummary)
  123. {
  124. RtlCopyMemory(poc, oszSummary, sizeof(oszSummary));
  125. return(sizeof(oszSummary)/sizeof(OLECHAR));
  126. }
  127. ASSERT(CCH_PROPSET >= sizeof(oszDocumentSummary)/sizeof(OLECHAR));
  128. if (*pguid == guidDocumentSummary || *pguid == guidDocumentSummary2)
  129. {
  130. RtlCopyMemory(poc, oszDocumentSummary, sizeof(oszDocumentSummary));
  131. return(sizeof(oszDocumentSummary)/sizeof(OLECHAR));
  132. }
  133. while (pb < pbEnd)
  134. {
  135. ULONG i = *pb >> (CBIT_BYTE - cbitRemain);
  136. if (cbitRemain >= CBIT_CHARMASK)
  137. {
  138. *poc = MapChar(i);
  139. if (cbitRemain == CBIT_BYTE &&
  140. *poc >= ((OLECHAR)'a') &&
  141. *poc <= ((OLECHAR)'z') )
  142. {
  143. *poc += (OLECHAR) ((OLECHAR)('A') - (OLECHAR)('a'));
  144. }
  145. poc++;
  146. cbitRemain -= CBIT_CHARMASK;
  147. if (cbitRemain == 0)
  148. {
  149. pb++;
  150. cbitRemain = CBIT_BYTE;
  151. }
  152. }
  153. else
  154. {
  155. if (++pb < pbEnd)
  156. {
  157. i |= *pb << cbitRemain;
  158. }
  159. *poc++ = MapChar(i);
  160. cbitRemain += CBIT_BYTE - CBIT_CHARMASK;
  161. }
  162. }
  163. *poc = (OLECHAR)'\0';
  164. return(CCH_PROPSET);
  165. }
  166. #endif // #ifndef _UNIX
  167. #define Check(x,y) _Check(x,y, __LINE__)
  168. void Cleanup(); // forward declaration
  169. //+=================================================================
  170. //
  171. // Function: _Check
  172. //
  173. // Synopsis: Verify that the actual HR is the expected
  174. // value. If not, report an error and exit.
  175. //
  176. // Inputs: [HRESULT] hrExpected
  177. // What we expected
  178. // [HRESULT] hrActual
  179. // The actual HR of the previous operation.
  180. // [int] line
  181. // The line number of the operation.
  182. //
  183. // Outputs: None.
  184. //
  185. //+=================================================================
  186. void _Check(HRESULT hrExpected, HRESULT hrActual, int line)
  187. {
  188. if (hrExpected != hrActual)
  189. {
  190. printf("\nFailed with hr=%08x at line %d (expected hr=%08x in proptest.cxx)\n",
  191. hrActual, line, hrExpected );
  192. Cleanup();
  193. }
  194. }
  195. OLECHAR * GetNextTest()
  196. {
  197. static int nTest;
  198. static CHAR pchBuf[10];
  199. static OLECHAR pocs[10];
  200. sprintf(pchBuf, "%d", nTest++);
  201. STOT(pchBuf, pocs, strlen(pchBuf)+1);
  202. return(pocs);
  203. }
  204. void Now(FILETIME *pftNow)
  205. {
  206. DfGetTOD(pftNow);
  207. }
  208. enum CreateOpen
  209. {
  210. Create, Open
  211. };
  212. IStorage *_pstgTemp=NULL;
  213. IStorage *_pstgTempCopyTo=NULL; // _pstgTemp is copied to _pstgTempCopyTo
  214. class CTempStorage
  215. {
  216. public:
  217. CTempStorage(DWORD grfMode = STGM_DIRECT | STGM_CREATE)
  218. {
  219. Check(S_OK, (_pstgTemp->CreateStorage(GetNextTest(), grfMode |
  220. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
  221. &_pstg)));
  222. }
  223. CTempStorage(CreateOpen co, IStorage *pstgParent,
  224. OLECHAR *pocsChild, DWORD grfMode = STGM_DIRECT)
  225. {
  226. if (co == Create)
  227. Check(S_OK, pstgParent->CreateStorage(pocsChild,
  228. grfMode | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
  229. &_pstg));
  230. else
  231. Check(S_OK, pstgParent->OpenStorage(pocsChild, NULL,
  232. grfMode | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0,
  233. &_pstg));
  234. }
  235. ~CTempStorage()
  236. {
  237. if (_pstg != NULL)
  238. _pstg->Release();
  239. }
  240. IStorage * operator -> ()
  241. {
  242. return(_pstg);
  243. }
  244. operator IStorage * ()
  245. {
  246. return(_pstg);
  247. }
  248. void Release()
  249. {
  250. if (_pstg != NULL)
  251. {
  252. _pstg->Release();
  253. _pstg = NULL;
  254. }
  255. }
  256. private:
  257. static unsigned int _iName;
  258. IStorage * _pstg;
  259. };
  260. unsigned int CTempStorage::_iName;
  261. class CGenProps
  262. {
  263. public:
  264. CGenProps() : _vt((VARENUM)2) {}
  265. PROPVARIANT * GetNext(int HowMany, int *pActual, BOOL fWrapOk = FALSE, BOOL fNoNonSimple = TRUE);
  266. private:
  267. BOOL _GetNext(PROPVARIANT *pVar, BOOL fWrapOk, BOOL fNoNonSimple);
  268. VARENUM _vt;
  269. };
  270. PROPVARIANT * CGenProps::GetNext(int HowMany, int *pActual, BOOL fWrapOk, BOOL fNoNonSimple)
  271. {
  272. PROPVARIANT *pVar = new PROPVARIANT[HowMany];
  273. if (pVar == NULL)
  274. return(NULL);
  275. int l;
  276. for (l=0; l<HowMany && _GetNext(pVar + l, fWrapOk, fNoNonSimple); l++) { };
  277. if (pActual)
  278. *pActual = l;
  279. if (l == 0)
  280. {
  281. delete pVar;
  282. return(NULL);
  283. }
  284. return(pVar);
  285. }
  286. BOOL CGenProps::_GetNext(PROPVARIANT *pVar, BOOL fWrapOk, BOOL fNoNonSimple)
  287. {
  288. if (_vt == (VT_VECTOR | VT_CLSID)+1)
  289. {
  290. if (!fWrapOk)
  291. return(FALSE);
  292. else
  293. _vt = (VARENUM)2;
  294. }
  295. PROPVARIANT Var;
  296. BOOL fFirst = TRUE;
  297. do
  298. {
  299. GUID *pg;
  300. if (!fFirst)
  301. {
  302. PropVariantClear(&Var);
  303. }
  304. fFirst = FALSE;
  305. memset(&Var, 0, sizeof(Var));
  306. Var.vt = _vt;
  307. (*((int*)&_vt))++;
  308. switch (Var.vt)
  309. {
  310. case VT_LPSTR:
  311. Var.pszVal = (LPSTR)CoTaskMemAlloc(6);
  312. strcpy(Var.pszVal, "lpstr");
  313. break;
  314. case VT_LPWSTR:
  315. DECLARE_WIDESTR(wcsTemp, "lpwstr");
  316. Var.pwszVal = (LPWSTR)CoTaskMemAlloc(14);
  317. wcscpy(Var.pwszVal, wcsTemp);
  318. break;
  319. case VT_CLSID:
  320. pg = (GUID*)CoTaskMemAlloc(sizeof(GUID));
  321. UuidCreate(pg);
  322. Var.puuid = pg;
  323. break;
  324. case VT_CF:
  325. Var.pclipdata = (CLIPDATA*)CoTaskMemAlloc(sizeof(CLIPDATA));
  326. Var.pclipdata->cbSize = 10;
  327. Var.pclipdata->pClipData = (BYTE*)CoTaskMemAlloc(10);
  328. Var.pclipdata->ulClipFmt = 0;
  329. break;
  330. }
  331. } while ( (fNoNonSimple &&
  332. (Var.vt == VT_STREAM || Var.vt == VT_STREAMED_OBJECT ||
  333. Var.vt == VT_STORAGE || Var.vt == VT_STORED_OBJECT)) ||
  334. Var.vt == (VT_VECTOR | VT_VARIANT) ||
  335. Var.vt == (VT_VECTOR | VT_CF) ||
  336. Var.vt == (VT_VECTOR | VT_BSTR) ||
  337. S_OK != PropVariantCopy(pVar, &Var) ); // Is valid propvariant ?
  338. PropVariantClear(&Var);
  339. return(TRUE);
  340. }
  341. VOID
  342. CleanStat(ULONG celt, STATPROPSTG *psps)
  343. {
  344. while (celt--)
  345. {
  346. CoTaskMemFree(psps->lpwstrName);
  347. psps++;
  348. }
  349. }
  350. HRESULT
  351. PopulateRGPropVar( CPropVariant rgcpropvar[],
  352. CPropSpec rgcpropspec[] )
  353. {
  354. HRESULT hr = E_FAIL;
  355. int i;
  356. ULONG ulPropIndex = 0;
  357. CLIPDATA clipdataNull, clipdataNonNull;
  358. // Initialize the PropVariants
  359. for( i = 0; i < CPROPERTIES_ALL; i++ )
  360. {
  361. rgcpropvar[i].Clear();
  362. }
  363. // Create a UI1 property
  364. DECLARE_OLESTR(ocsUI1, "UI1 Property" );
  365. rgcpropspec[ulPropIndex] = ocsUI1;
  366. rgcpropvar[ulPropIndex] = (UCHAR) 39; // 0x27
  367. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_UI1 );
  368. ulPropIndex++;
  369. // Create an I2 property
  370. DECLARE_OLESTR(ocsI2, "I2 Property" );
  371. rgcpropspec[ulPropIndex] = ocsI2;
  372. rgcpropvar[ulPropIndex] = (SHORT) -502; // 0xfe0a
  373. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_I2 );
  374. ulPropIndex++;
  375. // Create a UI2 property
  376. DECLARE_OLESTR(ocsUI2, "UI2 Property" );
  377. rgcpropspec[ulPropIndex] = ocsUI2;
  378. rgcpropvar[ulPropIndex] = (USHORT) 502; // 01f6
  379. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_UI2 );
  380. ulPropIndex++;
  381. // Create a BOOL property
  382. DECLARE_OLESTR(ocsBool, "Bool Property" );
  383. rgcpropspec[ulPropIndex] = ocsBool;
  384. rgcpropvar[ulPropIndex].SetBOOL( VARIANT_TRUE ); // 0xFFFF
  385. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_BOOL );
  386. ulPropIndex++;
  387. // Create a I4 property
  388. DECLARE_OLESTR(ocsI4, "I4 Property" );
  389. rgcpropspec[ulPropIndex] = ocsI4;
  390. rgcpropvar[ulPropIndex] = (long) -523; // 0xFFFFFDF5
  391. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_I4 );
  392. ulPropIndex++;
  393. // Create a UI4 property
  394. DECLARE_OLESTR(ocsUI4, "UI4 Property" );
  395. rgcpropspec[ulPropIndex] = ocsUI4;
  396. rgcpropvar[ulPropIndex] = (ULONG) 530; // 0x212
  397. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_UI4 );
  398. ulPropIndex++;
  399. // Create a R4 property
  400. DECLARE_OLESTR(ocsR4, "R4 Property" );
  401. rgcpropspec[ulPropIndex] = ocsR4;
  402. rgcpropvar[ulPropIndex] = (float) 5.37; // 0x40abd70a ?
  403. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_R4 );
  404. ulPropIndex++;
  405. // Create an ERROR property
  406. DECLARE_OLESTR(ocsErr, "ERROR Property" );
  407. rgcpropspec[ulPropIndex] = ocsErr;
  408. // 0x800030002
  409. rgcpropvar[ulPropIndex].SetERROR( STG_E_FILENOTFOUND );
  410. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_ERROR );
  411. ulPropIndex++;
  412. // Create an I8 property
  413. LARGE_INTEGER large_integer;
  414. large_integer.LowPart = 551; // 0x227
  415. large_integer.HighPart = 30; // 0x1E
  416. DECLARE_OLESTR(ocsI8, "I8 Property" );
  417. rgcpropspec[ulPropIndex] = ocsI8;
  418. rgcpropvar[ulPropIndex] = large_integer;
  419. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_I8 );
  420. ulPropIndex++;
  421. // Create a UI8 property
  422. ULARGE_INTEGER ularge_integer;
  423. ularge_integer.LowPart = 561; // 0x231
  424. ularge_integer.HighPart = 30; // 0x1E
  425. DECLARE_OLESTR(ocsUI8, "UI8 Property" );
  426. rgcpropspec[ulPropIndex] = ocsUI8;
  427. rgcpropvar[ulPropIndex] = ularge_integer;
  428. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_UI8 );
  429. ulPropIndex++;
  430. // Create an R8 property
  431. DECLARE_OLESTR( ocsR8, "R8 Property" );
  432. rgcpropspec[ulPropIndex] = ocsR8;
  433. rgcpropvar[ulPropIndex] = (double) 571.36; // 4081dae1:47ae147b
  434. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_R8 );
  435. ulPropIndex++;
  436. // Create a CY property
  437. CY cy;
  438. cy.int64 = 578; // 0x242
  439. DECLARE_OLESTR(ocsCY, "Cy Property" );
  440. rgcpropspec[ulPropIndex] = ocsCY;
  441. rgcpropvar[ulPropIndex] = cy;
  442. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_CY );
  443. ulPropIndex++;
  444. // Create a DATE property
  445. DECLARE_OLESTR(ocsDate, "DATE Property" );
  446. rgcpropspec[ulPropIndex] = ocsDate;
  447. rgcpropvar[ulPropIndex].SetDATE( 587 );
  448. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_DATE );
  449. ulPropIndex++;
  450. // Create a FILETIME property
  451. FILETIME filetime;
  452. filetime.dwLowDateTime = 0x767c0570;
  453. filetime.dwHighDateTime = 0x1bb7ecf;
  454. DECLARE_OLESTR(ocsFT, "FILETIME Property" );
  455. rgcpropspec[ulPropIndex] = ocsFT;
  456. rgcpropvar[ulPropIndex] = filetime;
  457. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_FILETIME );
  458. ulPropIndex++;
  459. // Create a CLSID property
  460. DECLARE_OLESTR(ocsCLSID, "CLSID Property" );
  461. rgcpropspec[ulPropIndex] = ocsCLSID;
  462. // f29f85e0-4ff9-1068-ab91-08002b27b3d9
  463. rgcpropvar[ulPropIndex] = FMTID_SummaryInformation;
  464. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_CLSID );
  465. ulPropIndex++;
  466. // Create a vector of CLSIDs
  467. DECLARE_OLESTR(ocsVectCLSID, "CLSID Vector Property" );
  468. rgcpropspec[ulPropIndex] = ocsVectCLSID;
  469. // f29f85e0-4ff9-1068-ab91-08002b27b3d9
  470. rgcpropvar[ulPropIndex][0] = FMTID_SummaryInformation;
  471. rgcpropvar[ulPropIndex][1] = FMTID_DocSummaryInformation;
  472. rgcpropvar[ulPropIndex][2] = FMTID_UserDefinedProperties;
  473. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_CLSID | VT_VECTOR );
  474. ulPropIndex++;
  475. // Create a BSTR property
  476. DECLARE_OLESTR(ocsBSTR, "BSTR");
  477. DECLARE_OLESTR(ocsBSTRVal, "BSTR Value");
  478. rgcpropspec[ulPropIndex] = ocsBSTR;
  479. rgcpropvar[ulPropIndex].SetBSTR( ocsBSTRVal );
  480. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_BSTR );
  481. ulPropIndex++;
  482. // Create a BSTR Vector property
  483. DECLARE_OLESTR(ocsBSTRVect, "BSTR Vector");
  484. rgcpropspec[ulPropIndex] = ocsBSTRVect;
  485. DECLARE_OLESTR(ocsBSTRVectElt, "# - BSTR Vector Element");
  486. for( i = 0; i < 3; i++ )
  487. {
  488. OLECHAR *olestrElement = ocsBSTRVectElt;
  489. olestrElement[0] = (OLECHAR) i%10 + (OLECHAR)'0';
  490. rgcpropvar[ulPropIndex].SetBSTR( olestrElement, i );
  491. }
  492. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_BSTR | VT_VECTOR) );
  493. ulPropIndex++;
  494. // Create a variant vector BSTR property.
  495. DECLARE_OLESTR(ocsBSTRVariantVect, "BSTR Variant Vector");
  496. DECLARE_OLESTR(ocsBSTRVariantVectElt, "# - Vector Variant Vector");
  497. rgcpropspec[ulPropIndex ] = ocsBSTRVariantVect;
  498. for( i = 0; i < 3; i++ )
  499. {
  500. if( i == 0 )
  501. {
  502. rgcpropvar[ulPropIndex][0] =
  503. (PROPVARIANT*) CPropVariant((long) 0x1234);
  504. }
  505. else
  506. {
  507. CPropVariant cpropvarBSTR;
  508. cpropvarBSTR.SetBSTR( ocsBSTRVariantVectElt );
  509. (cpropvarBSTR.GetBSTR())[0] = (OLECHAR) i%10 + (OLECHAR)'0';
  510. rgcpropvar[ulPropIndex][i] = (PROPVARIANT*) cpropvarBSTR;
  511. }
  512. }
  513. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_VARIANT | VT_VECTOR) );
  514. ulPropIndex++;
  515. // Create an LPSTR property
  516. DECLARE_OLESTR(ocsLPSTRP, "LPSTR Property");
  517. rgcpropspec[ulPropIndex] = ocsLPSTRP;
  518. rgcpropvar[ulPropIndex] = "LPSTR Value";
  519. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_LPSTR );
  520. ulPropIndex++;
  521. // Create some ClipFormat properties
  522. DECLARE_OLESTR(ocsClipName, "ClipFormat property");
  523. rgcpropspec[ ulPropIndex ] = ocsClipName;
  524. DECLARE_WIDESTR(wcsClipData, "Clipboard Data");
  525. rgcpropvar[ ulPropIndex ] = CClipData( wcsClipData );
  526. ASSERT( rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  527. ulPropIndex++;
  528. DECLARE_OLESTR(ocsEmptyClipName,
  529. "Empty ClipFormat property (NULL pointer)");
  530. rgcpropspec[ ulPropIndex ] = ocsEmptyClipName;
  531. clipdataNull.cbSize = 4;
  532. clipdataNull.ulClipFmt = (ULONG) -1; // 0xffff
  533. clipdataNull.pClipData = NULL;
  534. rgcpropvar[ ulPropIndex ] = clipdataNull;
  535. ASSERT( rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  536. ulPropIndex++;
  537. DECLARE_OLESTR(ocsEmptyClipNameNotNull,
  538. "Empty ClipFormat property (non-NULL pointer)");
  539. rgcpropspec[ ulPropIndex ] = ocsEmptyClipNameNotNull;
  540. clipdataNonNull.cbSize = 4;
  541. clipdataNonNull.ulClipFmt = (ULONG) -1; // 0xffff
  542. clipdataNonNull.pClipData = (BYTE*) CoTaskMemAlloc(0);
  543. rgcpropvar[ ulPropIndex ] = clipdataNonNull;
  544. ASSERT( rgcpropvar[ ulPropIndex ].VarType() == VT_CF );
  545. ulPropIndex++;
  546. // Create a vector of ClipFormat properties
  547. CClipData cclipdataEmpty;
  548. cclipdataEmpty.Set( (ULONG) -1, "", 0 );
  549. DECLARE_OLESTR(ocsClipArr, "ClipFormat Array Property");
  550. rgcpropspec[ ulPropIndex ] = ocsClipArr;
  551. DECLARE_OLESTR(ocsElt1, "Clipboard Date element 1");
  552. DECLARE_OLESTR(ocsElt2, "Clipboard Date element 2");
  553. rgcpropvar[ ulPropIndex ][0] = CClipData( ocsElt1 );
  554. rgcpropvar[ ulPropIndex ][1] = cclipdataEmpty;
  555. rgcpropvar[ ulPropIndex ][2] = clipdataNull;
  556. rgcpropvar[ ulPropIndex ][3] = clipdataNonNull;
  557. rgcpropvar[ ulPropIndex ][4] = CClipData( ocsElt2 );
  558. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_CF | VT_VECTOR) );
  559. ASSERT( rgcpropvar[ulPropIndex].Count() == 5 );
  560. ulPropIndex++;
  561. // Create an LPSTR|Vector property (e.g., the DocSumInfo
  562. // Document Parts array).
  563. DECLARE_OLESTR(ocsLPSTRorVect, "LPSTR|Vector property");
  564. rgcpropspec[ ulPropIndex ] = ocsLPSTRorVect;
  565. rgcpropvar[ ulPropIndex ][0] = "LPSTR Element 0";
  566. rgcpropvar[ ulPropIndex ][1] = "LPSTR Element 1";
  567. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_LPSTR | VT_VECTOR) );
  568. ulPropIndex++;
  569. // Create an LPWSTR|Vector property
  570. DECLARE_OLESTR(ocsLPWSTRVect, "LPWSTR|Vector property");
  571. DECLARE_WIDESTR(ocslpwvElt1, "LPWSTR Element 0");
  572. DECLARE_WIDESTR(ocslpwvElt2, "LPWSTR Element 1");
  573. rgcpropspec[ ulPropIndex ] = ocsLPWSTRVect;
  574. rgcpropvar[ ulPropIndex ][0] = ocslpwvElt1;
  575. rgcpropvar[ ulPropIndex ][1] = ocslpwvElt2;
  576. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_LPWSTR | VT_VECTOR) );
  577. ulPropIndex++;
  578. // Create a DocSumInfo HeadingPairs array.
  579. DECLARE_OLESTR(ocsPairArr, "HeadingPair array");
  580. rgcpropspec[ ulPropIndex ] = ocsPairArr;
  581. rgcpropvar[ ulPropIndex ][0] = (PROPVARIANT*) CPropVariant( "Heading 0" );
  582. rgcpropvar[ ulPropIndex ][1] = (PROPVARIANT*) CPropVariant( (long) 1 );
  583. rgcpropvar[ ulPropIndex ][2] = (PROPVARIANT*) CPropVariant( "Heading 1" );
  584. rgcpropvar[ ulPropIndex ][3] = (PROPVARIANT*) CPropVariant( (long) 1 );
  585. ASSERT( rgcpropvar[ulPropIndex].VarType() == (VT_VARIANT | VT_VECTOR) );
  586. ulPropIndex++;
  587. // Create some NULL (but extant) properties
  588. DECLARE_OLESTR(ocsEmptyLPSTR, "Empty LPSTR");
  589. rgcpropspec[ulPropIndex] = ocsEmptyLPSTR;
  590. rgcpropvar[ulPropIndex] = "";
  591. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_LPSTR );
  592. ulPropIndex++;
  593. DECLARE_OLESTR(ocsEmptyLPWSTR, "Empty LPWSTR");
  594. DECLARE_WIDESTR(wcsEmpty, "");
  595. rgcpropspec[ulPropIndex] = ocsEmptyLPWSTR;
  596. rgcpropvar[ulPropIndex] = wcsEmpty;
  597. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_LPWSTR );
  598. ulPropIndex++;
  599. DECLARE_OLESTR(ocsEmptyBLOB, "Empty BLOB");
  600. rgcpropspec[ulPropIndex] = ocsEmptyBLOB;
  601. rgcpropvar[ulPropIndex] = CBlob(0);
  602. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_BLOB );
  603. ulPropIndex++;
  604. DECLARE_OLESTR(ocsEmptyBSTR, "Empty BSTR");
  605. DECLARE_OLESTR(ocsEmpty, "");
  606. rgcpropspec[ulPropIndex] = ocsEmptyBSTR;
  607. rgcpropvar[ulPropIndex].SetBSTR( ocsEmpty );
  608. ASSERT( rgcpropvar[ulPropIndex].VarType() == VT_BSTR );
  609. ulPropIndex++;
  610. // ----
  611. // Exit
  612. // ----
  613. CoTaskMemFree( clipdataNonNull.pClipData );
  614. memset( &clipdataNonNull, 0, sizeof(clipdataNonNull) );
  615. ASSERT( CPROPERTIES_ALL == ulPropIndex );
  616. hr = S_OK;
  617. return(hr);
  618. }
  619. //+---------------------------------------------------------------
  620. //
  621. // Function: test_WriteReadAllProperties
  622. //
  623. // Synopsis: This test simply creates two new property
  624. // sets in a new file (one Ansi and one Unicode),
  625. // writes all the properties in g_rgcpropvarAll,
  626. // reads them back, and verifies that it reads what
  627. // it wrote.
  628. //
  629. // Outputs: None.
  630. //
  631. //+---------------------------------------------------------------
  632. void
  633. test_WriteReadAllProperties(ULONG ulTestOptions )
  634. {
  635. FMTID fmtidAnsi, fmtidUnicode;
  636. TSafeStorage< IStorage > pstg;
  637. TSafeStorage< IPropertySetStorage > ppropsetstg;
  638. TSafeStorage< IPropertyStorage > ppropstgAnsi;
  639. TSafeStorage< IPropertyStorage > ppropstgUnicode;
  640. CPropVariant rgcpropvarAnsi[ CPROPERTIES_ALL ];
  641. CPropVariant rgcpropvarUnicode[ CPROPERTIES_ALL ];
  642. printf( " Simple Write/Read Test\n" );
  643. // -----------------------
  644. // Create the Property Set
  645. // -----------------------
  646. // Generate FMTIDs.
  647. fmtidAnsi = IID_IPropertyStorage;
  648. fmtidUnicode = IID_IPropertySetStorage;
  649. // Generate a filename from the directory name.
  650. DECLARE_OLESTR(ocsFile, "AllProps.stg" );
  651. if (! (ulTestOptions & TEST_INTEROP_R))
  652. {
  653. // Create the Docfile.
  654. printf(" Writing into file ... \n");
  655. Check( S_OK, StgCreateDocfile( ocsFile,
  656. STGM_CREATE |
  657. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  658. 0L,
  659. &pstg ));
  660. // Get the IPropertySetStorage
  661. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage,
  662. (void**)&ppropsetstg ));
  663. // Create a Property Storage
  664. Check( S_OK, ppropsetstg->Create( fmtidAnsi,
  665. &CLSID_NULL,
  666. PROPSETFLAG_DEFAULT,
  667. STGM_READWRITE |
  668. STGM_SHARE_EXCLUSIVE,
  669. &ppropstgAnsi ));
  670. Check( S_OK, ppropsetstg->Create( fmtidUnicode,
  671. &CLSID_NULL,
  672. PROPSETFLAG_ANSI,
  673. STGM_READWRITE |
  674. STGM_SHARE_EXCLUSIVE,
  675. &ppropstgUnicode ));
  676. Check( S_OK, ppropstgAnsi->WriteMultiple( CPROPERTIES_ALL,
  677. (PROPSPEC*)g_rgcpropspecAll,
  678. (PROPVARIANT*)g_rgcpropvarAll,
  679. PID_FIRST_USABLE ));
  680. Check( S_OK, ppropstgUnicode->WriteMultiple( CPROPERTIES_ALL,
  681. (PROPSPEC*)g_rgcpropspecAll,
  682. (PROPVARIANT*)g_rgcpropvarAll,
  683. PID_FIRST_USABLE ));
  684. }
  685. else
  686. {
  687. // open it
  688. printf(" opening file ... \n");
  689. Check(S_OK, StgOpenStorage( ocsFile,
  690. (IStorage*) NULL,
  691. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  692. (SNB) 0,
  693. (DWORD) 0,
  694. &pstg ));
  695. // Get the IPropertySetStorage
  696. Check( S_OK, pstg->QueryInterface( IID_IPropertySetStorage,
  697. (void**)&ppropsetstg ));
  698. // Open the Property Storage
  699. Check(S_OK, ppropsetstg->Open(fmtidUnicode,
  700. STGM_SHARE_EXCLUSIVE |
  701. STGM_DIRECT | STGM_READWRITE,
  702. &ppropstgUnicode));
  703. Check(S_OK, ppropsetstg->Open(fmtidAnsi,
  704. STGM_SHARE_EXCLUSIVE |
  705. STGM_DIRECT | STGM_READWRITE,
  706. &ppropstgAnsi));
  707. }
  708. printf(" Verifying file ... \n");
  709. // either way, read it and make sure it is right
  710. Check( S_OK, ppropstgAnsi->ReadMultiple( CPROPERTIES_ALL,
  711. (PROPSPEC*)g_rgcpropspecAll,
  712. (PROPVARIANT*)rgcpropvarAnsi ));
  713. Check( S_OK, ppropstgUnicode->ReadMultiple( CPROPERTIES_ALL,
  714. (PROPSPEC*)g_rgcpropspecAll,
  715. (PROPVARIANT*)rgcpropvarUnicode ));
  716. // ----------------------
  717. // Compare the properties
  718. // ----------------------
  719. for( int i = 0; i < (int)CPROPERTIES_ALL; i++ )
  720. {
  721. Check( TRUE, rgcpropvarAnsi[i] == g_rgcpropvarAll[i]
  722. &&
  723. rgcpropvarUnicode[i] == g_rgcpropvarAll[i] );
  724. }
  725. } // test_WriteReadProperties
  726. //
  727. // DOCFILE -- run all tests on DocFile
  728. //
  729. // IPropertySetStorage tests
  730. //
  731. void
  732. test_IPropertySetStorage_IUnknown(IStorage *pStorage)
  733. {
  734. printf( " IPropertySetStorage::IUnknown\n" );
  735. // Check ref counting through different interfaces on object
  736. //
  737. // QI to IPropertySetStorage
  738. // QI to IUnknown on IStorage
  739. // QI to IUnknown on IPropertySetStorage
  740. // QI back to IPropertySetStorage from IUnknown
  741. // QI back to IStorage from IPropertySetStorage
  742. //
  743. // Release all.
  744. //
  745. IStorage *pStorage2;
  746. IPropertySetStorage *ppss1, *ppss2, *ppss3;
  747. IUnknown *punk1,*punk2;
  748. Check(S_OK, pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&ppss1));
  749. Check(S_OK, pStorage->QueryInterface(IID_IUnknown, (void **)&punk1));
  750. Check(S_OK, ppss1->QueryInterface(IID_IUnknown, (void **)&punk2));
  751. Check(S_OK, ppss1->QueryInterface(IID_IStorage, (void **)&pStorage2));
  752. Check(S_OK, ppss1->QueryInterface(IID_IPropertySetStorage, (void **)&ppss2));
  753. Check(S_OK, punk1->QueryInterface(IID_IPropertySetStorage, (void **)&ppss3));
  754. ppss1->AddRef();
  755. ppss1->Release();
  756. //pStorage.Release();
  757. ppss1->Release();
  758. punk1->Release();
  759. punk2->Release();
  760. pStorage2->Release();
  761. ppss2->Release();
  762. ppss3->Release();
  763. }
  764. #define INVALID_POINTER ( (void *) 0xFFFFFFFF )
  765. #define VTABLE_MEMBER_FN(pObj,entry) ( (*(ULONG ***)(pObj))[ (entry) ] )
  766. //+---------------------------------------------------------
  767. //
  768. // Template: Alloc2PageVector
  769. //
  770. // Purpose: This function template allocates two pages
  771. // of memory, and then sets a vector pointer
  772. // so that its first element is wholy within
  773. // the first page, and the second element is
  774. // wholy within the second. Then, the protection
  775. // of the second page is set according to the
  776. // caller-provided parameter.
  777. //
  778. //
  779. // Inputs: [TYPE**] ppBase
  780. // Points to the beginning of the two pages.
  781. // [TYPE**] ppVector
  782. // Points to the beginning of the vector of TYPEs.
  783. // [DWORD] dwProtect
  784. // The desired protection on the second page
  785. // (from the PAGE_* enumeration).
  786. // [LPWSTR] lpwstr (optional)
  787. // If not NULL, used to initialize the vector
  788. // elements.
  789. //
  790. // Output: TRUE iff successful.
  791. //
  792. //+---------------------------------------------------------
  793. template< class TYPE > BOOL Alloc2PageVector( TYPE** ppBase,
  794. TYPE** ppVector,
  795. DWORD dwProtect,
  796. TYPE* pInit )
  797. {
  798. DWORD dwOldProtect;
  799. SYSTEM_INFO si;
  800. GetSystemInfo( &si );
  801. *ppBase = (TYPE*) VirtualAlloc( NULL, 2 * si.dwPageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  802. if( NULL == *ppBase )
  803. return( FALSE );
  804. *ppVector = (TYPE*) ( (BYTE*) *ppBase + si.dwPageSize - sizeof(TYPE) );
  805. if( NULL != pInit )
  806. {
  807. memcpy( &((LPWSTR*)*ppVector)[0], pInit, sizeof(TYPE) );
  808. memcpy( &((LPWSTR*)*ppVector)[1], pInit, sizeof(TYPE) );
  809. }
  810. if( !VirtualProtect( (BYTE*) *ppBase + si.dwPageSize, si.dwPageSize, dwProtect, &dwOldProtect ) )
  811. return( FALSE );
  812. return( TRUE );
  813. }
  814. void
  815. test_PropVariantValidation( IStorage *pStg )
  816. {
  817. printf( " PropVariant Validation\n" );
  818. TSafeStorage< IPropertySetStorage > pPSStg( pStg );
  819. TSafeStorage< IPropertyStorage > pPStg;
  820. CPropVariant cpropvar;
  821. CLIPDATA clipdata;
  822. PROPSPEC propspec;
  823. DECLARE_WIDESTR(wszText, "Unicode Text String");
  824. FMTID fmtid;
  825. UuidCreate( &fmtid );
  826. Check(S_OK, pPSStg->Create( fmtid,
  827. NULL,
  828. PROPSETFLAG_DEFAULT,
  829. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  830. &pPStg ));
  831. propspec.ulKind = PRSPEC_PROPID;
  832. propspec.propid = 2;
  833. // -------------------------------
  834. // Test invalid VT_CF Propvariants
  835. // -------------------------------
  836. // NULL clip format.
  837. clipdata.cbSize = 4;
  838. clipdata.ulClipFmt = (ULONG) -1;
  839. clipdata.pClipData = NULL;
  840. cpropvar = clipdata;
  841. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  842. // Too short cbSize.
  843. ((PROPVARIANT*)cpropvar)->pclipdata->cbSize = 3;
  844. Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  845. // Too short pClipData (it should be 1 byte, but the pClipData is NULL).
  846. ((PROPVARIANT*)cpropvar)->pclipdata->cbSize = 5;
  847. Check(STG_E_INVALIDPARAMETER, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  848. }
  849. // Check creation/open/deletion of property sets (check fmtid and predefined names)
  850. // Create a property set
  851. // Try recreate of same
  852. // Try delete
  853. // Close the property set
  854. // Try recreate of same
  855. // Reopen the property set
  856. // Try recreate of same
  857. // Try delete
  858. // Close the property set
  859. // Delete the property set
  860. // Repeat the test once more
  861. void
  862. test_IPropertySetStorage_CreateOpenDelete(IStorage *pStorage)
  863. {
  864. printf( " IPropertySetStorage::Create/Open/Delete\n" );
  865. FMTID fmtid;
  866. PROPSPEC propspec;
  867. UuidCreate(&fmtid);
  868. int i;
  869. for (i=0; i<4; i++)
  870. {
  871. {
  872. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  873. IPropertyStorage *PropStg, *PropStg2;
  874. Check(S_OK, pPropSetStg->Create(fmtid,
  875. NULL,
  876. PROPSETFLAG_DEFAULT,
  877. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  878. &PropStg));
  879. Check(S_OK, pPropSetStg->Create(
  880. fmtid,
  881. NULL,
  882. PROPSETFLAG_DEFAULT,
  883. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  884. &PropStg2));
  885. Check(STG_E_REVERTED, PropStg->Commit(0));
  886. PropStg->Release();
  887. PropStg2->Release();
  888. }
  889. {
  890. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  891. IPropertyStorage *PropStg, *PropStg2;
  892. // use STGM_FAILIFTHERE
  893. Check(STG_E_FILEALREADYEXISTS,
  894. pPropSetStg->Create(fmtid,
  895. NULL,
  896. PROPSETFLAG_DEFAULT,
  897. STGM_SHARE_EXCLUSIVE | STGM_DIRECT |
  898. STGM_READWRITE,
  899. &PropStg));
  900. Check(S_OK,
  901. pPropSetStg->Open(fmtid,
  902. STGM_SHARE_EXCLUSIVE | STGM_DIRECT |
  903. STGM_READWRITE,
  904. &PropStg));
  905. Check(STG_E_ACCESSDENIED,
  906. pPropSetStg->Create(fmtid,
  907. NULL,
  908. PROPSETFLAG_DEFAULT,
  909. STGM_SHARE_EXCLUSIVE | STGM_DIRECT |
  910. STGM_READWRITE,
  911. &PropStg2));
  912. Check(S_OK,
  913. pPropSetStg->Delete(fmtid));
  914. propspec.ulKind = PRSPEC_PROPID;
  915. propspec.propid = 1000;
  916. PROPVARIANT propvar;
  917. propvar.vt = VT_I4;
  918. propvar.lVal = 12345;
  919. Check(STG_E_REVERTED,
  920. PropStg->WriteMultiple(1, &propspec, &propvar,
  921. 2)); // force dirty
  922. PropStg->Release();
  923. }
  924. }
  925. // --------------------------------------------------------
  926. // Test the Create/Delete of the DocumentSummaryInformation
  927. // property set (this requires special code because it
  928. // has two sections).
  929. // --------------------------------------------------------
  930. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  931. TSafeStorage< IPropertyStorage> pPropStg1, pPropStg2;
  932. // Create & Delete a DSI propset with just the first section.
  933. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  934. NULL,
  935. PROPSETFLAG_DEFAULT,
  936. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  937. &pPropStg1));
  938. pPropStg1->Release(); pPropStg1 = NULL;
  939. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  940. // Create & Delete a DSI propset with just the second section
  941. Check(S_OK, pPropSetStg->Create(FMTID_UserDefinedProperties,
  942. NULL,
  943. PROPSETFLAG_DEFAULT,
  944. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  945. &pPropStg1 ));
  946. pPropStg1->Release(); pPropStg1 = NULL;
  947. Check(S_OK, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  948. // Create & Delete a DocumentSummaryInformation propset with both sections.
  949. // If you delete the DSI propset first, it should delete both sections.
  950. // If you delete the UD propset first, the DSI propset should still
  951. // remain. We'll loop twice, trying both combinations.
  952. for( i = 0; i < 2; i++ )
  953. {
  954. // Create the first section, which implicitely creates
  955. // the second section.
  956. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  957. NULL,
  958. PROPSETFLAG_DEFAULT,
  959. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  960. &pPropStg1));
  961. pPropStg1->Release(); pPropStg1 = NULL;
  962. if( i == 0 )
  963. {
  964. Check(S_OK, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  965. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  966. }
  967. else
  968. {
  969. Check(S_OK, pPropSetStg->Delete( FMTID_DocSummaryInformation ));
  970. Check(STG_E_FILENOTFOUND, pPropSetStg->Delete( FMTID_UserDefinedProperties ));
  971. }
  972. } // for( i = 0; i < 2; i++ )
  973. // -------------------------------------
  974. // Test special properties in DocSumInfo
  975. // -------------------------------------
  976. // This verifies that when we Create a DocSumInfo
  977. // property set, and write a Vector or LPSTRs,
  978. // we can read it again. We test this because
  979. // Vectors of LPSTRs are a special case in the DocSumInfo,
  980. // and the Create & Open path are slightly different
  981. // in CPropertySetStream::_LoadHeader.
  982. // Create a new property set.
  983. Check(S_OK, pPropSetStg->Create(FMTID_DocSummaryInformation,
  984. NULL,
  985. PROPSETFLAG_DEFAULT,
  986. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  987. &pPropStg1));
  988. // Create a vector of LPSTRs. Make the strings
  989. // varying lengths to ensure we get plenty of
  990. // opportunity for alignment problems.
  991. CPropVariant cpropvarWrite, cpropvarRead;
  992. cpropvarWrite[3] = "12345678";
  993. cpropvarWrite[2] = "1234567";
  994. cpropvarWrite[1] = "123456";
  995. cpropvarWrite[0] = "12345";
  996. ASSERT( cpropvarWrite.Count() == 4 );
  997. // Write the property
  998. DECLARE_OLESTR(ocsVect, "A Vector of LPSTRs");
  999. propspec.ulKind = PRSPEC_LPWSTR;
  1000. propspec.lpwstr = ocsVect;
  1001. Check(S_OK, pPropStg1->WriteMultiple( 1, &propspec, cpropvarWrite, 2 ));
  1002. // Read the property back.
  1003. Check(S_OK, pPropStg1->ReadMultiple( 1, &propspec, cpropvarRead ));
  1004. // Verify that we read what we wrote.
  1005. for( i = 0; i < (int) cpropvarWrite.Count(); i++ )
  1006. {
  1007. Check(0, strcmp( (LPSTR) cpropvarWrite[i], (LPSTR) cpropvarRead[i] ));
  1008. }
  1009. }
  1010. void
  1011. test_IPropertySetStorage_SummaryInformation(IStorage *pStorage)
  1012. {
  1013. printf( " SummaryInformation\n" );
  1014. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1015. IPropertyStorage *PropStg;
  1016. IStream *pstm;
  1017. Check(S_OK, pPropSetStg->Create(FMTID_SummaryInformation,
  1018. NULL,
  1019. PROPSETFLAG_DEFAULT, // simple, wide
  1020. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  1021. &PropStg));
  1022. PropStg->Release();
  1023. DECLARE_OLESTR(ocsSummary, "\005SummaryInformation");
  1024. Check(S_OK, pStorage->OpenStream(ocsSummary,
  1025. NULL,
  1026. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1027. 0,
  1028. &pstm));
  1029. pstm->Release();
  1030. }
  1031. //
  1032. // Check STGM_FAILIFTHERE and ~STGM_FAILIFTHERE in following cases
  1033. // Check overwriting simple with simple
  1034. void
  1035. test_IPropertySetStorage_FailIfThere(IStorage *pStorage)
  1036. {
  1037. // (Use "fale" instead of "fail" in this printf so the output won't
  1038. // alarm anyone with the word "fail" uncessarily).
  1039. printf( " IPropertySetStorage, FaleIfThere\n" );
  1040. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1041. // Iter 0 1 2 3 4 5 6 7
  1042. // Create simple nonsimple simple nonsimple simple nonsimple simple nonsimple
  1043. // ReCreate simple simple nonsimple nonsimple simple simple nonsimple nonsimple
  1044. // failif failif failif failif overw overw overw overw
  1045. //
  1046. // expected exists exists exists exists ok ok ok ok
  1047. for (int i=0; i<8; i++)
  1048. {
  1049. FMTID fmtid;
  1050. IPropertyStorage *PropStg;
  1051. UuidCreate(&fmtid);
  1052. Check(S_OK, pPropSetStg->Create(fmtid,
  1053. NULL,
  1054. 0,
  1055. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  1056. &PropStg));
  1057. PropStg->Release();
  1058. Check((i&4) == 4 ? S_OK : STG_E_FILEALREADYEXISTS,
  1059. pPropSetStg->Create(fmtid,
  1060. NULL,
  1061. 0,
  1062. ( (i & 4) == 4 ? STGM_CREATE : STGM_FAILIFTHERE) |
  1063. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  1064. &PropStg));
  1065. if (PropStg)
  1066. {
  1067. PropStg->Release();
  1068. }
  1069. }
  1070. }
  1071. void
  1072. test_IPropertySetStorage(IStorage *pStorage)
  1073. {
  1074. // Check ref counting through different interfaces on object
  1075. test_IPropertySetStorage_IUnknown(pStorage);
  1076. test_IPropertySetStorage_CreateOpenDelete(pStorage);
  1077. test_IPropertySetStorage_SummaryInformation(pStorage);
  1078. test_IPropertySetStorage_FailIfThere(pStorage);
  1079. }
  1080. // IEnumSTATPROPSETSTG
  1081. //
  1082. // Check enumeration of property sets
  1083. //
  1084. // Check refcounting and IUnknown
  1085. //
  1086. // Create some property sets, predefined and not, simple and not, one through IStorage
  1087. // Enumerate them and check
  1088. // (check fmtid, grfFlags)
  1089. // (check when asking for more than there is: S_FALSE, S_OK)
  1090. // Delete one
  1091. // Reset the enumerator
  1092. // Enumerate them and check
  1093. // Delete one
  1094. //
  1095. // Reset the enumeratorA
  1096. // Read one from enumeratorA
  1097. // Clone enumerator -> enumeratorB
  1098. // Loop comparing rest of enumerator contents
  1099. //
  1100. // Reset the enumerator
  1101. // Skip all
  1102. // Check none left
  1103. //
  1104. // Reset the enumerator
  1105. // Skip all but one
  1106. // Check one left
  1107. //
  1108. void CheckTime(const FILETIME &ftStart, const FILETIME &ftPropSet)
  1109. {
  1110. FILETIME ftNow;
  1111. Now(&ftNow);
  1112. if (ftPropSet.dwLowDateTime == 0 && ftPropSet.dwHighDateTime == 0)
  1113. {
  1114. return;
  1115. }
  1116. // if ftPropSet < ftStart || ftNow < ftPropSet, error
  1117. ASSERT (!(CompareFileTime(&ftPropSet, &ftStart) == -1 ||
  1118. CompareFileTime(&ftNow, &ftPropSet) == -1));
  1119. }
  1120. void test_IEnumSTATPROPSETSTG(IStorage *pStorage)
  1121. {
  1122. printf( " IEnumSTATPROPSETSTG\n" );
  1123. FMTID afmtid[8];
  1124. CLSID aclsid[8];
  1125. IPropertyStorage *pPropSet;
  1126. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1127. FILETIME ftStart;
  1128. Now(&ftStart);
  1129. pPropSetStg->Delete(FMTID_SummaryInformation);
  1130. for (int i=0; i<5; i++)
  1131. {
  1132. if (i & 4)
  1133. afmtid[i] = FMTID_SummaryInformation;
  1134. else
  1135. UuidCreate(&afmtid[i]);
  1136. UuidCreate(&aclsid[i]);
  1137. Check(S_OK, pPropSetStg->Create(afmtid[i], aclsid+i,
  1138. ((i & 2) ? PROPSETFLAG_ANSI : 0),
  1139. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1140. &pPropSet));
  1141. pPropSet->Release();
  1142. }
  1143. STATPROPSETSTG StatBuffer[6];
  1144. ULONG celt;
  1145. IEnumSTATPROPSETSTG *penum, *penum2;
  1146. Check(S_OK, pPropSetStg->Enum(&penum));
  1147. IUnknown *punk, *punk2;
  1148. IEnumSTATPROPSETSTG *penum3;
  1149. Check(S_OK, penum->QueryInterface(IID_IUnknown, (void**)&punk));
  1150. Check(S_OK, punk->QueryInterface(IID_IEnumSTATPROPSETSTG, (void**)&penum3));
  1151. Check(S_OK, penum->QueryInterface(IID_IEnumSTATPROPSETSTG, (void**)&punk2));
  1152. ASSERT(punk == punk2);
  1153. punk->Release();
  1154. penum3->Release();
  1155. punk2->Release();
  1156. // test S_FALSE
  1157. Check(S_FALSE, penum->Next(6, StatBuffer, &celt));
  1158. ASSERT(celt == 5);
  1159. penum->Reset();
  1160. // test reading half out, then cloning, then comparing
  1161. // rest of enumeration with other clone.
  1162. Check(S_OK, penum->Next(3, StatBuffer, &celt));
  1163. ASSERT(celt == 3);
  1164. celt = 0;
  1165. Check(S_OK, penum->Clone(&penum2));
  1166. Check(S_OK, penum->Next(2, StatBuffer, &celt));
  1167. ASSERT(celt == 2);
  1168. // check the clone
  1169. for (int c=0; c<2; c++)
  1170. {
  1171. STATPROPSETSTG CloneStat;
  1172. Check(S_OK, penum2->Next(1, &CloneStat, NULL));
  1173. Check(TRUE, 0 == memcmp(&CloneStat, StatBuffer+c, sizeof(CloneStat)));
  1174. Check(TRUE, CloneStat.dwOSVersion == PROPSETHDR_OSVERSION_UNKNOWN);
  1175. }
  1176. // check both empty
  1177. celt = 0;
  1178. Check(S_FALSE, penum->Next(1, StatBuffer, &celt));
  1179. ASSERT(celt == 0);
  1180. Check(S_FALSE, penum2->Next(1, StatBuffer, &celt));
  1181. ASSERT(celt == 0);
  1182. penum->Reset();
  1183. //
  1184. // loop deleting one propset at a time
  1185. // enumerate the propsets checking that correct ones appear.
  1186. //
  1187. for (ULONG d = 0; d<5; d++)
  1188. {
  1189. // d is for delete
  1190. BOOL afFound[5];
  1191. Check(S_OK, penum->Next(5-d, StatBuffer, &celt));
  1192. ASSERT(celt == 5-d);
  1193. penum->Reset();
  1194. memset(afFound, 0, sizeof(afFound));
  1195. for (ULONG iPropSet=0; iPropSet<5; iPropSet++)
  1196. {
  1197. ULONG iSearch;
  1198. for (iSearch=0; iSearch<5-d; iSearch++)
  1199. {
  1200. if (0 == memcmp(&StatBuffer[iSearch].fmtid,
  1201. &afmtid[iPropSet],
  1202. sizeof(StatBuffer[0].fmtid)))
  1203. {
  1204. ASSERT (!afFound[iPropSet]);
  1205. afFound[iPropSet] = TRUE;
  1206. break;
  1207. }
  1208. }
  1209. if (iPropSet < d)
  1210. {
  1211. ASSERT(!afFound[iPropSet]);
  1212. }
  1213. if (iSearch == 5-d)
  1214. {
  1215. ASSERT(iPropSet < d);
  1216. continue;
  1217. }
  1218. ASSERT( ( (StatBuffer[iSearch].grfFlags
  1219. & PROPSETFLAG_NONSIMPLE) == 0 ) );
  1220. ASSERT((StatBuffer[iSearch].grfFlags & PROPSETFLAG_ANSI) == 0);
  1221. if (StatBuffer[iSearch].grfFlags & PROPSETFLAG_NONSIMPLE)
  1222. {
  1223. ASSERT(StatBuffer[iSearch].clsid == aclsid[iPropSet]);
  1224. }
  1225. else
  1226. {
  1227. ASSERT(StatBuffer[iSearch].clsid == CLSID_NULL);
  1228. }
  1229. CheckTime(ftStart, StatBuffer[iSearch].mtime);
  1230. CheckTime(ftStart, StatBuffer[iSearch].atime);
  1231. CheckTime(ftStart, StatBuffer[iSearch].ctime);
  1232. }
  1233. Check(S_OK, pPropSetStg->Delete(afmtid[d]));
  1234. Check(S_OK, penum->Reset());
  1235. }
  1236. penum->Release();
  1237. penum2->Release();
  1238. }
  1239. // Creation tests
  1240. //
  1241. // Access flags/Valid parameters/Permissions
  1242. // Check readonly cannot be written -
  1243. // WriteProperties, WritePropertyNames
  1244. void
  1245. test_IPropertyStorage_Access(IStorage *pStorage)
  1246. {
  1247. printf( " IPropertyStorage creation (access) tests\n" );
  1248. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1249. FMTID fmtid;
  1250. UuidCreate(&fmtid);
  1251. // check by name
  1252. IPropertyStorage *pPropStg;
  1253. Check(S_OK, pPropSetStg->Create(fmtid, NULL, 0,
  1254. STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  1255. // QueryInterface tests
  1256. // QI to IPropertyStorage
  1257. // QI to IUnknown on IPropertyStorage
  1258. // QI back to IPropertyStorage from IUnknown
  1259. //
  1260. // Release all.
  1261. IPropertyStorage *pPropStg2,*pPropStg3;
  1262. IUnknown *punk;
  1263. Check(S_OK, pPropStg->QueryInterface(IID_IPropertyStorage,
  1264. (void**)&pPropStg2));
  1265. Check(S_OK, pPropStg->QueryInterface(IID_IUnknown,
  1266. (void**)&punk));
  1267. Check(S_OK, punk->QueryInterface(IID_IPropertyStorage,
  1268. (void**)&pPropStg3));
  1269. pPropStg3->Release();
  1270. pPropStg2->Release();
  1271. punk->Release();
  1272. PROPSPEC ps;
  1273. ps.ulKind = PRSPEC_LPWSTR;
  1274. DECLARE_OLESTR(ocsTestProp, "testprop");
  1275. ps.lpwstr = ocsTestProp;
  1276. PROPVARIANT pv;
  1277. pv.vt = VT_LPWSTR;
  1278. DECLARE_CONST_OLESTR(ocsTestVal, "testval");
  1279. LPOLESTR ocsTest = ocsTestVal;
  1280. DECLARE_WIDESTR(wcsTestVal, "testval");
  1281. pv.pwszVal = wcsTestVal;
  1282. Check(S_OK, pPropStg->WriteMultiple(1, &ps, &pv, 2));
  1283. pPropStg->Release();
  1284. Check(S_OK, pPropSetStg->Open(fmtid, STGM_SHARE_EXCLUSIVE | STGM_READ,
  1285. &pPropStg));
  1286. Check(STG_E_ACCESSDENIED, pPropStg->WriteMultiple(1, &ps, &pv, 2));
  1287. Check(STG_E_ACCESSDENIED, pPropStg->DeleteMultiple(1, &ps));
  1288. PROPID propid=3;
  1289. Check(STG_E_ACCESSDENIED, pPropStg->WritePropertyNames(1, &propid,
  1290. &ocsTestVal));
  1291. Check(STG_E_ACCESSDENIED, pPropStg->DeletePropertyNames(1, &propid));
  1292. FILETIME ft;
  1293. Check(STG_E_ACCESSDENIED, pPropStg->SetTimes(&ft, &ft, &ft));
  1294. CLSID clsid;
  1295. Check(STG_E_ACCESSDENIED, pPropStg->SetClass(clsid));
  1296. pPropStg->Release();
  1297. }
  1298. // Creation tests
  1299. // Check VT_STREAM etc not usable with simple.
  1300. void
  1301. test_IPropertyStorage_Create(IStorage *pStorage)
  1302. {
  1303. printf( " IPropertyStorage creation tests\n" );
  1304. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1305. FMTID fmtid;
  1306. UuidCreate(&fmtid);
  1307. // check by name
  1308. IPropertyStorage *pPropStg;
  1309. Check(S_OK, pPropSetStg->Create(fmtid, NULL, 0 /* simple */,
  1310. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, &pPropStg));
  1311. PROPSPEC ps;
  1312. ps.ulKind = PRSPEC_PROPID;
  1313. ps.propid = 2;
  1314. PROPVARIANT pv;
  1315. pv.vt = VT_STREAM;
  1316. pv.pStream = NULL;
  1317. // the ref impl. does not recognize VT_STREAM, and will thus
  1318. // treat it as a invalid type.
  1319. Check(STG_E_INVALIDPARAMETER,
  1320. pPropStg->WriteMultiple(1, &ps, &pv, 2000));
  1321. //
  1322. pPropStg->Release();
  1323. }
  1324. void
  1325. CheckStat( IPropertyStorage *pPropSet, REFFMTID fmtid,
  1326. REFCLSID clsid, ULONG PropSetFlag,
  1327. const FILETIME & ftStart, DWORD dwOSVersion )
  1328. {
  1329. STATPROPSETSTG StatPropSetStg;
  1330. Check(S_OK, pPropSet->Stat(&StatPropSetStg));
  1331. Check(TRUE, StatPropSetStg.fmtid == fmtid);
  1332. Check(TRUE, StatPropSetStg.clsid == clsid);
  1333. Check(TRUE, StatPropSetStg.grfFlags == PropSetFlag);
  1334. Check(TRUE, StatPropSetStg.dwOSVersion == dwOSVersion);
  1335. CheckTime(ftStart, StatPropSetStg.mtime);
  1336. CheckTime(ftStart, StatPropSetStg.ctime);
  1337. CheckTime(ftStart, StatPropSetStg.atime);
  1338. }
  1339. //
  1340. //
  1341. // Stat (Create four combinations)
  1342. // Check ansi/wide fflag
  1343. // Also test clsid on propset
  1344. void test_IPropertyStorage_Stat(IStorage *pStorage)
  1345. {
  1346. printf( " IPropertyStorage::Stat\n" );
  1347. DWORD dwOSVersion = 0;
  1348. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1349. FMTID fmtid;
  1350. UuidCreate(&fmtid);
  1351. IPropertyStorage *pPropSet;
  1352. STATPROPSETSTG StatPropSetStg;
  1353. // Calculate the OS Version
  1354. #ifdef _MAC_
  1355. #error Do not know how to calculate the OS Version for the macintosh.
  1356. #endif
  1357. dwOSVersion = MAKELONG( 0x0100, OSKIND_REF );
  1358. for (ULONG i=0; i<4; i++)
  1359. {
  1360. FILETIME ftStart;
  1361. DfGetTOD(&ftStart);
  1362. memset(&StatPropSetStg, 0, sizeof(StatPropSetStg));
  1363. CLSID clsid;
  1364. UuidCreate(&clsid);
  1365. Check(S_OK, pPropSetStg->Create(fmtid, &clsid,
  1366. ((i & 2) ? PROPSETFLAG_ANSI : 0),
  1367. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1368. &pPropSet));
  1369. CheckStat(pPropSet, fmtid, clsid,
  1370. ((i & 2) ? PROPSETFLAG_ANSI : 0), ftStart, dwOSVersion );
  1371. pPropSet->Release();
  1372. Check(S_OK, pPropSetStg->Open(fmtid,
  1373. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1374. &pPropSet));
  1375. CheckStat(pPropSet, fmtid, clsid,
  1376. ((i & 2) ? PROPSETFLAG_ANSI : 0), ftStart, dwOSVersion );
  1377. pPropSet->Release();
  1378. Check(S_OK, pPropSetStg->Open(fmtid,
  1379. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1380. &pPropSet));
  1381. CheckStat(pPropSet, fmtid, clsid,
  1382. ((i & 2) ? PROPSETFLAG_ANSI : 0), ftStart, dwOSVersion );
  1383. pPropSet->Release();
  1384. }
  1385. }
  1386. //
  1387. // test using IStorage::Commit to commit the changes in a nested
  1388. // property set
  1389. //
  1390. void
  1391. test_IPropertyStorage_Commit(IStorage *pStorage)
  1392. {
  1393. printf( " IPropertyStorage::Commit\n" );
  1394. // create another level of storage
  1395. SCODE sc;
  1396. // 8 scenarios: simple * direct * (release only + commit storage + commit
  1397. // propset)
  1398. // note: some scenarios might repeat since there is no
  1399. // non-simple/transacted cases
  1400. for (int i=0; i<32; i++)
  1401. {
  1402. CTempStorage pDeeper(Create, pStorage, GetNextTest(),
  1403. STGM_DIRECT);
  1404. TSafeStorage< IPropertySetStorage > pPropSetStg(pDeeper);
  1405. FMTID fmtid;
  1406. UuidCreate(&fmtid);
  1407. IPropertyStorage *pPropSet;
  1408. if (S_OK != (sc = pPropSetStg->Create(
  1409. fmtid, NULL,
  1410. PROPSETFLAG_DEFAULT,
  1411. STGM_SHARE_EXCLUSIVE | STGM_READWRITE |
  1412. STGM_DIRECT,
  1413. &pPropSet)))
  1414. {
  1415. Check(S_OK, sc);
  1416. }
  1417. PROPSPEC ps;
  1418. ps.ulKind = PRSPEC_PROPID;
  1419. ps.propid = 100;
  1420. PROPVARIANT pv;
  1421. pv.vt = VT_I4;
  1422. pv.lVal = 1234;
  1423. Check(S_OK, pPropSet->WriteMultiple(1, &ps, &pv, 1000));
  1424. PropVariantClear(&pv);
  1425. Check(S_OK, pPropSet->ReadMultiple(1, &ps, &pv));
  1426. ASSERT(pv.vt==VT_I4);
  1427. ASSERT(pv.lVal == 1234);
  1428. pv.lVal = 2345; // no size changes
  1429. Check(S_OK, pPropSet->WriteMultiple(1, &ps, &pv, 1000));
  1430. if (i & 4)
  1431. Check(S_OK, pPropSet->Commit(0));
  1432. if (i & 2)
  1433. Check(S_OK, pStorage->Commit(0));
  1434. Check(0, pPropSet->Release()); // implicit commit if i&2 is false
  1435. if (S_OK == pPropSetStg->Open(fmtid, STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1436. &pPropSet))
  1437. {
  1438. PropVariantClear(&pv);
  1439. Check( S_OK, pPropSet->ReadMultiple(1, &ps, &pv));
  1440. ASSERT(pv.vt == VT_I4);
  1441. ASSERT(pv.lVal == 2345);
  1442. pPropSet->Release();
  1443. }
  1444. }
  1445. }
  1446. void
  1447. test_IPropertyStorage_WriteMultiple(IStorage *pStorage)
  1448. {
  1449. test_IPropertyStorage_Commit(pStorage);
  1450. }
  1451. // this serves as a test for WritePropertyNames, ReadPropertyNames, DeletePropertyNames
  1452. // DeleteMultiple, PropVariantCopy, FreePropVariantArray.
  1453. void
  1454. test_IPropertyStorage_DeleteMultiple(IStorage *pStorage)
  1455. {
  1456. printf( " IPropertyStorage::DeleteMultiple\n" );
  1457. TSafeStorage< IPropertySetStorage > pPropSetStg(pStorage);
  1458. FMTID fmtid;
  1459. UuidCreate(&fmtid);
  1460. IPropertyStorage *pPropSet;
  1461. int PropId = 3;
  1462. UuidCreate(&fmtid);
  1463. Check(S_OK, pPropSetStg->Create(
  1464. fmtid,
  1465. NULL, PROPSETFLAG_DEFAULT,
  1466. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  1467. &pPropSet));
  1468. // create and delete each type.
  1469. PROPVARIANT *pVar;
  1470. for (int AtOnce=1; AtOnce <3; AtOnce++)
  1471. {
  1472. CGenProps gp;
  1473. int Actual;
  1474. while (pVar = gp.GetNext(AtOnce, &Actual, FALSE, TRUE))
  1475. {
  1476. PROPSPEC ps[3];
  1477. PROPID rgpropid[3];
  1478. LPOLESTR rglpostrName[3];
  1479. OLECHAR aosz[3][16];
  1480. char pchTemp [16];
  1481. for (int s=0; s<3; s++)
  1482. {
  1483. sprintf(pchTemp, "prop%d", PropId );
  1484. STOT(pchTemp, aosz[s], strlen(pchTemp)+1);
  1485. rgpropid[s] = PropId++;
  1486. rglpostrName[s] = &aosz[s][0];
  1487. ps[s].ulKind = PRSPEC_LPWSTR;
  1488. ps[s].lpwstr = &aosz[s][0];
  1489. }
  1490. for (int l=1; l<Actual; l++)
  1491. {
  1492. PROPVARIANT VarRead[3];
  1493. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  1494. Check(S_OK, pPropSet->
  1495. WritePropertyNames(l, rgpropid, rglpostrName));
  1496. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  1497. Check(S_OK, pPropSet->WriteMultiple(l, ps, pVar, 1000));
  1498. Check(S_OK, pPropSet->ReadMultiple(l, ps, VarRead));
  1499. Check(S_OK, FreePropVariantArray(l, VarRead));
  1500. Check(S_OK, pPropSet->DeleteMultiple(l, ps));
  1501. Check(S_FALSE, pPropSet->ReadMultiple(l, ps, VarRead));
  1502. Check(S_OK, FreePropVariantArray(l, VarRead));
  1503. LPOLESTR rglpostrNameCheck[3];
  1504. Check(S_OK, pPropSet->
  1505. ReadPropertyNames(l, rgpropid, rglpostrNameCheck));
  1506. for (int c=0; c<l; c++)
  1507. {
  1508. ASSERT(ocscmp(rglpostrNameCheck[c], rglpostrName[c])==0);
  1509. CoTaskMemFree(rglpostrNameCheck[c]);
  1510. }
  1511. Check(S_OK, pPropSet->DeletePropertyNames(l, rgpropid));
  1512. Check(S_FALSE, pPropSet->ReadPropertyNames(l, rgpropid,
  1513. rglpostrNameCheck));
  1514. }
  1515. FreePropVariantArray(Actual, pVar);
  1516. delete pVar;
  1517. }
  1518. }
  1519. pPropSet->Release();
  1520. }
  1521. void
  1522. test_IPropertyStorage(IStorage *pStorage)
  1523. {
  1524. test_IPropertyStorage_Access(pStorage);
  1525. test_IPropertyStorage_Create(pStorage);
  1526. test_IPropertyStorage_Stat(pStorage);
  1527. test_IPropertyStorage_WriteMultiple(pStorage);
  1528. test_IPropertyStorage_DeleteMultiple(pStorage);
  1529. }
  1530. //
  1531. // Word6.0 summary information
  1532. // Open
  1533. // Read fields
  1534. // Stat
  1535. //
  1536. #define W6TEST "w6test.doc"
  1537. void test_Word6(IStorage *pStorage)
  1538. {
  1539. printf( " Word 6.0 compatibility test\n" );
  1540. extern unsigned char g_achTestDoc[];
  1541. extern unsigned g_cbTestDoc;
  1542. OLECHAR ocsTempFile[MAX_PATH+1];
  1543. FILE *f = fopen(W6TEST, "w+b");
  1544. int nWritten = fwrite(g_achTestDoc, 1, g_cbTestDoc, f);
  1545. ASSERT(nWritten == (int)g_cbTestDoc);
  1546. fclose(f);
  1547. STOT(W6TEST, ocsTempFile, strlen(W6TEST)+1);
  1548. IStorage *pStg;
  1549. Check(S_OK, StgOpenStorage(ocsTempFile,
  1550. (IStorage*)NULL,
  1551. (DWORD) STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1552. 0,
  1553. 0,
  1554. &pStg));
  1555. TSafeStorage< IPropertySetStorage > pPropSetStg(pStg);
  1556. IPropertyStorage *pPropStg;
  1557. Check(S_OK, pPropSetStg->Open(FMTID_SummaryInformation,
  1558. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READ,
  1559. &pPropStg));
  1560. #define WORDPROPS 18
  1561. static struct tagWordTest {
  1562. VARENUM vt;
  1563. void *pv;
  1564. } avt[WORDPROPS] = {
  1565. VT_LPSTR, "Title of the document.", // PID_TITLE
  1566. VT_LPSTR, "Subject of the document.", // PID_SUBJECT
  1567. VT_LPSTR, "Author of the document.", // PID_AUTHOR
  1568. VT_LPSTR, "Keywords of the document.", // PID_KEYWORDS
  1569. VT_LPSTR, "Comments of the document.", // PID_COMMENTS
  1570. VT_LPSTR, "Normal.dot", // PID_TEMPLATE -- Normal.dot
  1571. VT_LPSTR, "Bill Morel", // PID_LASTAUTHOR --
  1572. VT_LPSTR, "3", // PID_REVNUMBER -- '3'
  1573. VT_EMPTY, 0, // PID_EDITTIME -- 3 Minutes FILETIME
  1574. VT_EMPTY, 0, // PID_LASTPRINTED -- 04/07/95 12:04 FILETIME
  1575. VT_EMPTY, 0, // PID_CREATE_DTM
  1576. VT_EMPTY, 0, // PID_LASTSAVE_DTM
  1577. VT_I4, (void*) 1, // PID_PAGECOUNT
  1578. VT_I4, (void*) 7, // PID_WORDCOUNT
  1579. VT_I4, (void*) 65, // PID_CHARCOUNT
  1580. VT_EMPTY, 0, // PID_THUMBNAIL
  1581. VT_LPSTR, "Microsoft Word 6.0", // PID_APPNAME
  1582. VT_I4, 0 }; // PID_SECURITY
  1583. PROPSPEC propspec[WORDPROPS+2];
  1584. int i;
  1585. for (i=2; i<WORDPROPS+2; i++)
  1586. {
  1587. propspec[i].ulKind = PRSPEC_PROPID;
  1588. propspec[i].propid = (PROPID)i;
  1589. }
  1590. PROPVARIANT propvar[WORDPROPS+2];
  1591. Check(S_OK, pPropStg->ReadMultiple(WORDPROPS, propspec+2, propvar+2));
  1592. for (i=2; i<WORDPROPS+2; i++)
  1593. {
  1594. if ( propvar[i].vt != avt[i-2].vt )
  1595. {
  1596. printf( " PROPTEST: 0x%x retrieved type 0x%x, expected type 0x%x\n",
  1597. i, propvar[i].vt, avt[i-2].vt );
  1598. ASSERT(propvar[i].vt == avt[i-2].vt);
  1599. }
  1600. switch (propvar[i].vt)
  1601. {
  1602. case VT_LPSTR:
  1603. ASSERT(strcmp(propvar[i].pszVal, (char*)avt[i-2].pv)==0);
  1604. break;
  1605. case VT_I4:
  1606. ASSERT(propvar[i].lVal == (int)avt[i-2].pv);
  1607. break;
  1608. }
  1609. }
  1610. FreePropVariantArray( WORDPROPS, propvar+2 );
  1611. pPropStg->Release();
  1612. pStg->Release();
  1613. //_unlink("w6test");
  1614. }
  1615. BOOL
  1616. IsEqualSTATPROPSTG(const STATPROPSTG *p1, const STATPROPSTG *p2)
  1617. {
  1618. BOOL f1 = p1->propid == p2->propid;
  1619. BOOL f2 = p1->vt == p2->vt;
  1620. BOOL f3 = (p1->lpwstrName == NULL && p2->lpwstrName == NULL) ||
  1621. ((p1->lpwstrName != NULL && p2->lpwstrName != NULL) &&
  1622. ocscmp(p1->lpwstrName, p2->lpwstrName) == 0);
  1623. return(f1 && f2 && f3);
  1624. }
  1625. void
  1626. test_IEnumSTATPROPSTG(IStorage *pstgTemp)
  1627. {
  1628. printf( " IEnumSTATPROPSTG\n" );
  1629. PROPID apropid[8];
  1630. LPOLESTR alpostrName[8];
  1631. OLECHAR aosz[8][32];
  1632. PROPID PropId=2;
  1633. PROPSPEC ps[8];
  1634. char pchTemp[32];
  1635. FMTID fmtid;
  1636. IPropertyStorage *pPropStg;
  1637. TSafeStorage< IPropertySetStorage > pPropSetStg(pstgTemp);
  1638. UuidCreate(&fmtid);
  1639. for (int setup=0; setup<8; setup++)
  1640. {
  1641. alpostrName[setup] = &aosz[setup][0];
  1642. }
  1643. CGenProps gp;
  1644. // simple/simple, ansi/wide, named/not named
  1645. for (int outer=0; outer<8; outer++)
  1646. {
  1647. Check(S_OK, pPropSetStg->Create(fmtid, NULL,
  1648. ((outer&2) ? PROPSETFLAG_ANSI : 0),
  1649. STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1650. &pPropStg));
  1651. for (int i=0; i<CPROPERTIES; i++)
  1652. {
  1653. apropid[i] = PropId++;
  1654. if (outer & 1)
  1655. {
  1656. ps[i].ulKind = PRSPEC_LPWSTR;
  1657. sprintf(pchTemp, "prop%d\0", apropid[i]);
  1658. STOT(pchTemp, aosz[i], strlen(pchTemp)+1);
  1659. ps[i].lpwstr = aosz[i];
  1660. }
  1661. else
  1662. {
  1663. ps[i].ulKind = PRSPEC_PROPID;
  1664. ps[i].propid = apropid[i];
  1665. }
  1666. }
  1667. if (outer & 1)
  1668. {
  1669. Check(S_OK, pPropStg->WritePropertyNames(CPROPERTIES, apropid, alpostrName));
  1670. }
  1671. PROPVARIANT *pVar = gp.GetNext(CPROPERTIES, NULL, TRUE, TRUE);
  1672. ASSERT(pVar != NULL);
  1673. Check(S_OK, pPropStg->WriteMultiple(CPROPERTIES, ps, pVar, 1000));
  1674. FreePropVariantArray(CPROPERTIES, pVar);
  1675. delete pVar;
  1676. // Allocate enough STATPROPSTGs for one more than the actual properties
  1677. // in the set.
  1678. STATPROPSTG StatBuffer[CPROPERTIES+1];
  1679. ULONG celt;
  1680. IEnumSTATPROPSTG *penum, *penum2;
  1681. Check(S_OK, pPropStg->Enum(&penum));
  1682. IUnknown *punk, *punk2;
  1683. IEnumSTATPROPSTG *penum3;
  1684. Check(S_OK, penum->QueryInterface(IID_IUnknown, (void**)&punk));
  1685. Check(S_OK, punk->QueryInterface(IID_IEnumSTATPROPSTG, (void**)&penum3));
  1686. Check(S_OK, penum->QueryInterface(IID_IEnumSTATPROPSTG, (void**)&punk2));
  1687. ASSERT(punk == punk2);
  1688. punk->Release();
  1689. penum3->Release();
  1690. punk2->Release();
  1691. // test S_FALSE
  1692. Check(S_FALSE, penum->Next( CPROPERTIES+1, StatBuffer, &celt));
  1693. ASSERT(celt == CPROPERTIES);
  1694. CleanStat(celt, StatBuffer);
  1695. penum->Reset();
  1696. // test reading half out, then cloning, then comparing
  1697. // rest of enumeration with other clone.
  1698. Check(S_OK, penum->Next(CPROPERTIES/2, StatBuffer, &celt));
  1699. ASSERT(celt == CPROPERTIES/2);
  1700. CleanStat(celt, StatBuffer);
  1701. celt = 0;
  1702. Check(S_OK, penum->Clone(&penum2));
  1703. Check(S_OK, penum->Next(CPROPERTIES - CPROPERTIES/2, StatBuffer, &celt));
  1704. ASSERT(celt == CPROPERTIES - CPROPERTIES/2);
  1705. // check the clone
  1706. for (int c=0; c<CPROPERTIES - CPROPERTIES/2; c++)
  1707. {
  1708. STATPROPSTG CloneStat;
  1709. Check(S_OK, penum2->Next(1, &CloneStat, NULL));
  1710. ASSERT(IsEqualSTATPROPSTG(&CloneStat, StatBuffer+c));
  1711. CleanStat(1, &CloneStat);
  1712. }
  1713. CleanStat(celt, StatBuffer);
  1714. // check both empty
  1715. celt = 0;
  1716. Check(S_FALSE, penum->Next(1, StatBuffer, &celt));
  1717. ASSERT(celt == 0);
  1718. Check(S_FALSE, penum2->Next(1, StatBuffer, &celt));
  1719. ASSERT(celt == 0);
  1720. penum->Reset();
  1721. //
  1722. // loop deleting one property at a time
  1723. // enumerate the propertys checking that correct ones appear.
  1724. //
  1725. for (ULONG d = 0; d<CPROPERTIES; d++)
  1726. {
  1727. // d is for delete
  1728. BOOL afFound[CPROPERTIES];
  1729. ULONG cTotal = 0;
  1730. Check(S_OK, penum->Next(CPROPERTIES-d, StatBuffer, &celt));
  1731. ASSERT(celt == CPROPERTIES-d);
  1732. penum->Reset();
  1733. memset(afFound, 0, sizeof(afFound));
  1734. for (ULONG iProperty=0; iProperty<CPROPERTIES; iProperty++)
  1735. {
  1736. // Search the StatBuffer for this property.
  1737. for (ULONG iSearch=0; iSearch<CPROPERTIES-d; iSearch++)
  1738. {
  1739. // Compare this entry in the StatBuffer to the property for which we're searching.
  1740. // Use the lpstrName or propid, whichever is appropriate for this pass (indicated
  1741. // by 'outer').
  1742. if ( ( (outer & 1) == 1 && 0 == ocscmp(StatBuffer[iSearch].lpwstrName, ps[iProperty].lpwstr) )
  1743. ||
  1744. ( (outer & 1) == 0 && StatBuffer[iSearch].propid == apropid[iProperty] )
  1745. )
  1746. {
  1747. ASSERT (!afFound[iSearch]);
  1748. afFound[iSearch] = TRUE;
  1749. cTotal++;
  1750. break;
  1751. }
  1752. }
  1753. }
  1754. CleanStat(celt, StatBuffer);
  1755. ASSERT(cTotal == CPROPERTIES-d);
  1756. Check(S_OK, pPropStg->DeleteMultiple(1, ps+d));
  1757. Check(S_OK, penum->Reset());
  1758. }
  1759. penum->Release();
  1760. penum2->Release();
  1761. pPropStg->Release();
  1762. }
  1763. }
  1764. void
  1765. test_MaxPropertyName(IStorage *pstgTemp)
  1766. {
  1767. printf( " Max Property Name length\n" );
  1768. // ----------
  1769. // Initialize
  1770. // ----------
  1771. CPropVariant cpropvar;
  1772. // Create a new storage, because we're going to create
  1773. // well-known property sets, and this way we can be sure
  1774. // that they don't already exist.
  1775. TSafeStorage< IStorage > pstg;
  1776. DECLARE_OLESTR(ocsMaxProp, "MaxPropNameTest");
  1777. Check(S_OK, pstgTemp->CreateStorage( ocsMaxProp,
  1778. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1779. 0L, 0L,
  1780. &pstg ));
  1781. // Generate a new Format ID.
  1782. FMTID fmtid;
  1783. UuidCreate(&fmtid);
  1784. // Get a IPropertySetStorage from the IStorage.
  1785. TSafeStorage< IPropertySetStorage > pPropSetStg(pstg);
  1786. TSafeStorage< IPropertyStorage > pPropStg;
  1787. // ----------------------------------
  1788. // Test the non-SumInfo property set.
  1789. // ----------------------------------
  1790. // Create a new PropertyStorage.
  1791. Check(S_OK, pPropSetStg->Create(fmtid,
  1792. NULL,
  1793. PROPSETFLAG_DEFAULT,
  1794. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  1795. &pPropStg));
  1796. // Generate a property name which is max+1 characters.
  1797. OLECHAR *poszPropertyName;
  1798. poszPropertyName = (OLECHAR*)
  1799. CoTaskMemAlloc( (CCH_MAXPROPNAMESZ+1) * sizeof(OLECHAR) );
  1800. Check(TRUE, poszPropertyName != NULL );
  1801. for( ULONG ulIndex = 0; ulIndex < CCH_MAXPROPNAMESZ; ulIndex++ )
  1802. poszPropertyName[ ulIndex ] = (OLECHAR)'a' + (OLECHAR) ( ulIndex % 26 );
  1803. poszPropertyName[ CCH_MAXPROPNAMESZ ] = (OLECHAR)0; // terminating null
  1804. // Write out a property with this max+1 name.
  1805. PROPSPEC propspec;
  1806. propspec.ulKind = PRSPEC_LPWSTR;
  1807. propspec.lpwstr = poszPropertyName;
  1808. cpropvar = (long) 0x1234;
  1809. Check(STG_E_INVALIDPARAMETER, pPropStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1810. // Write out a property with a max-character name (we create a max-
  1811. // char name by terminating the previously-used string one character
  1812. // earlier).
  1813. poszPropertyName[ CWC_MAXPROPNAME ] = 0;
  1814. Check(S_OK, pPropStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1815. // Write out a property with a minimum-character name.
  1816. DECLARE_OLESTR(ocsX, "X");
  1817. propspec.lpwstr = ocsX;
  1818. Check(S_OK, pPropStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1819. // Write out a property with a below-minimum-character name.
  1820. DECLARE_OLESTR(ocsEmpty, "");
  1821. propspec.lpwstr = ocsEmpty;
  1822. Check(STG_E_INVALIDPARAMETER,
  1823. pPropStg->WriteMultiple( 1, &propspec,
  1824. cpropvar,
  1825. PID_FIRST_USABLE));
  1826. CoTaskMemFree( poszPropertyName );
  1827. }
  1828. #define CODEPAGE_TEST_NAMED_PROPERTY "Named Property"
  1829. #define CODEPAGE_TEST_UNNAMED_BSTR_PROPID 3
  1830. #define CODEPAGE_TEST_UNNAMED_I4_PROPID 4
  1831. #define CODEPAGE_TEST_VBSTR_PROPID 7
  1832. #define CODEPAGE_TEST_VPROPVAR_BSTR_PROPID 9
  1833. void
  1834. CreateCodePageTestFile( LPOLESTR poszFileName,
  1835. IStorage **ppStg,
  1836. BOOL fUseUnicode)
  1837. {
  1838. ASSERT( poszFileName != NULL );
  1839. // --------------
  1840. // Initialization
  1841. // --------------
  1842. TSafeStorage< IPropertySetStorage > pPSStg;
  1843. TSafeStorage< IPropertyStorage > pPStg;
  1844. PROPSPEC propspec;
  1845. CPropVariant cpropvar;
  1846. *ppStg = NULL;
  1847. OLECHAR poszActualFile[MAX_PATH];
  1848. ocscpy(poszActualFile, poszFileName);
  1849. // assume the path name has enough space, change the last character
  1850. // of the filename
  1851. int len = ocslen(poszActualFile);
  1852. if (!fUseUnicode)
  1853. {
  1854. poszActualFile[len]='a';
  1855. poszActualFile[len+1]=0;
  1856. }
  1857. else
  1858. {
  1859. poszActualFile[len]='w';
  1860. poszActualFile[len+1]=0;
  1861. }
  1862. Check(S_OK, StgCreateDocfile( poszActualFile,
  1863. STGM_CREATE | STGM_READWRITE |
  1864. STGM_SHARE_EXCLUSIVE,
  1865. 0,
  1866. ppStg ));
  1867. // Get an IPropertySetStorage
  1868. Check(S_OK, (*ppStg)->QueryInterface( IID_IPropertySetStorage, (void**)&pPSStg ));
  1869. // Create an IPropertyStorage (ANSI or UNICODE)
  1870. DWORD psFlag= (fUseUnicode) ? 0 : PROPSETFLAG_ANSI ;
  1871. Check(S_OK, pPSStg->Create( FMTID_NULL,
  1872. NULL,
  1873. psFlag,
  1874. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1875. &pPStg ));
  1876. // ----------------------
  1877. // Write a named property
  1878. // ----------------------
  1879. // Write a named I4 property
  1880. propspec.ulKind = PRSPEC_LPWSTR;
  1881. DECLARE_OLESTR(ocsNamed, CODEPAGE_TEST_NAMED_PROPERTY);
  1882. propspec.lpwstr = ocsNamed;
  1883. cpropvar = (LONG) 0x12345678;
  1884. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1885. // --------------------------
  1886. // Write singleton properties
  1887. // --------------------------
  1888. // Write an un-named BSTR.
  1889. propspec.ulKind = PRSPEC_PROPID;
  1890. propspec.propid = CODEPAGE_TEST_UNNAMED_BSTR_PROPID;
  1891. DECLARE_OLESTR(ocsBSTR, "BSTR Property");
  1892. cpropvar.SetBSTR( ocsBSTR );
  1893. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1894. // Write an un-named I4
  1895. propspec.ulKind = PRSPEC_PROPID;
  1896. propspec.propid = CODEPAGE_TEST_UNNAMED_I4_PROPID;
  1897. cpropvar = (LONG) 0x76543210;
  1898. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1899. // -----------------------
  1900. // Write vector properties
  1901. // -----------------------
  1902. // Write a vector of BSTRs.
  1903. propspec.ulKind = PRSPEC_PROPID;
  1904. propspec.propid = CODEPAGE_TEST_VBSTR_PROPID;
  1905. DECLARE_OLESTR(ocsElt0, "BSTR Element 0");
  1906. DECLARE_OLESTR(ocsElt1, "BSTR Element 1");
  1907. cpropvar.SetBSTR( ocsElt1, 1 );
  1908. cpropvar.SetBSTR( ocsElt0, 0 );
  1909. ASSERT( (VT_VECTOR | VT_BSTR) == cpropvar.VarType() );
  1910. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1911. // -------------------------------
  1912. // Write Variant Vector Properties
  1913. // -------------------------------
  1914. // Write a variant vector that has a BSTR
  1915. propspec.ulKind = PRSPEC_PROPID;
  1916. propspec.propid = CODEPAGE_TEST_VPROPVAR_BSTR_PROPID;
  1917. CPropVariant cpropvarT;
  1918. DECLARE_OLESTR(ocsPropVect, "PropVar Vector BSTR");
  1919. cpropvarT.SetBSTR( ocsPropVect );
  1920. cpropvar[1] = (LPPROPVARIANT) cpropvarT;
  1921. cpropvar[0] = (LPPROPVARIANT) CPropVariant((long) 44);
  1922. ASSERT( (VT_VARIANT | VT_VECTOR) == cpropvar.VarType() );
  1923. Check(S_OK, pPStg->WriteMultiple( 1, &propspec, cpropvar, PID_FIRST_USABLE ));
  1924. } // CreateCodePageTestFile()
  1925. void
  1926. OpenCodePageTestFile( LPOLESTR poszFileName,
  1927. IStorage **ppStg,
  1928. BOOL fUseUnicode)
  1929. {
  1930. OLECHAR poszActualFile[MAX_PATH];
  1931. ocscpy(poszActualFile, poszFileName);
  1932. // assume the path name has enough space, change the last character
  1933. // of the filename
  1934. int len = ocslen(poszActualFile);
  1935. if (!fUseUnicode)
  1936. {
  1937. poszActualFile[len]='a';
  1938. poszActualFile[len+1]=0;
  1939. }
  1940. else
  1941. {
  1942. poszActualFile[len]='w';
  1943. poszActualFile[len+1]=0;
  1944. }
  1945. Check(S_OK, StgOpenStorage( poszActualFile,
  1946. (IStorage*) NULL,
  1947. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1948. (SNB) 0,
  1949. (DWORD) 0,
  1950. ppStg ));
  1951. }
  1952. void
  1953. ModifyPropSetCodePage( IStorage *pStg, ULONG ulCodePage )
  1954. {
  1955. ASSERT( pStg != NULL );
  1956. // --------------
  1957. // Initialization
  1958. // --------------
  1959. OLECHAR aocPropSetName[ 32 ];
  1960. DWORD dwOffset = 0;
  1961. DWORD dwcbSection = 0;
  1962. DWORD dwcProperties = 0;
  1963. ULONG ulcbWritten = 0;
  1964. LARGE_INTEGER liSectionOffset, liCodePageOffset;
  1965. TSafeStorage< IStream > pStm;
  1966. CPropVariant cpropvar;
  1967. // Open the Stream
  1968. RtlGuidToPropertySetName( &FMTID_NULL, aocPropSetName );
  1969. Check(S_OK, pStg->OpenStream( aocPropSetName,
  1970. (VOID*)NULL,
  1971. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1972. (DWORD)NULL,
  1973. &pStm ));
  1974. // Seek past the propset header and the format ID.
  1975. liSectionOffset.HighPart = 0;
  1976. liSectionOffset.LowPart = sizeof(PROPERTYSETHEADER) + sizeof(FMTID);
  1977. Check(S_OK, pStm->Seek(liSectionOffset, STREAM_SEEK_SET, NULL ));
  1978. // Move to the beginning of the property set.
  1979. liSectionOffset.HighPart = 0;
  1980. Check(S_OK, pStm->Read( &liSectionOffset.LowPart, sizeof(DWORD), NULL ));
  1981. PropByteSwap(&liSectionOffset.LowPart);
  1982. Check(S_OK, pStm->Seek( liSectionOffset, STREAM_SEEK_SET, NULL ));
  1983. // Get the section size & property count.
  1984. Check(S_OK, pStm->Read( &dwcbSection, sizeof(DWORD), NULL ));
  1985. PropByteSwap( &dwcbSection );
  1986. Check(S_OK, pStm->Read( &dwcProperties, sizeof(DWORD), NULL ));
  1987. PropByteSwap( &dwcProperties );
  1988. // Scan for the PID_CODEPAGE property.
  1989. ULONG ulIndex;
  1990. for(ulIndex = 0; ulIndex < dwcProperties; ulIndex++ )
  1991. {
  1992. PROPID propid;
  1993. DWORD dwOffset;
  1994. // Read in the PROPID
  1995. Check(S_OK, pStm->Read( &propid, sizeof(PROPID), NULL ));
  1996. // Is it the codepage?
  1997. if( PropByteSwap(propid) == PID_CODEPAGE )
  1998. break;
  1999. // Read in this PROPIDs offset (we don't need it, but we want
  2000. // to seek past it.
  2001. Check(S_OK, pStm->Read( &dwOffset, sizeof(dwOffset), NULL ));
  2002. }
  2003. // Verify that the above for loop terminated because we found
  2004. // the codepage.
  2005. Check( TRUE, ulIndex < dwcProperties );
  2006. // Move to the code page.
  2007. liCodePageOffset.HighPart = 0;
  2008. Check(S_OK, pStm->Read( &liCodePageOffset.LowPart, sizeof(DWORD), NULL ));
  2009. PropByteSwap( &liCodePageOffset.LowPart );
  2010. liCodePageOffset.LowPart += liSectionOffset.LowPart + sizeof(ULONG); // Move past VT too.
  2011. ASSERT( liSectionOffset.HighPart == 0 );
  2012. Check(S_OK, pStm->Seek( liCodePageOffset, STREAM_SEEK_SET, NULL ));
  2013. // this is so that you can manually verify what was read
  2014. // i.e. that it is the code page
  2015. WORD wCodePage;
  2016. Check(S_OK, pStm->Read( &wCodePage, sizeof(WORD), NULL));
  2017. Check(S_OK, pStm->Seek( liCodePageOffset, STREAM_SEEK_SET, NULL ));
  2018. // Write the new code page.
  2019. wCodePage = PropByteSwap( (WORD) ((ulCodePage << 16) >> 16) );
  2020. Check(S_OK, pStm->Write( &wCodePage, sizeof(wCodePage), &ulcbWritten ));
  2021. Check(TRUE, ulcbWritten == sizeof(wCodePage) );
  2022. //pStm->Commit(0);
  2023. } // ModifyPropSetCodePage()
  2024. void
  2025. ModifyOSVersion( IStorage* pStg, DWORD dwOSVersion )
  2026. {
  2027. ASSERT( pStg != NULL );
  2028. // --------------
  2029. // Initialization
  2030. // --------------
  2031. OLECHAR aocPropSetName[ 32 ];
  2032. ULONG ulcbWritten = 0;
  2033. LARGE_INTEGER liOffset;
  2034. PROPERTYSETHEADER propsetheader;
  2035. TSafeStorage< IStream > pStm;
  2036. // Open the Stream
  2037. RtlGuidToPropertySetName( &FMTID_NULL, aocPropSetName );
  2038. Check(S_OK, pStg->OpenStream( aocPropSetName,
  2039. (VOID*)NULL,
  2040. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2041. (DWORD)NULL,
  2042. &pStm ));
  2043. // Seek to the OS Version field in the header.
  2044. liOffset.HighPart = 0;
  2045. propsetheader; // avoid compiler warning of unref'd var.
  2046. liOffset.LowPart = sizeof(propsetheader.wByteOrder) + sizeof(propsetheader.wFormat);
  2047. Check(S_OK, pStm->Seek( liOffset, STREAM_SEEK_SET, NULL ));
  2048. // Set the new OS Version
  2049. PropByteSwap( &dwOSVersion );
  2050. Check(S_OK, pStm->Write( &dwOSVersion, sizeof(dwOSVersion), &ulcbWritten ));
  2051. Check(TRUE, ulcbWritten == sizeof(dwOSVersion) );
  2052. } // ModifyOSVersion()
  2053. #define CODEPAGE_DEFAULT 0x04e4 // US English
  2054. #define CODEPAGE_GOOD 0x0000 // Present on a US English machine
  2055. #define CODEPAGE_BAD 0x9999 // Non-existent code page
  2056. void
  2057. test_CodePages( LPOLESTR poszDirectory,
  2058. ULONG ulTestOptions,
  2059. BOOL fTestUnicode)
  2060. {
  2061. printf( " Code Page compatibility -- " );
  2062. if (ulTestOptions & TEST_INTEROP_R)
  2063. printf("Verify Read, ");
  2064. else
  2065. printf("Write & Read, ");
  2066. if (fTestUnicode)
  2067. printf("UNICODE files\n");
  2068. else
  2069. printf("ASCII files\n");
  2070. // --------------
  2071. // Initialization
  2072. // --------------
  2073. OLECHAR oszBadFile[ MAX_PATH ];
  2074. OLECHAR oszGoodFile[ MAX_PATH ];
  2075. OLECHAR oszUnicodeFile[ MAX_PATH ];
  2076. OLECHAR oszMacFile[ MAX_PATH ];
  2077. HRESULT hr = S_OK;
  2078. TSafeStorage< IStorage > pStgBad, pStgGood, pStgUnicode, pStgMac;
  2079. CPropVariant cpropvarWrite, cpropvarRead;
  2080. Check( TRUE, GetACP() == CODEPAGE_DEFAULT );
  2081. // ------------------------------
  2082. // Create test property sets
  2083. // ------------------------------
  2084. // Create a property set with a bad codepage.
  2085. #ifdef _WIN32
  2086. DECLARE_OLESTR(ocsBad, "\\badcp.sg");
  2087. ocscpy( oszBadFile, poszDirectory );
  2088. ocscat( oszBadFile, ocsBad );
  2089. #else
  2090. DECLARE_OLESTR(ocsBad, "badcp.sg");
  2091. ocscpy( oszBadFile, ocsBad );
  2092. #endif
  2093. if (! (ulTestOptions & TEST_INTEROP_R))
  2094. {
  2095. CreateCodePageTestFile( oszBadFile, &pStgBad, fTestUnicode );
  2096. if (!fTestUnicode)
  2097. {
  2098. // modification of code page is only
  2099. // interesting for ansi property sets,
  2100. // otherwise it will result in in error
  2101. ModifyPropSetCodePage( pStgBad, CODEPAGE_BAD );
  2102. }
  2103. }
  2104. else
  2105. OpenCodePageTestFile( oszBadFile, &pStgBad, fTestUnicode );
  2106. // Create a property set with a good codepage.
  2107. #ifdef _WIN32
  2108. ocscpy( oszGoodFile, poszDirectory );
  2109. DECLARE_OLESTR(ocsGood, "\\goodcp.sg");
  2110. ocscat( oszGoodFile, ocsGood );
  2111. #else
  2112. DECLARE_OLESTR(ocsGood, "goodcp.sg");
  2113. ocscpy( oszGoodFile, ocsGood );
  2114. #endif
  2115. if (! (ulTestOptions & TEST_INTEROP_R))
  2116. {
  2117. CreateCodePageTestFile( oszGoodFile, &pStgGood, fTestUnicode );
  2118. // We can only modify code page of ansi property sets; Modfiying
  2119. // code page of UNICODE pages will result in a INVALID_HEADER
  2120. // 'cos it will treat strings as wide chars instead of single-byte
  2121. if (!fTestUnicode)
  2122. {
  2123. ModifyPropSetCodePage( pStgGood, CODEPAGE_GOOD );
  2124. }
  2125. }
  2126. else
  2127. OpenCodePageTestFile( oszGoodFile, &pStgGood, fTestUnicode );
  2128. // Create a property set that has the OS Kind (in the
  2129. // header) set to "Mac".
  2130. #ifdef _WIN32
  2131. DECLARE_OLESTR(ocsMac, "\\mackind.sg");
  2132. ocscpy( oszMacFile, poszDirectory );
  2133. ocscat( oszMacFile, ocsMac );
  2134. #else
  2135. DECLARE_OLESTR(ocsMac, "mackind.sg");
  2136. ocscpy( oszMacFile, ocsMac );
  2137. #endif
  2138. if (! (ulTestOptions & TEST_INTEROP_R))
  2139. {
  2140. CreateCodePageTestFile( oszMacFile, &pStgMac, fTestUnicode );
  2141. ModifyOSVersion( pStgMac, 0x00010904 );
  2142. }
  2143. else
  2144. OpenCodePageTestFile( oszMacFile, &pStgMac, fTestUnicode );
  2145. // ---------------------------
  2146. // Open the Ansi property sets
  2147. // ---------------------------
  2148. TSafeStorage< IPropertySetStorage > pPropSetStgBad(pStgBad);
  2149. TSafeStorage< IPropertySetStorage > pPropSetStgGood(pStgGood);
  2150. TSafeStorage< IPropertySetStorage > pPropSetStgMac(pStgMac);
  2151. TSafeStorage< IPropertyStorage > pPropStgBad, pPropStgGood, pPropStgMac;
  2152. Check(S_OK, pPropSetStgBad->Open(FMTID_NULL,
  2153. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2154. &pPropStgBad));
  2155. Check(S_OK, pPropSetStgGood->Open(FMTID_NULL,
  2156. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2157. &pPropStgGood));
  2158. Check(S_OK, pPropSetStgMac->Open(FMTID_NULL,
  2159. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2160. &pPropStgMac));
  2161. PROPSPEC propspec;
  2162. PROPVARIANT propvar;
  2163. PropVariantInit( &propvar );
  2164. // ASSUMPTION: all three files are created all together by
  2165. // proptest, they will all be ansi or they will all be
  2166. // unicode.
  2167. //
  2168. // For UNICODE APIs, when the code page is not Unicode, it will
  2169. // try and translate it to unicode and thus result in an error
  2170. propspec.ulKind = PRSPEC_PROPID;
  2171. propspec.propid = 1; // propid for code page indicator
  2172. Check(S_OK, pPropStgGood->ReadMultiple( 1, &propspec, &propvar));
  2173. HRESULT pStgBadHr = S_OK; // default
  2174. if (propvar.iVal == (SHORT) CODEPAGE_GOOD)
  2175. { // files created in Ansi
  2176. #ifdef _UNICODE
  2177. pStgBadHr = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION);
  2178. #endif
  2179. }
  2180. // Since we are doing interoperability testing and pStgBad with
  2181. // a wrong codepage number will result in a invalid_header error,
  2182. // we change it back to normal to get rid of the error.
  2183. //
  2184. // Also, we only change it when the current code page is bad,
  2185. // otherwise, we leave it as it is.
  2186. //
  2187. // We know that the correct number to put in is 1252 'cos we only
  2188. // change the code page for ansi property sets.
  2189. if (propvar.iVal == (SHORT) CODEPAGE_BAD)
  2190. ModifyPropSetCodePage( pStgBad, 1252 );
  2191. // ------------------------------------------
  2192. // Test BSTRs in the three property sets
  2193. // ------------------------------------------
  2194. // Attempt to read by name.
  2195. propspec.ulKind = PRSPEC_LPWSTR;
  2196. DECLARE_OLESTR(ocsCP_test, CODEPAGE_TEST_NAMED_PROPERTY);
  2197. propspec.lpwstr = ocsCP_test;
  2198. CPropVariant cpropvar=(LONG) 0x12345678;
  2199. Check(S_OK,
  2200. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  2201. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2202. PropVariantClear( &propvar );
  2203. Check(pStgBadHr,
  2204. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  2205. PropVariantClear( &propvar );
  2206. Check(S_OK,
  2207. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  2208. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2209. // Attempt to write by name.
  2210. Check(S_OK,
  2211. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2212. Check(pStgBadHr,
  2213. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2214. Check(S_OK,
  2215. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2216. PropVariantClear( &propvar );
  2217. // Attempt to read the BSTR property
  2218. propspec.ulKind = PRSPEC_PROPID;
  2219. propspec.propid = CODEPAGE_TEST_UNNAMED_BSTR_PROPID;
  2220. DECLARE_OLESTR(ocsBSTR, "BSTR Property");
  2221. cpropvar.SetBSTR( ocsBSTR );
  2222. Check(S_OK,
  2223. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  2224. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2225. PropVariantClear( &propvar );
  2226. Check(pStgBadHr,
  2227. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  2228. PropVariantClear( &propvar );
  2229. Check(S_OK,
  2230. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  2231. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2232. // Attempt to write the BSTR property
  2233. Check(S_OK,
  2234. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2235. Check(pStgBadHr,
  2236. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2237. Check(S_OK,
  2238. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2239. PropVariantClear( &propvar );
  2240. // Attempt to read the BSTR Vector property
  2241. propspec.ulKind = PRSPEC_PROPID;
  2242. propspec.propid = CODEPAGE_TEST_VBSTR_PROPID;
  2243. DECLARE_OLESTR(ocsElt0, "BSTR Element 0");
  2244. DECLARE_OLESTR(ocsElt1, "BSTR Element 1");
  2245. cpropvar.SetBSTR( ocsElt1, 1 );
  2246. cpropvar.SetBSTR( ocsElt0, 0 );
  2247. ASSERT( (VT_VECTOR | VT_BSTR) == cpropvar.VarType() );
  2248. Check(S_OK,
  2249. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  2250. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2251. PropVariantClear( &propvar );
  2252. Check(pStgBadHr,
  2253. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  2254. PropVariantClear(&propvar);
  2255. Check(S_OK,
  2256. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  2257. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2258. // Attempt to write the BSTR Vector property
  2259. Check(S_OK,
  2260. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2261. Check(pStgBadHr,
  2262. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2263. Check(S_OK,
  2264. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2265. PropVariantClear( &propvar );
  2266. // Attempt to read the Variant Vector which has a BSTR
  2267. CPropVariant cpropvarT;
  2268. DECLARE_OLESTR(ocsPropVect, "PropVar Vector BSTR");
  2269. cpropvarT.SetBSTR( ocsPropVect );
  2270. cpropvar[1] = (LPPROPVARIANT) cpropvarT;
  2271. cpropvar[0] = (LPPROPVARIANT) CPropVariant((long) 44);
  2272. ASSERT( (VT_VARIANT | VT_VECTOR) == cpropvar.VarType() );
  2273. propspec.ulKind = PRSPEC_PROPID;
  2274. propspec.propid = CODEPAGE_TEST_VPROPVAR_BSTR_PROPID;
  2275. Check(S_OK,
  2276. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  2277. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2278. PropVariantClear( &propvar );
  2279. Check(pStgBadHr,
  2280. pPropStgBad->ReadMultiple( 1, &propspec, &propvar ));
  2281. PropVariantClear(&propvar);
  2282. Check(S_OK,
  2283. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  2284. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2285. // Attempt to write the Variant Vector which has a BSTR
  2286. Check(S_OK,
  2287. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2288. Check(pStgBadHr,
  2289. pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2290. Check(S_OK,
  2291. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2292. PropVariantClear( &propvar );
  2293. // Attempt to read the I4 property.
  2294. propspec.ulKind = PRSPEC_PROPID;
  2295. propspec.propid = CODEPAGE_TEST_UNNAMED_I4_PROPID;
  2296. Check(S_OK,
  2297. pPropStgMac->ReadMultiple( 1, &propspec, &propvar ));
  2298. cpropvar = (LONG) 0x76543210;
  2299. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2300. PropVariantClear( &propvar );
  2301. hr = pPropStgBad->ReadMultiple( 1, &propspec, &propvar );
  2302. Check(TRUE, S_OK == hr || pStgBadHr == hr );
  2303. PropVariantClear( &propvar );
  2304. Check(S_OK,
  2305. pPropStgGood->ReadMultiple( 1, &propspec, &propvar ));
  2306. Check(S_OK, CPropVariant::Compare( &propvar, &cpropvar ));
  2307. // Attempt to write the I4 property
  2308. Check(S_OK,
  2309. pPropStgMac->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2310. hr = pPropStgBad->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE );
  2311. Check(TRUE, S_OK == hr || pStgBadHr == hr );
  2312. Check(S_OK,
  2313. pPropStgGood->WriteMultiple( 1, &propspec, &propvar, PID_FIRST_USABLE ));
  2314. PropVariantClear( &propvar );
  2315. // ---------------------------------------
  2316. // Test LPSTRs in the Unicode property set
  2317. // ---------------------------------------
  2318. // This test doesn't verify that the LPSTRs are actually
  2319. // written in Unicode. A manual test is required for that.
  2320. // Create a Unicode property set. We'll make it
  2321. // non-simple so that we can test a VT_STREAM (which
  2322. // is stored like an LPSTR).
  2323. #ifdef _WIN32
  2324. DECLARE_OLESTR(ocsUni, "\\UnicodCP.stg");
  2325. ocscpy( oszUnicodeFile, poszDirectory );
  2326. ocscat( oszUnicodeFile, ocsUni);
  2327. #else
  2328. DECLARE_OLESTR(ocsUni, "UnicodCP.stg");
  2329. ocscpy( oszUnicodeFile, ocsUni );
  2330. #endif
  2331. Check(S_OK, StgCreateDocfile(oszUnicodeFile,
  2332. STGM_CREATE | STGM_READWRITE |
  2333. STGM_SHARE_EXCLUSIVE,
  2334. (DWORD)NULL,
  2335. &pStgUnicode));
  2336. TSafeStorage< IPropertySetStorage > pPropSetStgUnicode(pStgUnicode);
  2337. TSafeStorage< IPropertyStorage > pPropStgUnicode;
  2338. Check(S_OK, pPropSetStgUnicode->Create(FMTID_NULL,
  2339. &CLSID_NULL,
  2340. PROPSETFLAG_DEFAULT,
  2341. STGM_CREATE | STGM_SHARE_EXCLUSIVE
  2342. | STGM_READWRITE,
  2343. &pPropStgUnicode));
  2344. // Write/verify an LPSTR property.
  2345. propspec.ulKind = PRSPEC_LPWSTR;
  2346. DECLARE_OLESTR(ocsLPSTR, "LPSTR Property");
  2347. propspec.lpwstr = ocsLPSTR;
  2348. cpropvarWrite = "An LPSTR Property";
  2349. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, cpropvarWrite, PID_FIRST_USABLE ));
  2350. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, cpropvarRead ));
  2351. Check(0, strcmp( (LPSTR) cpropvarWrite, (LPSTR) cpropvarRead ));
  2352. cpropvarRead.Clear();
  2353. // Write/verify a vector of LPSTR properties
  2354. DECLARE_OLESTR(ocsVectLPSTR, "Vector of LPSTR properties");
  2355. propspec.lpwstr = ocsVectLPSTR;
  2356. cpropvarWrite[1] = "LPSTR Property #1";
  2357. cpropvarWrite[0] = "LPSTR Property #0";
  2358. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, cpropvarWrite, PID_FIRST_USABLE ));
  2359. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, cpropvarRead ));
  2360. Check(0, strcmp( (LPSTR) cpropvarWrite[1], (LPSTR) cpropvarRead[1] ));
  2361. Check(0, strcmp( (LPSTR) cpropvarWrite[0], (LPSTR) cpropvarRead[0] ));
  2362. cpropvarRead.Clear();
  2363. // Write/verify a vector of variants which has an LPSTR
  2364. DECLARE_OLESTR(ocsVariantWithLPSTR, "Variant Vector with an LPSTR");
  2365. propspec.lpwstr = ocsVariantWithLPSTR;
  2366. cpropvarWrite[1] = (LPPROPVARIANT) CPropVariant("LPSTR in a Variant Vector");
  2367. cpropvarWrite[0] = (LPPROPVARIANT) CPropVariant((long) 22); // an I4
  2368. ASSERT( (VT_VECTOR | VT_VARIANT) == cpropvarWrite.VarType() );
  2369. Check(S_OK, pPropStgUnicode->WriteMultiple( 1, &propspec, cpropvarWrite, PID_FIRST_USABLE ));
  2370. Check(S_OK, pPropStgUnicode->ReadMultiple( 1, &propspec, cpropvarRead ));
  2371. Check(0, strcmp( (LPSTR) cpropvarWrite[1], (LPSTR) cpropvarRead[1] ));
  2372. cpropvarRead.Clear();
  2373. }
  2374. void
  2375. test_PropertyInterfaces(IStorage *pstgTemp)
  2376. {
  2377. // this test depends on being first for enumerator
  2378. test_IEnumSTATPROPSETSTG(pstgTemp);
  2379. test_MaxPropertyName(pstgTemp);
  2380. test_IPropertyStorage(pstgTemp);
  2381. test_IPropertySetStorage(pstgTemp);
  2382. test_IEnumSTATPROPSTG(pstgTemp);
  2383. }
  2384. //===================================================================
  2385. //
  2386. // Function: test_CopyTo
  2387. //
  2388. // Synopsis: Verify that IStorage::CopyTo copies an
  2389. // un-flushed property set.
  2390. //
  2391. // This test creates and writes to a simple property set,
  2392. // a non-simple property set, and a new Storage & Stream,
  2393. // all within the source (caller-provided) Storage.
  2394. //
  2395. // It then copies the entire source Storage to the
  2396. // destination Storage, and verifies that all commited
  2397. // data in the Source is also in the destination.
  2398. //
  2399. // All new Storages and property sets are created
  2400. // under a new base storage. The caller can specify
  2401. // if this base Storage is direct or transacted, and
  2402. // can specify if the property sets are direct or
  2403. // transacted.
  2404. //
  2405. //===================================================================
  2406. void test_CopyTo(IStorage *pstgSource, // Source of the CopyTo
  2407. IStorage *pstgDestination, // Destination of the CopyTo
  2408. ULONG ulBaseStgTransaction, // Transaction bit for the base storage.
  2409. ULONG ulPropSetTransaction, // Transaction bit for the property sets.
  2410. LPOLESTR oszBaseStorageName )
  2411. {
  2412. printf( " IStorage::CopyTo (Base Storage is %s, PropSets are %s)\n",
  2413. ulBaseStgTransaction & STGM_TRANSACTED ? "transacted" : "directed",
  2414. ulPropSetTransaction & STGM_TRANSACTED ? "transacted" : "directed" );
  2415. // ---------------
  2416. // Local Variables
  2417. // ---------------
  2418. DECLARE_OLESTR(poszTestSubStorage ,"TestStorage" );
  2419. DECLARE_OLESTR(poszTestSubStream ,"TestStream" );
  2420. DECLARE_OLESTR(poszTestDataPreCommit ,"Test Data (pre-commit)" );
  2421. DECLARE_OLESTR(poszTestDataPostCommit ,"Test Data (post-commit)");
  2422. long lSimplePreCommit = 0x0123;
  2423. long lSimplePostCommit = 0x4567;
  2424. long lNonSimplePreCommit = 0x89AB;
  2425. long lNonSimplePostCommit = 0xCDEF;
  2426. BYTE acReadBuffer[ 80 ];
  2427. ULONG cbRead;
  2428. FMTID fmtidSimple, fmtidNonSimple;
  2429. // Base Storages for the Source & Destination. All
  2430. // new Streams/Storages/PropSets will be created below here.
  2431. TSafeStorage< IStorage > pstgBaseSource;
  2432. TSafeStorage< IStorage > pstgBaseDestination;
  2433. TSafeStorage< IStorage > pstgSub; // A sub-storage of the base.
  2434. TSafeStorage< IStream > pstmSub; // A Stream in the sub-storage (pstgSub)
  2435. PROPSPEC propspec;
  2436. PROPVARIANT propvarSourceSimple,
  2437. propvarDestination;
  2438. // -----
  2439. // Begin
  2440. // -----
  2441. // Create new format IDs
  2442. UuidCreate(&fmtidSimple);
  2443. UuidCreate(&fmtidNonSimple);
  2444. // -----------------------
  2445. // Create the base Storage
  2446. // -----------------------
  2447. // Create a base Storage for the Source. All of this test will be under
  2448. // that Storage.
  2449. // In the source Storage.
  2450. Check( S_OK, pstgSource->CreateStorage(
  2451. oszBaseStorageName,
  2452. STGM_CREATE | ulBaseStgTransaction | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  2453. 0L, 0L,
  2454. &pstgBaseSource ));
  2455. // And in the destination Storage.
  2456. Check( S_OK, pstgDestination->CreateStorage(
  2457. oszBaseStorageName,
  2458. STGM_CREATE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  2459. 0L, 0L,
  2460. &pstgBaseDestination ));
  2461. // -------------------------------------------
  2462. // Write data to a new Stream in a new Storage
  2463. // -------------------------------------------
  2464. // We'll partially verify the CopyTo by checking that this data
  2465. // makes it into the destination Storage.
  2466. // Create a Storage, and then a Stream within it.
  2467. Check( S_OK, pstgBaseSource->CreateStorage(
  2468. poszTestSubStorage,
  2469. STGM_CREATE | ulPropSetTransaction | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  2470. 0L, 0L,
  2471. &pstgSub ));
  2472. Check( S_OK, pstgSub->CreateStream(
  2473. poszTestSubStream,
  2474. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2475. 0L, 0L,
  2476. &pstmSub ));
  2477. // Write data to the Stream.
  2478. Check( S_OK, pstmSub->Write(
  2479. poszTestDataPreCommit,
  2480. ( sizeof(OLECHAR)
  2481. *
  2482. ( ocslen(poszTestDataPreCommit) + sizeof( OLECHAR ))
  2483. ),
  2484. NULL ));
  2485. // ---------------------------------------------------------
  2486. // Write to a new simple property set in the Source storage.
  2487. // ---------------------------------------------------------
  2488. TSafeStorage< IPropertySetStorage > pPropSetStgSource(pstgBaseSource);
  2489. TSafeStorage< IPropertyStorage > pPropStgSource1,
  2490. pPropStgSource2,
  2491. pPropStgDestination;
  2492. // Create a property set mode.
  2493. Check(S_OK, pPropSetStgSource->Create(fmtidSimple,
  2494. NULL,
  2495. PROPSETFLAG_DEFAULT,
  2496. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  2497. &pPropStgSource1));
  2498. // Write the property set name (just to test this functionality).
  2499. PROPID pidDictionary = 0;
  2500. DECLARE_CONST_OLESTR(cposzPropSetName, "Property Set for CopyTo Test");
  2501. ASSERT( CWC_MAXPROPNAMESZ >= ocslen(cposzPropSetName) + sizeof(OLECHAR) );
  2502. Check(S_OK, pPropStgSource1->WritePropertyNames( 1, &pidDictionary,
  2503. &cposzPropSetName ));
  2504. // Create a PROPSPEC. We'll use this throughout the rest of the routine.
  2505. propspec.ulKind = PRSPEC_PROPID;
  2506. propspec.propid = 1000;
  2507. // Create a PROPVARIANT for this test of the Simple case.
  2508. propvarSourceSimple.vt = VT_I4;
  2509. propvarSourceSimple.lVal = lSimplePreCommit;
  2510. // Write the PROPVARIANT to the property set.
  2511. Check(S_OK, pPropStgSource1->WriteMultiple(1, &propspec, &propvarSourceSimple, 2));
  2512. // -------------------------
  2513. // Commit everything so far.
  2514. // -------------------------
  2515. // Commit the sub-Storage.
  2516. Check(S_OK, pstgSub->Commit( STGC_DEFAULT ));
  2517. // Commit the simple property set.
  2518. Check(S_OK, pPropStgSource1->Commit( STGC_DEFAULT ));
  2519. // Commit the base Storage which holds all of the above.
  2520. Check(S_OK, pstgBaseSource->Commit( STGC_DEFAULT ));
  2521. // -------------------------------------------------
  2522. // Write new data to everything but don't commit it.
  2523. // -------------------------------------------------
  2524. // Write to the sub-storage.
  2525. Check(S_OK, pstmSub->Seek(g_li0, STREAM_SEEK_SET, NULL));
  2526. Check( S_OK, pstmSub->Write(
  2527. poszTestDataPostCommit,
  2528. ( sizeof(OLECHAR)
  2529. *
  2530. (ocslen( poszTestDataPostCommit ) + sizeof(OLECHAR))
  2531. ),
  2532. NULL ));
  2533. // Write to the simple property set.
  2534. propvarSourceSimple.lVal = lSimplePostCommit;
  2535. Check(S_OK, pPropStgSource1->WriteMultiple(1, &propspec, &propvarSourceSimple, 2));
  2536. // -------------------------------------------
  2537. // Copy the source Storage to the destination.
  2538. // -------------------------------------------
  2539. // Release the sub-Storage (which is below the base Storage, and has
  2540. // a Stream with data in it), just to test that the CopyTo can
  2541. // handle it.
  2542. pstgSub->Release();
  2543. pstgSub = NULL;
  2544. Check(S_OK, pstgBaseSource->CopyTo( 0, NULL, NULL, pstgBaseDestination ));
  2545. // ----------------------------------------------------------
  2546. // Verify the simple property set in the destination Storage.
  2547. // ----------------------------------------------------------
  2548. TSafeStorage< IPropertySetStorage > pPropSetStgDestination(pstgBaseDestination);
  2549. // Open the simple property set.
  2550. Check(S_OK, pPropSetStgDestination->Open(fmtidSimple,
  2551. STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  2552. &pPropStgDestination));
  2553. // Verify the property set name.
  2554. OLECHAR *poszPropSetNameDestination;
  2555. BOOL bReadPropertyNamePassed = FALSE;
  2556. Check(S_OK, pPropStgDestination->
  2557. ReadPropertyNames( 1, &pidDictionary, &poszPropSetNameDestination ));
  2558. if( poszPropSetNameDestination // Did we get a name back?
  2559. && // If so, was it the correct name?
  2560. !ocscmp( cposzPropSetName, poszPropSetNameDestination )
  2561. )
  2562. {
  2563. bReadPropertyNamePassed = TRUE;
  2564. }
  2565. CoTaskMemFree( poszPropSetNameDestination );
  2566. poszPropSetNameDestination = NULL;
  2567. Check( TRUE, bReadPropertyNamePassed );
  2568. // Read the PROPVARIANT that we wrote earlier.
  2569. Check(S_OK, pPropStgDestination->ReadMultiple(1, &propspec, &propvarDestination));
  2570. // Verify that it's correct.
  2571. Check(TRUE, propvarDestination.vt == propvarSourceSimple.vt );
  2572. Check(TRUE, propvarDestination.lVal == lSimplePostCommit);
  2573. Check(S_OK, pPropStgDestination->Commit( STGC_DEFAULT ));
  2574. Check(S_OK, pPropStgDestination->Release());
  2575. pPropStgDestination = NULL;
  2576. // ------------------------------------------------
  2577. // Verify the test data in the destination Storage.
  2578. // ------------------------------------------------
  2579. // Now we can release and re-use the Stream pointer that
  2580. // currently points to the sub-Stream in the source docfile.
  2581. Check(STG_E_REVERTED, pstmSub->Commit( STGC_DEFAULT ));
  2582. Check(S_OK, pstmSub->Release());
  2583. pstmSub = NULL;
  2584. // Get the Storage then the Stream.
  2585. Check( S_OK, pstgBaseDestination->OpenStorage(
  2586. poszTestSubStorage,
  2587. NULL,
  2588. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  2589. NULL,
  2590. 0L,
  2591. &pstgSub ));
  2592. Check( S_OK, pstgSub->OpenStream(
  2593. poszTestSubStream,
  2594. NULL,
  2595. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2596. 0L,
  2597. &pstmSub ));
  2598. // Read the data and compare it against what we wrote.
  2599. Check( S_OK, pstmSub->Read(
  2600. acReadBuffer,
  2601. sizeof( acReadBuffer ),
  2602. &cbRead ));
  2603. OLECHAR const *poszTestData = ( STGM_TRANSACTED & ulPropSetTransaction )
  2604. ?
  2605. poszTestDataPreCommit
  2606. :
  2607. poszTestDataPostCommit;
  2608. Check( TRUE, cbRead == sizeof(OLECHAR)
  2609. *
  2610. (ocslen( poszTestData ) + sizeof(OLECHAR))
  2611. );
  2612. Check( FALSE, ocscmp( poszTestData, (OLECHAR *) acReadBuffer ));
  2613. // ----
  2614. // Exit
  2615. // ----
  2616. // We're done. Don't bother to release anything;
  2617. // they'll release themselves in their destructors.
  2618. return;
  2619. } // test_CopyTo()
  2620. //--------------------------------------------------------
  2621. //
  2622. // Function: test_OLESpecTickerExample
  2623. //
  2624. // Synopsis: This function generates the ticker property set
  2625. // example that's used in the OLE Programmer's Reference
  2626. // (when describing property ID 0 - the dictionary).
  2627. //
  2628. //--------------------------------------------------------
  2629. #define PID_SYMBOL 0x7
  2630. #define PID_OPEN 0x3
  2631. #define PID_CLOSE 0x4
  2632. #define PID_HIGH 0x5
  2633. #define PID_LOW 0x6
  2634. #define PID_LAST 0x8
  2635. #define PID_VOLUME 0x9
  2636. void test_OLESpecTickerExample( IStorage* pstg )
  2637. {
  2638. printf( " Generate the Stock Ticker property set example from the OLE Programmer's Ref\n" );
  2639. // ------
  2640. // Locals
  2641. // ------
  2642. FMTID fmtid;
  2643. PROPSPEC propspec;
  2644. DECLARE_CONST_OLESTR(coszPropSetName, "Stock Quote" );
  2645. DECLARE_CONST_OLESTR(coszTickerSymbolName, "Ticker Symbol" );
  2646. DECLARE_CONST_OLESTR(coszOpenName, "Opening Price" );
  2647. DECLARE_CONST_OLESTR(coszCloseName, "Last Closing Price" );
  2648. DECLARE_CONST_OLESTR(coszHighName, "High Price" );
  2649. DECLARE_CONST_OLESTR(coszLowName, "Low Price" );
  2650. DECLARE_CONST_OLESTR(coszLastName, "Last Price" );
  2651. DECLARE_CONST_OLESTR(coszVolumeName, "Volume" );
  2652. // ---------------------------------
  2653. // Create a new simple property set.
  2654. // ---------------------------------
  2655. TSafeStorage< IPropertySetStorage > pPropSetStg(pstg);
  2656. IPropertyStorage *pPropStg;
  2657. UuidCreate( &fmtid );
  2658. Check(S_OK, pPropSetStg->Create(fmtid,
  2659. NULL,
  2660. PROPSETFLAG_DEFAULT, // Unicode
  2661. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2662. &pPropStg));
  2663. // ---------------------------------------------
  2664. // Fill in the simply property set's dictionary.
  2665. // ---------------------------------------------
  2666. // Write the property set's name.
  2667. PROPID pidDictionary = 0;
  2668. Check(S_OK, pPropStg->WritePropertyNames(1, &pidDictionary, &coszPropSetName ));
  2669. // Write the High price, forcing the dictionary to pad.
  2670. propspec.ulKind = PRSPEC_PROPID;
  2671. propspec.propid = PID_HIGH;
  2672. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszHighName ));
  2673. // Write the ticker symbol.
  2674. propspec.propid = PID_SYMBOL;
  2675. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszTickerSymbolName));
  2676. // Write the rest of the dictionary.
  2677. propspec.propid = PID_LOW;
  2678. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszLowName));
  2679. propspec.propid = PID_OPEN;
  2680. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszOpenName));
  2681. propspec.propid = PID_CLOSE;
  2682. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszCloseName));
  2683. propspec.propid = PID_LAST;
  2684. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszLastName));
  2685. propspec.propid = PID_VOLUME;
  2686. Check(S_OK, pPropStg->WritePropertyNames(1, &propspec.propid, &coszVolumeName));
  2687. // Write out the ticker symbol.
  2688. propspec.propid = PID_SYMBOL;
  2689. PROPVARIANT propvar;
  2690. propvar.vt = VT_LPWSTR;
  2691. DECLARE_WIDESTR(wszMSFT, "MSFT");
  2692. propvar.pwszVal = wszMSFT;
  2693. Check(S_OK, pPropStg->WriteMultiple(1, &propspec, &propvar, 2));
  2694. // ----
  2695. // Exit
  2696. // ----
  2697. Check(S_OK, pPropStg->Commit( STGC_DEFAULT ));
  2698. Check(S_OK, pPropStg->Release());
  2699. Check(S_OK, pstg->Commit( STGC_DEFAULT ));
  2700. return;
  2701. } // test_OLESpecTickerExample()
  2702. void
  2703. test_Office( LPOLESTR wszTestFile )
  2704. {
  2705. printf( " Generate Office Property Sets\n" );
  2706. TSafeStorage<IStorage> pStg;
  2707. TSafeStorage<IPropertyStorage> pPStgSumInfo, pPStgDocSumInfo, pPStgUserDefined;
  2708. PROPVARIANT propvarWrite, propvarRead;
  2709. PROPSPEC propspec;
  2710. PropVariantInit( &propvarWrite );
  2711. PropVariantInit( &propvarRead );
  2712. // Create the DocFile
  2713. Check(S_OK, StgCreateDocfile( wszTestFile,
  2714. STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  2715. 0,
  2716. &pStg));
  2717. // Create the SummaryInformation property set.
  2718. TSafeStorage<IPropertySetStorage> pPSStg( pStg );
  2719. Check(S_OK, pPSStg->Create( FMTID_SummaryInformation,
  2720. NULL,
  2721. PROPSETFLAG_ANSI,
  2722. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2723. &pPStgSumInfo ));
  2724. // Write a Title to the SumInfo property set.
  2725. PropVariantInit( &propvarWrite );
  2726. propvarWrite.vt = VT_LPSTR;
  2727. propvarWrite.pszVal = "Title from PropTest";
  2728. propspec.ulKind = PRSPEC_PROPID;
  2729. propspec.propid = PID_TITLE;
  2730. Check( S_OK, pPStgSumInfo->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  2731. Check( S_OK, pPStgSumInfo->ReadMultiple( 1, &propspec, &propvarRead ));
  2732. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  2733. Check( FALSE, strcmp( propvarWrite.pszVal, propvarRead.pszVal ));
  2734. PropVariantClear( &propvarRead );
  2735. PropVariantInit( &propvarRead );
  2736. pPStgSumInfo->Release();
  2737. pPStgSumInfo = NULL;
  2738. // Create the DocumentSummaryInformation property set.
  2739. Check(S_OK, pPSStg->Create( FMTID_DocSummaryInformation,
  2740. NULL,
  2741. PROPSETFLAG_ANSI,
  2742. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2743. &pPStgDocSumInfo ));
  2744. // Write a word-count to the DocSumInfo property set.
  2745. PropVariantInit( &propvarWrite );
  2746. propvarWrite.vt = VT_I4;
  2747. propvarWrite.lVal = 100;
  2748. propspec.ulKind = PRSPEC_PROPID;
  2749. propspec.propid = PID_WORDCOUNT;
  2750. Check( S_OK, pPStgDocSumInfo->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  2751. Check( S_OK, pPStgDocSumInfo->ReadMultiple( 1, &propspec, &propvarRead ));
  2752. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  2753. Check( TRUE, propvarWrite.lVal == propvarRead.lVal );
  2754. PropVariantClear( &propvarRead );
  2755. PropVariantInit( &propvarRead );
  2756. pPStgDocSumInfo->Release();
  2757. pPStgDocSumInfo = NULL;
  2758. // Create the UserDefined property set.
  2759. Check(S_OK, pPSStg->Create( FMTID_UserDefinedProperties,
  2760. NULL,
  2761. PROPSETFLAG_ANSI,
  2762. STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  2763. &pPStgUserDefined ));
  2764. // Write named string to the UserDefined property set.
  2765. PropVariantInit( &propvarWrite );
  2766. propvarWrite.vt = VT_LPSTR;
  2767. propvarWrite.pszVal = "User-Defined string from PropTest";
  2768. propspec.ulKind = PRSPEC_LPWSTR;
  2769. DECLARE_OLESTR(ocsTest, "PropTest String");
  2770. propspec.lpwstr = ocsTest;
  2771. Check( S_OK, pPStgUserDefined->WriteMultiple( 1, &propspec, &propvarWrite, PID_FIRST_USABLE ));
  2772. Check( S_OK, pPStgUserDefined->ReadMultiple( 1, &propspec, &propvarRead ));
  2773. Check( TRUE, propvarWrite.vt == propvarRead.vt );
  2774. Check( FALSE, strcmp( propvarWrite.pszVal, propvarRead.pszVal ));
  2775. PropVariantClear( &propvarRead );
  2776. PropVariantInit( &propvarRead );
  2777. pPStgUserDefined->Release();
  2778. pPStgUserDefined = NULL;
  2779. // And we're done! (Everything releases automatically)
  2780. return;
  2781. }
  2782. inline BOOL operator == ( FILETIME &ft1, FILETIME &ft2 )
  2783. {
  2784. return( ft1.dwHighDateTime == ft2.dwHighDateTime
  2785. &&
  2786. ft1.dwLowDateTime == ft2.dwLowDateTime );
  2787. }
  2788. inline BOOL operator != ( FILETIME &ft1, FILETIME &ft2 )
  2789. {
  2790. return( ft1.dwHighDateTime != ft2.dwHighDateTime
  2791. ||
  2792. ft1.dwLowDateTime != ft2.dwLowDateTime );
  2793. }
  2794. inline BOOL operator > ( FILETIME &ft1, FILETIME &ft2 )
  2795. {
  2796. return( ft1.dwHighDateTime > ft2.dwHighDateTime
  2797. ||
  2798. ft1.dwHighDateTime == ft2.dwHighDateTime
  2799. &&
  2800. ft1.dwLowDateTime > ft2.dwLowDateTime );
  2801. }
  2802. inline BOOL operator < ( FILETIME &ft1, FILETIME &ft2 )
  2803. {
  2804. return( ft1.dwHighDateTime < ft2.dwHighDateTime
  2805. ||
  2806. ft1.dwHighDateTime == ft2.dwHighDateTime
  2807. &&
  2808. ft1.dwLowDateTime < ft2.dwLowDateTime );
  2809. }
  2810. inline BOOL operator >= ( FILETIME &ft1, FILETIME &ft2 )
  2811. {
  2812. return( ft1 > ft2
  2813. ||
  2814. ft1 == ft2 );
  2815. }
  2816. inline BOOL operator <= ( FILETIME &ft1, FILETIME &ft2 )
  2817. {
  2818. return( ft1 < ft2
  2819. ||
  2820. ft1 == ft2 );
  2821. }
  2822. FILETIME operator - ( FILETIME &ft1, FILETIME &ft2 )
  2823. {
  2824. FILETIME ftDiff;
  2825. if( ft1 < ft2 )
  2826. {
  2827. ftDiff.dwLowDateTime = 0;
  2828. ftDiff.dwHighDateTime = 0;
  2829. }
  2830. else if( ft1.dwLowDateTime >= ft2.dwLowDateTime )
  2831. {
  2832. ftDiff.dwLowDateTime = ft1.dwLowDateTime - ft2.dwLowDateTime;
  2833. ftDiff.dwHighDateTime = ft1.dwHighDateTime - ft2.dwHighDateTime;
  2834. }
  2835. else
  2836. {
  2837. ftDiff.dwLowDateTime = ft1.dwLowDateTime - ft2.dwLowDateTime;
  2838. ftDiff.dwLowDateTime = (DWORD) -1 - ftDiff.dwLowDateTime;
  2839. ftDiff.dwHighDateTime = ft1.dwHighDateTime - ft2.dwHighDateTime - 1;
  2840. }
  2841. return( ftDiff );
  2842. }
  2843. void test_PropVariantCopy( )
  2844. {
  2845. printf( " PropVariantCopy\n" );
  2846. PROPVARIANT propvarCopy;
  2847. PropVariantInit( &propvarCopy );
  2848. for( int i = 0; i < CPROPERTIES_ALL; i++ )
  2849. {
  2850. Check(S_OK, PropVariantCopy( &propvarCopy, &g_rgcpropvarAll[i] ));
  2851. Check(S_OK, CPropVariant::Compare( &propvarCopy, &g_rgcpropvarAll[i]
  2852. ));
  2853. PropVariantClear( &propvarCopy );
  2854. }
  2855. }
  2856. char* oszft(FILETIME *pft)
  2857. {
  2858. static char szBuf[32];
  2859. szBuf[0] = '\0';
  2860. sprintf(szBuf, "(H)%x (L)%x", pft->dwLowDateTime,
  2861. pft->dwHighDateTime);
  2862. return szBuf;
  2863. }
  2864. void PrintOC(char *ocsStr)
  2865. {
  2866. // simple subsitute to print both WIDE and BYTE chars
  2867. for ( ;*ocsStr; ocsStr++)
  2868. printf("%c", (char) *(ocsStr));
  2869. }
  2870. void PrintOC(WCHAR *ocsStr)
  2871. {
  2872. // simple subsitute to print both WIDE and BYTE chars
  2873. for ( ;*ocsStr; ocsStr++)
  2874. if ( (int) *ocsStr < (int) 0xff) // in range
  2875. printf("%c", (char) *(ocsStr));
  2876. else
  2877. printf("[%d]", *ocsStr);
  2878. }
  2879. void DumpTime(WCHAR *pszName, FILETIME *pft)
  2880. {
  2881. PrintOC(pszName);
  2882. printf("(H)%x (L)%x\n",
  2883. pft->dwHighDateTime,
  2884. pft->dwLowDateTime);
  2885. }
  2886. void DumpTime(char *pszName, FILETIME *pft)
  2887. {
  2888. printf("%s (H)%x (L)%x\n",
  2889. pszName,
  2890. pft->dwHighDateTime,
  2891. pft->dwLowDateTime);
  2892. }
  2893. VOID
  2894. PrintGuid(GUID *pguid)
  2895. {
  2896. printf(
  2897. "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  2898. pguid->Data1,
  2899. pguid->Data2,
  2900. pguid->Data3,
  2901. pguid->Data4[0],
  2902. pguid->Data4[1],
  2903. pguid->Data4[2],
  2904. pguid->Data4[3],
  2905. pguid->Data4[4],
  2906. pguid->Data4[5],
  2907. pguid->Data4[6],
  2908. pguid->Data4[7]);
  2909. }
  2910. VOID
  2911. ListPropSetHeader(
  2912. STATPROPSETSTG *pspss,
  2913. OLECHAR *poszName)
  2914. {
  2915. BOOLEAN fDocumentSummarySection2;
  2916. OLECHAR oszStream[80]; // should be enough
  2917. fDocumentSummarySection2 = (BOOLEAN)
  2918. memcmp(&pspss->fmtid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0;
  2919. printf(" Property set ");
  2920. PrintGuid(&pspss->fmtid);
  2921. RtlGuidToPropertySetName(&pspss->fmtid, oszStream);
  2922. printf("\n %s Name ",
  2923. (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)?
  2924. "Embedding" : "Stream");
  2925. PrintOC(oszStream);
  2926. if (poszName != NULL || fDocumentSummarySection2)
  2927. {
  2928. printf(" (");
  2929. if (poszName != NULL)
  2930. PrintOC(poszName);
  2931. else
  2932. printf("User defined properties");
  2933. printf(")");
  2934. }
  2935. printf("\n");
  2936. if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
  2937. {
  2938. DumpTime(" Create Time ", &pspss->ctime);
  2939. }
  2940. DumpTime(" Modify Time ", &pspss->mtime);
  2941. if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
  2942. {
  2943. DumpTime(" Access Time ", &pspss->atime);
  2944. }
  2945. }
  2946. typedef enum _PUBLICPROPSET
  2947. {
  2948. PUBPS_UNKNOWN = 0,
  2949. PUBPS_SUMMARYINFO = 3,
  2950. PUBPS_DOCSUMMARYINFO = 4,
  2951. PUBPS_USERDEFINED = 5,
  2952. } PUBLICPROPSET;
  2953. #define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
  2954. ULONG
  2955. SizeProp(PROPVARIANT *pv)
  2956. {
  2957. ULONG j;
  2958. ULONG cbprop = 0;
  2959. switch (pv->vt)
  2960. {
  2961. default:
  2962. case VT_EMPTY:
  2963. case VT_NULL:
  2964. break;
  2965. case VT_UI1:
  2966. cbprop = sizeof(pv->bVal);
  2967. break;
  2968. case VT_I2:
  2969. case VT_UI2:
  2970. case VT_BOOL:
  2971. cbprop = sizeof(pv->iVal);
  2972. break;
  2973. case VT_I4:
  2974. case VT_UI4:
  2975. case VT_R4:
  2976. case VT_ERROR:
  2977. cbprop = sizeof(pv->lVal);
  2978. break;
  2979. case VT_I8:
  2980. case VT_UI8:
  2981. case VT_R8:
  2982. case VT_CY:
  2983. case VT_DATE:
  2984. case VT_FILETIME:
  2985. cbprop = sizeof(pv->hVal);
  2986. break;
  2987. case VT_CLSID:
  2988. cbprop = sizeof(*pv->puuid);
  2989. break;
  2990. case VT_BLOB_OBJECT:
  2991. case VT_BLOB:
  2992. cbprop = pv->blob.cbSize + sizeof(pv->blob.cbSize);
  2993. break;
  2994. case VT_CF:
  2995. cbprop = sizeof(pv->pclipdata->cbSize) +
  2996. pv->pclipdata->cbSize;
  2997. break;
  2998. case VT_BSTR:
  2999. // count + string
  3000. cbprop = sizeof(ULONG);
  3001. if (pv->bstrVal != NULL)
  3002. {
  3003. cbprop += BSTRLEN(pv->bstrVal);
  3004. }
  3005. break;
  3006. case VT_LPSTR:
  3007. // count + string + null char
  3008. cbprop = sizeof(ULONG);
  3009. if (pv->pszVal != NULL)
  3010. {
  3011. cbprop += strlen(pv->pszVal) + 1;
  3012. }
  3013. break;
  3014. case VT_STREAM:
  3015. case VT_STREAMED_OBJECT:
  3016. case VT_STORAGE:
  3017. case VT_STORED_OBJECT:
  3018. case VT_LPWSTR:
  3019. // count + string + null char
  3020. cbprop = sizeof(ULONG);
  3021. if (pv->pwszVal != NULL)
  3022. {
  3023. cbprop += sizeof(pv->pwszVal[0]) * (wcslen(pv->pwszVal) + 1);
  3024. }
  3025. break;
  3026. // vectors
  3027. case VT_VECTOR | VT_UI1:
  3028. cbprop = sizeof(pv->caub.cElems) +
  3029. pv->caub.cElems * sizeof(pv->caub.pElems[0]);
  3030. break;
  3031. case VT_VECTOR | VT_I2:
  3032. case VT_VECTOR | VT_UI2:
  3033. case VT_VECTOR | VT_BOOL:
  3034. cbprop = sizeof(pv->cai.cElems) +
  3035. pv->cai.cElems * sizeof(pv->cai.pElems[0]);
  3036. break;
  3037. case VT_VECTOR | VT_I4:
  3038. case VT_VECTOR | VT_UI4:
  3039. case VT_VECTOR | VT_R4:
  3040. case VT_VECTOR | VT_ERROR:
  3041. cbprop = sizeof(pv->cal.cElems) +
  3042. pv->cal.cElems * sizeof(pv->cal.pElems[0]);
  3043. break;
  3044. case VT_VECTOR | VT_I8:
  3045. case VT_VECTOR | VT_UI8:
  3046. case VT_VECTOR | VT_R8:
  3047. case VT_VECTOR | VT_CY:
  3048. case VT_VECTOR | VT_DATE:
  3049. case VT_VECTOR | VT_FILETIME:
  3050. cbprop = sizeof(pv->cah.cElems) +
  3051. pv->cah.cElems * sizeof(pv->cah.pElems[0]);
  3052. break;
  3053. case VT_VECTOR | VT_CLSID:
  3054. cbprop = sizeof(pv->cauuid.cElems) +
  3055. pv->cauuid.cElems * sizeof(pv->cauuid.pElems[0]);
  3056. break;
  3057. case VT_VECTOR | VT_CF:
  3058. cbprop = sizeof(pv->caclipdata.cElems);
  3059. for (j = 0; j < pv->caclipdata.cElems; j++)
  3060. {
  3061. cbprop += sizeof(pv->caclipdata.pElems[j].cbSize) +
  3062. DwordAlign(pv->caclipdata.pElems[j].cbSize);
  3063. }
  3064. break;
  3065. case VT_VECTOR | VT_BSTR:
  3066. cbprop = sizeof(pv->cabstr.cElems);
  3067. for (j = 0; j < pv->cabstr.cElems; j++)
  3068. {
  3069. // count + string + null char
  3070. cbprop += sizeof(ULONG);
  3071. if (pv->cabstr.pElems[j] != NULL)
  3072. {
  3073. cbprop += DwordAlign(BSTRLEN(pv->cabstr.pElems[j]));
  3074. }
  3075. }
  3076. break;
  3077. case VT_VECTOR | VT_LPSTR:
  3078. cbprop = sizeof(pv->calpstr.cElems);
  3079. for (j = 0; j < pv->calpstr.cElems; j++)
  3080. {
  3081. // count + string + null char
  3082. cbprop += sizeof(ULONG);
  3083. if (pv->calpstr.pElems[j] != NULL)
  3084. {
  3085. cbprop += DwordAlign(strlen(pv->calpstr.pElems[j]) + 1);
  3086. }
  3087. }
  3088. break;
  3089. case VT_VECTOR | VT_LPWSTR:
  3090. cbprop = sizeof(pv->calpwstr.cElems);
  3091. for (j = 0; j < pv->calpwstr.cElems; j++)
  3092. {
  3093. // count + string + null char
  3094. cbprop += sizeof(ULONG);
  3095. if (pv->calpwstr.pElems[j] != NULL)
  3096. {
  3097. cbprop += DwordAlign(
  3098. sizeof(pv->calpwstr.pElems[j][0]) *
  3099. (wcslen(pv->calpwstr.pElems[j]) + 1));
  3100. }
  3101. }
  3102. break;
  3103. case VT_VECTOR | VT_VARIANT:
  3104. cbprop = sizeof(pv->calpwstr.cElems);
  3105. for (j = 0; j < pv->calpwstr.cElems; j++)
  3106. {
  3107. cbprop += SizeProp(&pv->capropvar.pElems[j]);
  3108. }
  3109. break;
  3110. }
  3111. return(DwordAlign(cbprop) + DwordAlign(sizeof(pv->vt)));
  3112. }
  3113. PUBLICPROPSET
  3114. GuidToPropSet(GUID *pguid)
  3115. {
  3116. PUBLICPROPSET pubps = PUBPS_UNKNOWN;
  3117. if (pguid != NULL)
  3118. {
  3119. if (memcmp(pguid, &FMTID_SummaryInformation, sizeof(GUID)) == 0)
  3120. {
  3121. pubps = PUBPS_SUMMARYINFO;
  3122. }
  3123. else if (memcmp(pguid, &FMTID_DocSummaryInformation, sizeof(GUID)) == 0)
  3124. {
  3125. pubps = PUBPS_DOCSUMMARYINFO;
  3126. }
  3127. else if (memcmp(pguid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0)
  3128. {
  3129. pubps = PUBPS_USERDEFINED;
  3130. }
  3131. }
  3132. return(pubps);
  3133. }
  3134. char
  3135. PrintableChar(char ch)
  3136. {
  3137. if (ch < ' ' || ch > '~')
  3138. {
  3139. ch = '.';
  3140. }
  3141. return(ch);
  3142. }
  3143. VOID
  3144. DumpHex(BYTE *pb, ULONG cb, ULONG base)
  3145. {
  3146. char *pszsep;
  3147. ULONG r, i, cbremain;
  3148. int fZero = FALSE;
  3149. int fSame = FALSE;
  3150. for (r = 0; r < cb; r += 16)
  3151. {
  3152. cbremain = cb - r;
  3153. if (r != 0 && cbremain >= 16)
  3154. {
  3155. if (pb[r] == 0)
  3156. {
  3157. ULONG j;
  3158. for (j = r + 1; j < cb; j++)
  3159. {
  3160. if (pb[j] != 0)
  3161. {
  3162. break;
  3163. }
  3164. }
  3165. if (j == cb)
  3166. {
  3167. fZero = TRUE;
  3168. break;
  3169. }
  3170. }
  3171. if (memcmp(&pb[r], &pb[r - 16], 16) == 0)
  3172. {
  3173. fSame = TRUE;
  3174. continue;
  3175. }
  3176. }
  3177. if (fSame)
  3178. {
  3179. printf("\n\t *");
  3180. fSame = FALSE;
  3181. }
  3182. unsigned int iLimit = (cbremain > 16) ? 16 : cbremain;
  3183. for (i = 0; i < iLimit; i++)
  3184. {
  3185. pszsep = " ";
  3186. if ((i % 8) == 0) // 0 or 8
  3187. {
  3188. pszsep = " ";
  3189. if (i == 0) // 0
  3190. {
  3191. // start a new line
  3192. printf("%s %04x:", r == 0? "" : "\n", r + base);
  3193. pszsep = " ";
  3194. }
  3195. }
  3196. printf("%s%02x", pszsep, pb[r + i]);
  3197. }
  3198. if (i != 0)
  3199. {
  3200. printf("%*s", 3 + (16 - i)*3 + ((i <= 8)? 1 : 0), "");
  3201. for (i = 0; i < iLimit; i++)
  3202. {
  3203. printf("%c", PrintableChar(pb[r + i]));
  3204. }
  3205. }
  3206. }
  3207. if (r != 0)
  3208. {
  3209. printf("\n");
  3210. }
  3211. if (fZero)
  3212. {
  3213. printf(" Remaining %lx bytes are zero\n", cbremain);
  3214. }
  3215. }
  3216. // Property Id's for Summary Info
  3217. #define PID_TITLE 0x00000002L // VT_LPSTR
  3218. #define PID_SUBJECT 0x00000003L // VT_LPSTR
  3219. #define PID_AUTHOR 0x00000004L // VT_LPSTR
  3220. #define PID_KEYWORDS 0x00000005L // VT_LPSTR
  3221. #define PID_COMMENTS 0x00000006L // VT_LPSTR
  3222. #define PID_TEMPLATE 0x00000007L // VT_LPSTR
  3223. #define PID_LASTAUTHOR 0x00000008L // VT_LPSTR
  3224. #define PID_REVNUMBER 0x00000009L // VT_LPSTR
  3225. #define PID_EDITTIME 0x0000000aL // VT_FILETIME
  3226. #define PID_LASTPRINTED 0x0000000bL // VT_FILETIME
  3227. #define PID_CREATE_DTM 0x0000000cL // VT_FILETIME
  3228. #define PID_LASTSAVE_DTM 0x0000000dL // VT_FILETIME
  3229. #define PID_PAGECOUNT 0x0000000eL // VT_I4
  3230. #define PID_WORDCOUNT 0x0000000fL // VT_I4
  3231. #define PID_CHARCOUNT 0x00000010L // VT_I4
  3232. #define PID_THUMBNAIL 0x00000011L // VT_CF
  3233. #define PID_APPNAME 0x00000012L // VT_LPSTR
  3234. #define PID_SECURITY_DSI 0x00000013L // VT_I4
  3235. // Property Id's for Document Summary Info
  3236. #define PID_CATEGORY 0x00000002L // VT_LPSTR
  3237. #define PID_PRESFORMAT 0x00000003L // VT_LPSTR
  3238. #define PID_BYTECOUNT 0x00000004L // VT_I4
  3239. #define PID_LINECOUNT 0x00000005L // VT_I4
  3240. #define PID_PARACOUNT 0x00000006L // VT_I4
  3241. #define PID_SLIDECOUNT 0x00000007L // VT_I4
  3242. #define PID_NOTECOUNT 0x00000008L // VT_I4
  3243. #define PID_HIDDENCOUNT 0x00000009L // VT_I4
  3244. #define PID_MMCLIPCOUNT 0x0000000aL // VT_I4
  3245. #define PID_SCALE 0x0000000bL // VT_BOOL
  3246. #define PID_HEADINGPAIR 0x0000000cL // VT_VECTOR | VT_VARIANT
  3247. #define PID_DOCPARTS 0x0000000dL // VT_VECTOR | VT_LPSTR
  3248. #define PID_MANAGER 0x0000000eL // VT_LPSTR
  3249. #define PID_COMPANY 0x0000000fL // VT_LPSTR
  3250. #define PID_LINKSDIRTY 0x00000010L // VT_BOOL
  3251. #define PID_CCHWITHSPACES 0x00000011L // VT_I4
  3252. #define PID_GUID 0x00000012L // VT_LPSTR
  3253. #define PID_SHAREDDOC 0x00000013L // VT_BOOL
  3254. #define PID_LINKBASE 0x00000014L // VT_LPSTR
  3255. #define PID_HLINKS 0x00000015L // VT_VECTOR | VT_VARIANT
  3256. #define PID_HYPERLINKSCHANGED 0x00000016L // VT_BOOL
  3257. VOID
  3258. DisplayProps(
  3259. GUID *pguid,
  3260. ULONG cprop,
  3261. PROPID apid[],
  3262. STATPROPSTG asps[],
  3263. FULLPROPSPEC afps[],
  3264. PROPVARIANT *av,
  3265. BOOLEAN fsumcat,
  3266. ULONG *pcbprop)
  3267. {
  3268. PROPVARIANT *pv;
  3269. PROPVARIANT *pvend;
  3270. STATPROPSTG *psps;
  3271. FULLPROPSPEC *pfps, *pfpsLast = NULL;
  3272. BOOLEAN fVariantVector;
  3273. PUBLICPROPSET pubps;
  3274. DECLARE_OLESTR(ocsNull,"");
  3275. ASSERT(asps == NULL || afps == NULL);
  3276. fVariantVector = (asps == NULL && afps == NULL);
  3277. pubps = GuidToPropSet(pguid);
  3278. pvend = &av[cprop];
  3279. for (pv = av, psps = asps, pfps = afps; pv < pvend; pv++, psps++, pfps++)
  3280. {
  3281. ULONG j;
  3282. ULONG cbprop;
  3283. PROPID propid;
  3284. OLECHAR *postrName;
  3285. char *psz;
  3286. BOOLEAN fNewLine = TRUE;
  3287. int ccol;
  3288. static char szNoFormat[] = " (no display format)";
  3289. char achvt[19 + 8 + 1];
  3290. cbprop = SizeProp(pv);
  3291. *pcbprop += cbprop;
  3292. postrName = NULL;
  3293. if (asps != NULL)
  3294. {
  3295. propid = psps->propid;
  3296. postrName = psps->lpwstrName;
  3297. }
  3298. else if (afps != NULL) // If multiple propsets are possible
  3299. {
  3300. if (pfpsLast == NULL || // print unique GUIDs only
  3301. memcmp(
  3302. &pfps->guidPropSet,
  3303. &pfpsLast->guidPropSet,
  3304. sizeof(pfps->guidPropSet)) != 0)
  3305. {
  3306. OLECHAR oszStream[80];
  3307. printf("%s Guid: ", pfpsLast == NULL? "" : "\n");
  3308. PrintGuid(&pfps->guidPropSet);
  3309. pubps = GuidToPropSet(&pfps->guidPropSet);
  3310. RtlGuidToPropertySetName(&pfps->guidPropSet, oszStream);
  3311. printf( " Name: " );
  3312. PrintOC(oszStream);
  3313. printf( "%s", pubps == PUBPS_USERDEFINED?
  3314. g_szEmpty : " (User defined properties)");
  3315. pfpsLast = pfps;
  3316. }
  3317. if (pfps->psProperty.ulKind == PRSPEC_PROPID)
  3318. {
  3319. propid = pfps->psProperty.propid;
  3320. }
  3321. else
  3322. {
  3323. propid = PID_ILLEGAL;
  3324. postrName = pfps->psProperty.lpwstr;
  3325. }
  3326. }
  3327. else
  3328. {
  3329. ASSERT(apid != NULL);
  3330. propid = apid[0];
  3331. }
  3332. printf(" ");
  3333. ccol = 0;
  3334. if (propid != PID_ILLEGAL)
  3335. {
  3336. printf(" %04x", propid);
  3337. ccol += 5;
  3338. if (propid & (0xf << 28))
  3339. {
  3340. ccol += 4;
  3341. }
  3342. else if (propid & (0xf << 24))
  3343. {
  3344. ccol += 3;
  3345. }
  3346. else if (propid & (0xf << 20))
  3347. {
  3348. ccol += 2;
  3349. }
  3350. else if (propid & (0xf << 16))
  3351. {
  3352. ccol++;
  3353. }
  3354. }
  3355. if (postrName != NULL)
  3356. {
  3357. printf(" '");
  3358. PrintOC(postrName);
  3359. printf("' ");
  3360. ccol += ocslen(postrName) + 3;
  3361. }
  3362. else if (fVariantVector)
  3363. {
  3364. ULONG i = pv - av;
  3365. printf("[%x]", i);
  3366. do
  3367. {
  3368. ccol++;
  3369. i >>= 4;
  3370. } while (i != 0);
  3371. ccol += 2;
  3372. }
  3373. else
  3374. {
  3375. psz = NULL;
  3376. switch (propid)
  3377. {
  3378. case PID_LOCALE: psz = "Locale"; break;
  3379. case PID_SECURITY: psz = "SecurityId"; break;
  3380. case PID_MODIFY_TIME: psz = "ModifyTime"; break;
  3381. case PID_CODEPAGE: psz = "CodePage"; break;
  3382. case PID_DICTIONARY: psz = "Dictionary"; break;
  3383. }
  3384. if (psz == NULL)
  3385. switch (pubps)
  3386. {
  3387. case PUBPS_SUMMARYINFO:
  3388. switch (propid)
  3389. {
  3390. case PID_TITLE: psz = "Title"; break;
  3391. case PID_SUBJECT: psz = "Subject"; break;
  3392. case PID_AUTHOR: psz = "Author"; break;
  3393. case PID_KEYWORDS: psz = "Keywords"; break;
  3394. case PID_COMMENTS: psz = "Comments"; break;
  3395. case PID_TEMPLATE: psz = "Template"; break;
  3396. case PID_LASTAUTHOR: psz = "LastAuthor"; break;
  3397. case PID_REVNUMBER: psz = "RevNumber"; break;
  3398. case PID_EDITTIME: psz = "EditTime"; break;
  3399. case PID_LASTPRINTED: psz = "LastPrinted"; break;
  3400. case PID_CREATE_DTM: psz = "CreateDateTime"; break;
  3401. case PID_LASTSAVE_DTM: psz = "LastSaveDateTime";break;
  3402. case PID_PAGECOUNT: psz = "PageCount"; break;
  3403. case PID_WORDCOUNT: psz = "WordCount"; break;
  3404. case PID_CHARCOUNT: psz = "CharCount"; break;
  3405. case PID_THUMBNAIL: psz = "ThumbNail"; break;
  3406. case PID_APPNAME: psz = "AppName"; break;
  3407. case PID_DOC_SECURITY: psz = "Security"; break;
  3408. }
  3409. break;
  3410. case PUBPS_DOCSUMMARYINFO:
  3411. switch (propid)
  3412. {
  3413. case PID_CATEGORY: psz = "Category"; break;
  3414. case PID_PRESFORMAT: psz = "PresFormat"; break;
  3415. case PID_BYTECOUNT: psz = "ByteCount"; break;
  3416. case PID_LINECOUNT: psz = "LineCount"; break;
  3417. case PID_PARACOUNT: psz = "ParaCount"; break;
  3418. case PID_SLIDECOUNT: psz = "SlideCount"; break;
  3419. case PID_NOTECOUNT: psz = "NoteCount"; break;
  3420. case PID_HIDDENCOUNT: psz = "HiddenCount"; break;
  3421. case PID_MMCLIPCOUNT: psz = "MmClipCount"; break;
  3422. case PID_SCALE: psz = "Scale"; break;
  3423. case PID_HEADINGPAIR: psz = "HeadingPair"; break;
  3424. case PID_DOCPARTS: psz = "DocParts"; break;
  3425. case PID_MANAGER: psz = "Manager"; break;
  3426. case PID_COMPANY: psz = "Company"; break;
  3427. case PID_LINKSDIRTY: psz = "LinksDirty"; break;
  3428. case PID_CCHWITHSPACES: psz = "CchWithSpaces"; break;
  3429. case PID_GUID: psz = "Guid"; break;
  3430. case PID_SHAREDDOC: psz = "SharedDoc"; break;
  3431. case PID_LINKBASE: psz = "LinkBase"; break;
  3432. case PID_HLINKS: psz = "HLinks"; break;
  3433. case PID_HYPERLINKSCHANGED: psz = "HyperLinksChanged";break;
  3434. }
  3435. break;
  3436. }
  3437. if (psz != NULL)
  3438. {
  3439. printf(" %s", psz);
  3440. ccol += strlen(psz) + 1;
  3441. }
  3442. }
  3443. #define CCOLPROPID 20
  3444. if (ccol != CCOLPROPID)
  3445. {
  3446. if (ccol > CCOLPROPID)
  3447. {
  3448. ccol = -1;
  3449. }
  3450. printf("%s%*s", ccol == -1? "\n" : "", CCOLPROPID - ccol, "");
  3451. }
  3452. printf(" %08x %04x %04x ", propid, cbprop, pv->vt);
  3453. psz = "";
  3454. switch (pv->vt)
  3455. {
  3456. default:
  3457. psz = achvt;
  3458. sprintf(psz, "Unknown (vt = %hx)", pv->vt);
  3459. break;
  3460. case VT_EMPTY:
  3461. printf("EMPTY");
  3462. break;
  3463. case VT_NULL:
  3464. printf("NULL");
  3465. break;
  3466. case VT_UI1:
  3467. printf("UI1 = %02lx", pv->bVal);
  3468. psz = "";
  3469. break;
  3470. case VT_I2:
  3471. psz = "I2";
  3472. goto doshort;
  3473. case VT_UI2:
  3474. psz = "UI2";
  3475. goto doshort;
  3476. case VT_BOOL:
  3477. psz = "BOOL";
  3478. doshort:
  3479. printf("%s = %04hx", psz, pv->iVal);
  3480. psz = g_szEmpty;
  3481. break;
  3482. case VT_I4:
  3483. psz = "I4";
  3484. goto dolong;
  3485. case VT_UI4:
  3486. psz = "UI4";
  3487. goto dolong;
  3488. case VT_R4:
  3489. psz = "R4";
  3490. goto dolong;
  3491. case VT_ERROR:
  3492. psz = "ERROR";
  3493. dolong:
  3494. printf("%s = %08lx", psz, pv->lVal);
  3495. psz = g_szEmpty;
  3496. break;
  3497. case VT_I8:
  3498. psz = "I8";
  3499. goto dotwodword;
  3500. case VT_UI8:
  3501. psz = "UI8";
  3502. dotwodword:
  3503. printf( "%s = %08lx:%08lx",
  3504. psz,
  3505. pv->hVal.HighPart,
  3506. pv->hVal.LowPart );
  3507. psz = g_szEmpty;
  3508. break;
  3509. case VT_R8:
  3510. psz = "R8";
  3511. goto dolonglong;
  3512. case VT_CY:
  3513. psz = "R8";
  3514. goto dolonglong;
  3515. case VT_DATE:
  3516. psz = "R8";
  3517. dolonglong:
  3518. printf(
  3519. "%s = %08lx:%08lx",
  3520. psz,
  3521. (pv->cyVal).split.Hi,
  3522. (pv->cyVal).split.Lo);
  3523. psz = g_szEmpty;
  3524. break;
  3525. case VT_FILETIME:
  3526. DumpTime("FILETIME =\n\t ", &pv->filetime);
  3527. fNewLine = FALSE; // skip newline printf
  3528. break;
  3529. case VT_CLSID:
  3530. printf("CLSID =\n\t ");
  3531. PrintGuid(pv->puuid);
  3532. break;
  3533. case VT_BLOB:
  3534. psz = "BLOB";
  3535. goto doblob;
  3536. case VT_BLOB_OBJECT:
  3537. psz = "BLOB_OBJECT";
  3538. doblob:
  3539. printf("%s (cbSize %x)", psz, pv->blob.cbSize);
  3540. if (pv->blob.cbSize != 0)
  3541. {
  3542. printf(" =\n");
  3543. DumpHex(pv->blob.pBlobData, pv->blob.cbSize, 0);
  3544. }
  3545. psz = g_szEmpty;
  3546. break;
  3547. case VT_CF:
  3548. printf(
  3549. "CF (cbSize %x, ulClipFmt %x)\n",
  3550. pv->pclipdata->cbSize,
  3551. pv->pclipdata->ulClipFmt);
  3552. DumpHex(pv->pclipdata->pClipData,
  3553. pv->pclipdata->cbSize - sizeof(pv->pclipdata->ulClipFmt),
  3554. 0);
  3555. break;
  3556. case VT_STREAM:
  3557. psz = "STREAM";
  3558. goto dostring;
  3559. case VT_STREAMED_OBJECT:
  3560. psz = "STREAMED_OBJECT";
  3561. goto dostring;
  3562. case VT_STORAGE:
  3563. psz = "STORAGE";
  3564. goto dostring;
  3565. case VT_STORED_OBJECT:
  3566. psz = "STORED_OBJECT";
  3567. goto dostring;
  3568. case VT_BSTR:
  3569. printf(
  3570. "BSTR (cb = %04lx)%s\n",
  3571. pv->bstrVal == NULL? 0 : BSTRLEN(pv->bstrVal),
  3572. pv->bstrVal == NULL? " NULL" : g_szEmpty);
  3573. if (pv->bstrVal != NULL)
  3574. {
  3575. DumpHex(
  3576. (BYTE *) pv->bstrVal,
  3577. BSTRLEN(pv->bstrVal) + sizeof(WCHAR),
  3578. 0);
  3579. }
  3580. break;
  3581. case VT_LPSTR:
  3582. psz = "LPSTR";
  3583. printf(
  3584. "%s = %s%s%s",
  3585. psz,
  3586. pv->pszVal == NULL? g_szEmpty : "'",
  3587. pv->pszVal == NULL? "NULL" : pv->pszVal,
  3588. pv->pszVal == NULL? g_szEmpty : "'");
  3589. psz = g_szEmpty;
  3590. break;
  3591. case VT_LPWSTR:
  3592. psz = "LPWSTR";
  3593. dostring:
  3594. printf(
  3595. "%s = %s",
  3596. psz,
  3597. pv->pwszVal == NULL? g_szEmpty : "'");
  3598. if ( pv->pwszVal == NULL)
  3599. printf("NULL");
  3600. else
  3601. PrintOC(pv->pwszVal);
  3602. printf("%s", pv->pwszVal == NULL? g_szEmpty : "'");
  3603. psz = g_szEmpty;
  3604. break;
  3605. // vectors
  3606. case VT_VECTOR | VT_UI1:
  3607. printf("UI1[%x] =", pv->caub.cElems);
  3608. for (j = 0; j < pv->caub.cElems; j++)
  3609. {
  3610. if ((j % 16) == 0)
  3611. {
  3612. printf("\n %02hx:", j);
  3613. }
  3614. printf(" %02hx", pv->caub.pElems[j]);
  3615. }
  3616. break;
  3617. case VT_VECTOR | VT_I2:
  3618. psz = "I2";
  3619. goto doshortvector;
  3620. case VT_VECTOR | VT_UI2:
  3621. psz = "UI2";
  3622. goto doshortvector;
  3623. case VT_VECTOR | VT_BOOL:
  3624. psz = "BOOL";
  3625. doshortvector:
  3626. printf("%s[%x] =", psz, pv->cai.cElems);
  3627. for (j = 0; j < pv->cai.cElems; j++)
  3628. {
  3629. if ((j % 8) == 0)
  3630. {
  3631. printf("\n %04hx:", j);
  3632. }
  3633. printf(" %04hx", pv->cai.pElems[j]);
  3634. }
  3635. psz = g_szEmpty;
  3636. break;
  3637. case VT_VECTOR | VT_I4:
  3638. psz = "I4";
  3639. goto dolongvector;
  3640. case VT_VECTOR | VT_UI4:
  3641. psz = "UI4";
  3642. goto dolongvector;
  3643. case VT_VECTOR | VT_R4:
  3644. psz = "R4";
  3645. goto dolongvector;
  3646. case VT_VECTOR | VT_ERROR:
  3647. psz = "ERROR";
  3648. dolongvector:
  3649. printf("%s[%x] =", psz, pv->cal.cElems);
  3650. for (j = 0; j < pv->cal.cElems; j++)
  3651. {
  3652. if ((j % 4) == 0)
  3653. {
  3654. printf("\n %04x:", j);
  3655. }
  3656. printf(" %08lx", pv->cal.pElems[j]);
  3657. }
  3658. psz = g_szEmpty;
  3659. break;
  3660. case VT_VECTOR | VT_I8:
  3661. psz = "I8";
  3662. goto dolonglongvector;
  3663. case VT_VECTOR | VT_UI8:
  3664. psz = "UI8";
  3665. goto dolonglongvector;
  3666. case VT_VECTOR | VT_R8:
  3667. psz = "R8";
  3668. goto dolonglongvector;
  3669. case VT_VECTOR | VT_CY:
  3670. psz = "CY";
  3671. goto dolonglongvector;
  3672. case VT_VECTOR | VT_DATE:
  3673. psz = "DATE";
  3674. dolonglongvector:
  3675. printf("%s[%x] =", psz, pv->cah.cElems);
  3676. for (j = 0; j < pv->cah.cElems; j++)
  3677. {
  3678. if ((j % 2) == 0)
  3679. {
  3680. printf("\n %04x:", j);
  3681. }
  3682. printf(
  3683. " %08lx:%08lx",
  3684. pv->cah.pElems[j].HighPart,
  3685. pv->cah.pElems[j].LowPart);
  3686. }
  3687. psz = g_szEmpty;
  3688. break;
  3689. case VT_VECTOR | VT_FILETIME:
  3690. printf("FILETIME[%x] =\n", pv->cafiletime.cElems);
  3691. for (j = 0; j < pv->cafiletime.cElems; j++)
  3692. {
  3693. printf(" %04x: ", j);
  3694. DumpTime(ocsNull, &pv->cafiletime.pElems[j]);
  3695. }
  3696. fNewLine = FALSE; // skip newline printf
  3697. break;
  3698. case VT_VECTOR | VT_CLSID:
  3699. printf("CLSID[%x] =", pv->cauuid.cElems);
  3700. for (j = 0; j < pv->cauuid.cElems; j++)
  3701. {
  3702. printf("\n %04x: ", j);
  3703. PrintGuid(&pv->cauuid.pElems[j]);
  3704. }
  3705. break;
  3706. case VT_VECTOR | VT_CF:
  3707. printf("CF[%x] =", pv->caclipdata.cElems);
  3708. for (j = 0; j < pv->caclipdata.cElems; j++)
  3709. {
  3710. printf("\n %04x: (cbSize %x, ulClipFmt %x) =\n",
  3711. j,
  3712. pv->caclipdata.pElems[j].cbSize,
  3713. pv->caclipdata.pElems[j].ulClipFmt);
  3714. DumpHex(
  3715. pv->caclipdata.pElems[j].pClipData,
  3716. pv->caclipdata.pElems[j].cbSize - sizeof(pv->caclipdata.pElems[j].ulClipFmt),
  3717. 0);
  3718. }
  3719. break;
  3720. case VT_VECTOR | VT_BSTR:
  3721. printf("BSTR[%x] =", pv->cabstr.cElems);
  3722. for (j = 0; j < pv->cabstr.cElems; j++)
  3723. {
  3724. BSTR bstr = pv->cabstr.pElems[j];
  3725. printf(
  3726. "\n %04x: cb = %04lx%s\n",
  3727. j,
  3728. bstr == NULL? 0 : BSTRLEN(pv->cabstr.pElems[j]),
  3729. bstr == NULL? " NULL" : g_szEmpty);
  3730. if (bstr != NULL)
  3731. {
  3732. DumpHex((BYTE *) bstr, BSTRLEN(bstr) + sizeof(WCHAR), 0);
  3733. }
  3734. }
  3735. break;
  3736. case VT_VECTOR | VT_LPSTR:
  3737. printf("LPSTR[%x] =", pv->calpstr.cElems);
  3738. for (j = 0; j < pv->calpstr.cElems; j++)
  3739. {
  3740. CHAR *psz = pv->calpstr.pElems[j];
  3741. printf(
  3742. "\n %04x: %s%s%s",
  3743. j,
  3744. psz == NULL? g_szEmpty : "'",
  3745. psz == NULL? "NULL" : psz,
  3746. psz == NULL? g_szEmpty : "'");
  3747. }
  3748. break;
  3749. case VT_VECTOR | VT_LPWSTR:
  3750. printf("LPWSTR[%x] =", pv->calpwstr.cElems);
  3751. for (j = 0; j < pv->calpwstr.cElems; j++)
  3752. {
  3753. WCHAR *pwsz = pv->calpwstr.pElems[j];
  3754. printf( "\n %04x: %s",
  3755. j, pv->pwszVal == NULL? g_szEmpty : "'");
  3756. if ( pwsz == NULL)
  3757. printf("NULL");
  3758. else
  3759. PrintOC(pwsz);
  3760. printf("%s", pwsz == NULL? g_szEmpty : "'");
  3761. }
  3762. break;
  3763. case VT_VECTOR | VT_VARIANT:
  3764. printf("VARIANT[%x] =\n", pv->capropvar.cElems);
  3765. DisplayProps(
  3766. pguid,
  3767. pv->capropvar.cElems,
  3768. &propid,
  3769. NULL,
  3770. NULL,
  3771. pv->capropvar.pElems,
  3772. fsumcat,
  3773. pcbprop);
  3774. fNewLine = FALSE; // skip newline printf
  3775. break;
  3776. }
  3777. if (*psz != '\0')
  3778. {
  3779. printf("%s", psz);
  3780. if (pv->vt & VT_VECTOR)
  3781. {
  3782. printf("[%x]", pv->cal.cElems);
  3783. }
  3784. printf("%s", szNoFormat);
  3785. }
  3786. if (!fVariantVector && apid != NULL && apid[pv - av] != propid)
  3787. {
  3788. printf(" (bad PROPID: %04x)", apid[pv - av]);
  3789. fNewLine = TRUE;
  3790. }
  3791. if (asps != NULL && pv->vt != psps->vt)
  3792. {
  3793. printf(" (bad STATPROPSTG VARTYPE: %04x)", psps->vt);
  3794. fNewLine = TRUE;
  3795. }
  3796. if (fNewLine)
  3797. {
  3798. printf("\n");
  3799. }
  3800. }
  3801. }
  3802. STATPROPSTG aspsStatic[] = {
  3803. { NULL, PID_CODEPAGE, VT_I2 },
  3804. { NULL, PID_MODIFY_TIME, VT_FILETIME },
  3805. { NULL, PID_SECURITY, VT_UI4 },
  3806. };
  3807. #define CPROPSTATIC (sizeof(aspsStatic)/sizeof(aspsStatic[0]))
  3808. #define CB_STREAM_OVERHEAD 28
  3809. #define CB_PROPSET_OVERHEAD (CB_STREAM_OVERHEAD + 8)
  3810. #define CB_PROP_OVERHEAD 8
  3811. HRESULT
  3812. DumpOlePropertySet(
  3813. IPropertySetStorage *ppsstg,
  3814. STATPROPSETSTG *pspss,
  3815. ULONG *pcprop,
  3816. ULONG *pcbprop)
  3817. {
  3818. HRESULT hr;
  3819. IEnumSTATPROPSTG *penumsps = NULL;
  3820. IPropertyStorage *pps;
  3821. ULONG cprop, cbpropset;
  3822. PROPID propid;
  3823. OLECHAR *poszName;
  3824. ULONG ispsStatic;
  3825. *pcprop = *pcbprop = 0;
  3826. hr = ppsstg->Open(
  3827. pspss->fmtid,
  3828. STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  3829. &pps);
  3830. if (FAILED(hr))
  3831. return (hr);
  3832. propid = PID_DICTIONARY;
  3833. hr = pps->ReadPropertyNames(1, &propid, &poszName);
  3834. if( S_FALSE == hr )
  3835. hr = S_OK;
  3836. Check( S_OK, hr );
  3837. ListPropSetHeader(pspss, poszName);
  3838. if (poszName != NULL)
  3839. {
  3840. CoTaskMemFree(poszName);
  3841. }
  3842. cprop = cbpropset = 0;
  3843. Check(S_OK, pps->Enum(&penumsps) );
  3844. ispsStatic = 0;
  3845. hr = S_OK;
  3846. while (hr == S_OK)
  3847. {
  3848. STATPROPSTG sps;
  3849. PROPSPEC propspec;
  3850. PROPVARIANT propvar;
  3851. ULONG count;
  3852. hr = S_FALSE;
  3853. if (ispsStatic == 0)
  3854. {
  3855. hr = penumsps->Next(1, &sps, &count);
  3856. }
  3857. if (hr != S_OK)
  3858. {
  3859. if (hr == S_FALSE)
  3860. {
  3861. hr = S_OK;
  3862. if (ispsStatic >= CPROPSTATIC)
  3863. {
  3864. break;
  3865. }
  3866. sps = aspsStatic[ispsStatic];
  3867. ispsStatic++;
  3868. count = 1;
  3869. }
  3870. Check( S_OK, hr );
  3871. }
  3872. PropVariantInit(&propvar);
  3873. if (sps.lpwstrName != NULL)
  3874. {
  3875. propspec.ulKind = PRSPEC_LPWSTR;
  3876. propspec.lpwstr = sps.lpwstrName;
  3877. }
  3878. else
  3879. {
  3880. propspec.ulKind = PRSPEC_PROPID;
  3881. propspec.propid = sps.propid;
  3882. }
  3883. hr = pps->ReadMultiple(1, &propspec, &propvar);
  3884. if (hr == S_FALSE)
  3885. {
  3886. if (g_fVerbose)
  3887. {
  3888. printf(
  3889. "%s(%u, %x) vt=%x returned hr=%x\n",
  3890. "IPropertyStorage::ReadMultiple",
  3891. ispsStatic,
  3892. propspec.propid,
  3893. propvar.vt,
  3894. hr);
  3895. }
  3896. ASSERT(propvar.vt == VT_EMPTY);
  3897. hr = S_OK;
  3898. }
  3899. Check( S_OK, hr );
  3900. if (ispsStatic == 0 || propvar.vt != VT_EMPTY)
  3901. {
  3902. ASSERT(count == 1);
  3903. cprop += count;
  3904. if (cprop == 1)
  3905. {
  3906. printf(g_szPropHeader);
  3907. }
  3908. DisplayProps(
  3909. &pspss->fmtid,
  3910. 1,
  3911. NULL,
  3912. &sps,
  3913. NULL,
  3914. &propvar,
  3915. FALSE,
  3916. &cbpropset);
  3917. PropVariantClear(&propvar);
  3918. }
  3919. if (sps.lpwstrName != NULL)
  3920. {
  3921. CoTaskMemFree(sps.lpwstrName);
  3922. }
  3923. }
  3924. if (penumsps != NULL)
  3925. {
  3926. penumsps->Release();
  3927. }
  3928. pps->Release();
  3929. if (cprop != 0)
  3930. {
  3931. cbpropset += CB_PROPSET_OVERHEAD + cprop * CB_PROP_OVERHEAD;
  3932. printf(" %04x bytes in %u properties\n\n", cbpropset, cprop);
  3933. }
  3934. *pcprop = cprop;
  3935. *pcbprop = cbpropset;
  3936. return(hr);
  3937. }
  3938. HRESULT
  3939. DumpOlePropertySets(
  3940. IStorage *pstg,
  3941. OLECHAR *aocpath)
  3942. {
  3943. HRESULT hr = S_OK;
  3944. IPropertySetStorage *ppsstg;
  3945. ULONG cbproptotal = 0;
  3946. ULONG cproptotal = 0;
  3947. ULONG cpropset = 0;
  3948. IID IIDpsstg = IID_IPropertySetStorage;
  3949. Check(S_OK, pstg->QueryInterface(IID_IPropertySetStorage, (void **) &ppsstg) );
  3950. {
  3951. IEnumSTATPROPSETSTG *penumspss = NULL;
  3952. Check(S_OK, ppsstg->Enum(&penumspss) );
  3953. while (hr == S_OK)
  3954. {
  3955. STATPROPSETSTG spss;
  3956. ULONG count;
  3957. BOOLEAN fDocumentSummarySection2;
  3958. hr = penumspss->Next(1, &spss, &count);
  3959. if (hr != S_OK)
  3960. {
  3961. if (hr == S_FALSE)
  3962. {
  3963. hr = S_OK;
  3964. }
  3965. Check( S_OK, hr );
  3966. break;
  3967. }
  3968. ASSERT(count == 1);
  3969. fDocumentSummarySection2 = FALSE;
  3970. while (TRUE)
  3971. {
  3972. ULONG cprop, cbprop;
  3973. HRESULT hr;
  3974. DumpOlePropertySet(
  3975. ppsstg,
  3976. &spss,
  3977. &cprop,
  3978. &cbprop);
  3979. if ( STG_E_FILENOTFOUND == hr
  3980. && fDocumentSummarySection2 )
  3981. {
  3982. hr = S_OK;
  3983. }
  3984. cpropset++;
  3985. cproptotal += cprop;
  3986. cbproptotal += cbprop;
  3987. if (memcmp(&spss.fmtid, &guidDocumentSummary, sizeof(GUID)))
  3988. {
  3989. break;
  3990. }
  3991. spss.fmtid = FMTID_UserDefinedProperties;
  3992. fDocumentSummarySection2 = TRUE;
  3993. }
  3994. }
  3995. if (penumspss != NULL)
  3996. {
  3997. penumspss->Release();
  3998. }
  3999. ppsstg->Release();
  4000. }
  4001. if ((cbproptotal | cproptotal | cpropset) != 0)
  4002. {
  4003. printf(
  4004. " %04x bytes in %u properties in %u property sets\n",
  4005. cbproptotal,
  4006. cproptotal,
  4007. cpropset);
  4008. }
  4009. return(hr);
  4010. }
  4011. inline ULONG min(ULONG ul1, ULONG ul2)
  4012. {
  4013. if (ul1 > ul2) return ul2;
  4014. else return ul1;
  4015. }
  4016. NTSTATUS
  4017. DumpOleStream(
  4018. LPSTREAM pstm,
  4019. ULONG cb)
  4020. {
  4021. ULONG cbTotal = 0;
  4022. while (TRUE)
  4023. {
  4024. ULONG cbOut;
  4025. BYTE ab[4096];
  4026. Check(S_OK, pstm->Read(ab, min(cb, sizeof(ab)), &cbOut) );
  4027. if (cbOut == 0)
  4028. {
  4029. break;
  4030. }
  4031. if (g_fVerbose)
  4032. {
  4033. DumpHex(ab, cbOut, cbTotal);
  4034. }
  4035. cb -= cbOut;
  4036. cbTotal += cbOut;
  4037. }
  4038. return(STATUS_SUCCESS);
  4039. }
  4040. VOID
  4041. DumpOleStorage(
  4042. IStorage *pstg,
  4043. LPOLESTR aocpath )
  4044. {
  4045. LPENUMSTATSTG penum;
  4046. STATSTG ss;
  4047. char *szType;
  4048. OLECHAR *pocChild;
  4049. HRESULT hr;
  4050. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  4051. Check( S_OK, DumpOlePropertySets(pstg, aocpath) );
  4052. Check( S_OK, pstg->EnumElements(0, NULL, 0, &penum) );
  4053. pocChild = &aocpath[ocslen(aocpath)];
  4054. // Continue enumeration until IEnumStatStg::Next returns non-S_OK
  4055. while (TRUE)
  4056. {
  4057. ULONG ulCount;
  4058. // Enumerate one element at a time
  4059. hr = penum->Next(1, &ss, &ulCount);
  4060. if( S_FALSE == hr )
  4061. break;
  4062. else
  4063. Check( S_OK, hr );
  4064. // Select the human-readable type of object to display
  4065. switch (ss.type)
  4066. {
  4067. case STGTY_STREAM: szType = "Stream"; break;
  4068. case STGTY_STORAGE: szType = "Storage"; break;
  4069. case STGTY_LOCKBYTES: szType = "LockBytes"; break;
  4070. case STGTY_PROPERTY: szType = "Property"; break;
  4071. default: szType = "<Unknown>"; break;
  4072. }
  4073. if (g_fVerbose)
  4074. {
  4075. printf(
  4076. "Type=%hs Size=%lx Mode=%lx LocksSupported=%lx StateBits=%lx",
  4077. szType,
  4078. ss.cbSize.LowPart,
  4079. ss.grfMode,
  4080. ss.grfLocksSupported,
  4081. ss.grfStateBits);
  4082. PrintOC(aocpath);
  4083. PrintOC(ss.pwcsName);
  4084. printf("\n");
  4085. printf("ss.clsid = ");
  4086. PrintGuid(&ss.clsid);
  4087. printf("\n");
  4088. }
  4089. // If a stream, output the data in hex format.
  4090. CoTaskMemFree(ss.pwcsName);
  4091. }
  4092. penum->Release();
  4093. return;
  4094. }
  4095. //+---------------------------------------------------------
  4096. //
  4097. // Function: MungePropertyStorage
  4098. //
  4099. // Synopsis: This routine munges the properties in a
  4100. // Property Storage. The values of the properties
  4101. // remain the same, but the underlying serialization
  4102. // is new (the properties are read, the property
  4103. // storage is deleted, and the properties are
  4104. // re-written).
  4105. //
  4106. // Inputs: [IPropertySetStorage*] ppropsetgstg (in)
  4107. // The Property Storage container.
  4108. // [FMTID] fmtid
  4109. // The Property Storage to munge.
  4110. //
  4111. // Returns: None.
  4112. //
  4113. // Note: Property names in the dictionary for which
  4114. // there is no property are not munged.
  4115. //
  4116. //+---------------------------------------------------------
  4117. #define MUNGE_PROPVARIANT_STEP 10
  4118. void
  4119. MungePropertyStorage( IPropertySetStorage *ppropsetstg,
  4120. FMTID fmtid )
  4121. {
  4122. // ------
  4123. // Locals
  4124. // ------
  4125. HRESULT hr;
  4126. ULONG celt, ulIndex;
  4127. TSafeStorage< IPropertyStorage > ppropstg;
  4128. IEnumSTATPROPSTG *penumstatpropstg=NULL;
  4129. PROPVARIANT *rgpropvar = NULL;
  4130. STATPROPSTG *rgstatpropstg = NULL;
  4131. ULONG cProperties = 0;
  4132. // Allocate an array of PropVariants. We may grow this later.
  4133. rgpropvar = (PROPVARIANT*) CoTaskMemAlloc( MUNGE_PROPVARIANT_STEP * sizeof(*rgpropvar) );
  4134. Check( FALSE, NULL == rgpropvar );
  4135. // Allocate an array of STATPROPSTGs. We may grow this also.
  4136. rgstatpropstg = (STATPROPSTG*) CoTaskMemAlloc( MUNGE_PROPVARIANT_STEP * sizeof(*rgstatpropstg) );
  4137. Check( FALSE, NULL == rgstatpropstg );
  4138. // -----------------
  4139. // Get an Enumerator
  4140. // -----------------
  4141. // Open the Property Storage. We may get an error if we're attempting
  4142. // the UserDefined propset. If it's file-not-found, then simply return,
  4143. // it's not an error, and there's nothing to do.
  4144. hr = ppropsetstg->Open( fmtid,
  4145. STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4146. &ppropstg );
  4147. if( FMTID_UserDefinedProperties == fmtid
  4148. &&
  4149. STG_E_FILENOTFOUND == hr )
  4150. {
  4151. goto Exit;
  4152. }
  4153. Check( S_OK, hr );
  4154. // Get an Enumerator
  4155. Check(S_OK, ppropstg->Enum( &penumstatpropstg ));
  4156. // --------------------------------------------
  4157. // Read & delete in all of the properties/names
  4158. // --------------------------------------------
  4159. // Get the first property from the enumerator
  4160. hr = penumstatpropstg->Next( 1, &rgstatpropstg[cProperties], &celt );
  4161. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4162. // Iterate through the properties.
  4163. while( celt > 0 )
  4164. {
  4165. PROPSPEC propspec;
  4166. propspec.ulKind = PRSPEC_PROPID;
  4167. propspec.propid = rgstatpropstg[cProperties].propid;
  4168. // Read and delete the property
  4169. Check(S_OK, ppropstg->ReadMultiple( 1, &propspec, &rgpropvar[cProperties] ));
  4170. Check(S_OK, ppropstg->DeleteMultiple( 1, &propspec ));
  4171. // If there is a property name, delete it also.
  4172. if( NULL != rgstatpropstg[cProperties].lpwstrName )
  4173. {
  4174. // We have a name.
  4175. Check(S_OK, ppropstg->DeletePropertyNames( 1, &rgstatpropstg[cProperties].propid ));
  4176. }
  4177. // Increment the property count.
  4178. cProperties++;
  4179. // Do we need to grow the arrays?
  4180. if( 0 != cProperties
  4181. &&
  4182. (cProperties % MUNGE_PROPVARIANT_STEP) == 0 )
  4183. {
  4184. // Yes - they must be reallocated.
  4185. rgpropvar = (PROPVARIANT*)
  4186. CoTaskMemRealloc( rgpropvar,
  4187. ( (cProperties + MUNGE_PROPVARIANT_STEP)
  4188. *
  4189. sizeof(*rgpropvar)
  4190. ));
  4191. Check( FALSE, NULL == rgpropvar );
  4192. rgstatpropstg = (STATPROPSTG*)
  4193. CoTaskMemRealloc( rgstatpropstg,
  4194. ( (cProperties + MUNGE_PROPVARIANT_STEP)
  4195. *
  4196. sizeof(*rgstatpropstg)
  4197. ));
  4198. Check( FALSE, NULL == rgstatpropstg );
  4199. }
  4200. // Move on to the next property.
  4201. hr = penumstatpropstg->Next( 1, &rgstatpropstg[cProperties], &celt );
  4202. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4203. } // while( celt > 0 )
  4204. // -------------------------------------
  4205. // Write the properties & names back out
  4206. // -------------------------------------
  4207. for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  4208. {
  4209. // Write the property.
  4210. PROPSPEC propspec;
  4211. propspec.ulKind = PRSPEC_PROPID;
  4212. propspec.propid = rgstatpropstg[ ulIndex ].propid;
  4213. Check(S_OK, ppropstg->WriteMultiple(1, &propspec, &rgpropvar[ulIndex], PID_FIRST_USABLE ));
  4214. // If this property has a name, write it too.
  4215. if( rgstatpropstg[ ulIndex ].lpwstrName != NULL )
  4216. {
  4217. Check(S_OK, ppropstg->WritePropertyNames(
  4218. 1,
  4219. &rgstatpropstg[ulIndex].propid,
  4220. &rgstatpropstg[ulIndex].lpwstrName ));
  4221. }
  4222. } // for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  4223. // ----
  4224. // Exit
  4225. // ----
  4226. Exit:
  4227. if( penumstatpropstg )
  4228. {
  4229. penumstatpropstg->Release();
  4230. penumstatpropstg = NULL;
  4231. }
  4232. // Free the PropVariants
  4233. if( rgpropvar )
  4234. {
  4235. FreePropVariantArray( cProperties, rgpropvar );
  4236. CoTaskMemFree( rgpropvar );
  4237. }
  4238. // Free the property names
  4239. if( rgstatpropstg )
  4240. {
  4241. for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  4242. {
  4243. if( NULL != rgstatpropstg[ ulIndex ].lpwstrName )
  4244. {
  4245. CoTaskMemFree( rgstatpropstg[ ulIndex ].lpwstrName );
  4246. }
  4247. } // for( ulIndex = 0; ulIndex < cProperties; ulIndex++ )
  4248. CoTaskMemFree( rgstatpropstg );
  4249. }
  4250. } // MungePropertyStorage
  4251. //+---------------------------------------------------------
  4252. //
  4253. // Function: MungeStorage
  4254. //
  4255. // Synopsis: This routine munges the property sets in a
  4256. // Storage. The properties themselves are not
  4257. // modified, but the serialized bytes are.
  4258. // For each property set, all the properties are
  4259. // read, the property set is deleted, and
  4260. // the properties are re-written.
  4261. //
  4262. // Inputs: [IStorage*] pstg (in)
  4263. // The Storage to munge.
  4264. //
  4265. // Returns: None.
  4266. //
  4267. // Note: This routine only munges simple property
  4268. // sets.
  4269. //
  4270. //+---------------------------------------------------------
  4271. void
  4272. MungeStorage( IStorage *pstg )
  4273. {
  4274. // ------
  4275. // Locals
  4276. // ------
  4277. HRESULT hr;
  4278. ULONG celt;
  4279. STATPROPSETSTG statpropsetstg;
  4280. STATSTG statstg;
  4281. TSafeStorage< IPropertySetStorage > ppropsetstg;
  4282. TSafeStorage< IPropertyStorage > ppropstg;
  4283. IEnumSTATPROPSETSTG *penumstatpropsetstg;
  4284. IEnumSTATSTG *penumstatstg;
  4285. // -----------------------------------------------
  4286. // Munge each of the property sets in this Storage
  4287. // -----------------------------------------------
  4288. // Get the IPropertySetStorage interface
  4289. Check(S_OK, pstg->QueryInterface( IID_IPropertySetStorage, (VOID**) &ppropsetstg ));
  4290. // Get a property storage enumerator
  4291. Check(S_OK, ppropsetstg->Enum( &penumstatpropsetstg ));
  4292. // Get the first STATPROPSETSTG
  4293. hr = penumstatpropsetstg->Next( 1, &statpropsetstg, &celt );
  4294. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4295. // Loop through the STATPROPSETSTGs.
  4296. while( celt > 0 )
  4297. {
  4298. // Is this a simple property storage (we don't
  4299. // handle non-simple sets)?
  4300. if( !(statpropsetstg.grfFlags & PROPSETFLAG_NONSIMPLE) )
  4301. {
  4302. // Munge the Property Storage.
  4303. MungePropertyStorage( ppropsetstg, statpropsetstg.fmtid );
  4304. }
  4305. // Get the next STATPROPSETSTG
  4306. // If we just did the first section of the DocSumInfo
  4307. // property set, then attempt the second section
  4308. if( FMTID_DocSummaryInformation == statpropsetstg.fmtid )
  4309. {
  4310. statpropsetstg.fmtid = FMTID_UserDefinedProperties;
  4311. }
  4312. else
  4313. {
  4314. hr = penumstatpropsetstg->Next( 1, &statpropsetstg, &celt );
  4315. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4316. }
  4317. }
  4318. // We're done with the Property Storage enumerator.
  4319. penumstatpropsetstg->Release();
  4320. penumstatpropsetstg = NULL;
  4321. // ------------------------------------------
  4322. // Recursively munge each of the sub-storages
  4323. // ------------------------------------------
  4324. // Get the IEnumSTATSTG enumerator
  4325. Check(S_OK, pstg->EnumElements( 0L, NULL, 0L, &penumstatstg ));
  4326. // Get the first STATSTG structure.
  4327. hr = penumstatstg->Next( 1, &statstg, &celt );
  4328. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4329. // Loop through the elements of this Storage.
  4330. while( celt > 0 )
  4331. {
  4332. // Is this a sub-Storage which must be
  4333. // munged?
  4334. if( STGTY_STORAGE & statstg.type // This is a Storage
  4335. &&
  4336. 0x20 <= *statstg.pwcsName ) // But not a system Storage.
  4337. {
  4338. // We'll munge it.
  4339. IStorage *psubstg;
  4340. // Open the sub-storage.
  4341. Check(S_OK, pstg->OpenStorage( statstg.pwcsName,
  4342. NULL,
  4343. STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
  4344. NULL,
  4345. 0L,
  4346. &psubstg ));
  4347. // Munge the sub-storage.
  4348. MungeStorage( psubstg );
  4349. psubstg->Release();
  4350. psubstg = NULL;
  4351. }
  4352. CoTaskMemFree(statstg.pwcsName);
  4353. // Move on to the next Storage element.
  4354. hr = penumstatstg->Next( 1, &statstg, &celt );
  4355. Check( TRUE, S_OK == hr || S_FALSE == hr );
  4356. }
  4357. penumstatstg->Release();
  4358. penumstatstg = NULL;
  4359. } // MungeStorage
  4360. void
  4361. DisplayUsage( LPSTR pszCommand )
  4362. {
  4363. printf("\n");
  4364. printf(" Usage: %s [[options] <test directory>] [file-commands]\n", pszCommand );
  4365. printf("\n");
  4366. printf(" The <test directory> is required in order to run tests, but is\n" );
  4367. printf(" not required for the file-commands.\n" );
  4368. printf("\n");
  4369. printf(" Options:\n" );
  4370. printf(" /w enables the Word 6 compatibility test\n");
  4371. printf(" /iw creates a file for interop test\n");
  4372. printf(" /ir verfies the file created for interop test\n" );
  4373. printf("\n");
  4374. printf(" File-commands:\n" );
  4375. printf(" /g<file> specifies a file to be munGed\n" );
  4376. printf(" (propsets are read, deleted, & re-written)\n" );
  4377. printf(" /d<file> specifies a file to be Dumped\n" );
  4378. printf(" (propsets are dumped to stdout)\n" );
  4379. printf("\n");
  4380. printf(" Examples:\n" );
  4381. printf(" %s c:\\test\n", pszCommand );
  4382. printf(" %s -iw c:\\test\n", pszCommand );
  4383. printf(" %s -dMyFile.doc\n", pszCommand );
  4384. printf(" %s -gMyFile.doc\n", pszCommand );
  4385. printf("\n");
  4386. return;
  4387. }
  4388. //
  4389. // Interoperability test
  4390. //
  4391. // test_interop_write writes in a doc file
  4392. // test_interop_read reads it in and verifies that it is right.
  4393. typedef struct tagInteropTest {
  4394. VARENUM vt;
  4395. void *pv;
  4396. } interopStruct;
  4397. const int cInteropPROPS=18;
  4398. static interopStruct
  4399. avtInterop[cInteropPROPS] = {
  4400. VT_LPSTR, "Title of the document.",
  4401. VT_LPSTR, "Subject of the document.",
  4402. VT_LPSTR, "Author of the document.",
  4403. VT_LPSTR, "Keywords of the document.",
  4404. VT_LPSTR, "Comments of the document.",
  4405. VT_LPSTR, "Normal.dot",
  4406. VT_LPSTR, "Mr. Unknown",
  4407. VT_LPSTR, "3",
  4408. VT_EMPTY, 0,
  4409. VT_EMPTY, 0,
  4410. VT_EMPTY, 0,
  4411. VT_EMPTY, 0,
  4412. VT_I4, (void*) 1,
  4413. VT_I4, (void*) 7,
  4414. VT_I4, (void*) 65,
  4415. VT_EMPTY, 0,
  4416. VT_LPSTR, "Reference",
  4417. VT_I4, (void*) 1121
  4418. };
  4419. void test_interop_write()
  4420. {
  4421. printf( " Interoperability - write \n" );
  4422. DECLARE_OLESTR(szFile, "t_interop");
  4423. IStorage *pStg;
  4424. Check(S_OK,
  4425. StgCreateDocfile(szFile,
  4426. STGM_CREATE| STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4427. (DWORD)NULL, &pStg));
  4428. TSafeStorage< IPropertySetStorage > pPropSetStg(pStg);
  4429. IPropertyStorage *pPropStg;
  4430. Check(S_OK, pPropSetStg->Create(FMTID_SummaryInformation, NULL, 0,
  4431. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READWRITE,
  4432. &pPropStg));
  4433. PROPSPEC propspec[cInteropPROPS+2];
  4434. int i;
  4435. for (i=2; i<cInteropPROPS+2; i++)
  4436. {
  4437. propspec[i].ulKind = PRSPEC_PROPID;
  4438. propspec[i].propid = (PROPID)i;
  4439. }
  4440. PROPVARIANT propvar[cInteropPROPS+2];
  4441. for (i=2; i<cInteropPROPS+2; i++)
  4442. {
  4443. propvar[i].vt = avtInterop[i-2].vt;
  4444. switch (avtInterop[i-2].vt)
  4445. {
  4446. case VT_LPSTR:
  4447. propvar[i].pszVal = (char*)avtInterop[i-2].pv;
  4448. break;
  4449. case VT_I4:
  4450. propvar[i].lVal = (int)avtInterop[i-2].pv;
  4451. break;
  4452. default:
  4453. break;
  4454. }
  4455. }
  4456. Check(S_OK,
  4457. pPropStg->WriteMultiple(cInteropPROPS, propspec+2,
  4458. propvar+2, 2) );
  4459. pPropStg->Release();
  4460. pStg->Release();
  4461. }
  4462. void test_interop_read()
  4463. {
  4464. printf( " Interoperability - read \n" );
  4465. DECLARE_OLESTR(szFile, "t_interop");
  4466. IStorage *pStg;
  4467. Check(S_OK, StgOpenStorage(szFile, NULL,
  4468. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStg));
  4469. TSafeStorage< IPropertySetStorage > pPropSetStg(pStg);
  4470. IPropertyStorage *pPropStg;
  4471. Check(S_OK, pPropSetStg->Open(FMTID_SummaryInformation,
  4472. STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_READ,
  4473. &pPropStg));
  4474. PROPSPEC propspec[cInteropPROPS+2];
  4475. int i;
  4476. for (i=2; i<cInteropPROPS+2; i++)
  4477. {
  4478. propspec[i].ulKind = PRSPEC_PROPID;
  4479. propspec[i].propid = (PROPID)i;
  4480. }
  4481. PROPVARIANT propvar[cInteropPROPS+2];
  4482. Check(S_OK, pPropStg->ReadMultiple(cInteropPROPS, propspec+2, propvar+2));
  4483. for (i=2; i<cInteropPROPS+2; i++)
  4484. {
  4485. if ( propvar[i].vt != avtInterop[i-2].vt )
  4486. {
  4487. printf( " PROPTEST: 0x%x retrieved type 0x%x, expected type 0x%x\n",
  4488. i, propvar[i].vt, avtInterop[i-2].vt );
  4489. ASSERT(propvar[i].vt == avtInterop[i-2].vt);
  4490. }
  4491. switch (propvar[i].vt)
  4492. {
  4493. case VT_LPSTR:
  4494. ASSERT(strcmp(propvar[i].pszVal, (char*)avtInterop[i-2].pv)==0);
  4495. break;
  4496. case VT_I4:
  4497. ASSERT(propvar[i].lVal == (int)avtInterop[i-2].pv);
  4498. break;
  4499. }
  4500. PropVariantClear(propvar+i);
  4501. }
  4502. pPropStg->Release();
  4503. pStg->Release();
  4504. }
  4505. void Cleanup()
  4506. {
  4507. ULONG ul;
  4508. // Clean up and exit.
  4509. if (_pstgTemp)
  4510. {
  4511. ul = _pstgTemp->Release();
  4512. assert(ul==0 && "_pstgTemp ref counting is wrong!");
  4513. }
  4514. if (_pstgTempCopyTo)
  4515. {
  4516. ul = _pstgTempCopyTo->Release();
  4517. assert( 0 == ul
  4518. && "_pstgTempCopyTo ref counting is wrong!");
  4519. }
  4520. }
  4521. int main(int argc, char *argv[])
  4522. {
  4523. int nArgIndex;
  4524. #ifndef _UNIX
  4525. INIT_OLESTR(oszSummary, "SummaryInformation");
  4526. INIT_OLESTR(aocMap, "abcdefghijklmnopqrstuvwxyz012345");
  4527. INIT_OLESTR( oszDocumentSummary, "DocumentSummaryInformation");
  4528. #endif
  4529. ULONG ulTestOptions = 0L;
  4530. BOOL fOffice97TestDoc = FALSE;
  4531. CHAR* pszFileToMunge = NULL;
  4532. CHAR* pszFileToDump = NULL;
  4533. printf("Property Set Tests\n");
  4534. // Check for command-line switches
  4535. if( 2 > argc )
  4536. {
  4537. printf("Too few arguments\n");
  4538. DisplayUsage( argv[0] );
  4539. exit(0);
  4540. }
  4541. for( nArgIndex = 1; nArgIndex < argc; nArgIndex++ )
  4542. {
  4543. if( argv[nArgIndex][0] == '/'
  4544. ||
  4545. argv[nArgIndex][0] == '-'
  4546. )
  4547. {
  4548. BOOL fNextArgument = FALSE;
  4549. for( int nOptionSubIndex = 1;
  4550. argv[nArgIndex][nOptionSubIndex] != '\0' && !fNextArgument;
  4551. nOptionSubIndex++
  4552. )
  4553. {
  4554. switch( argv[nArgIndex][nOptionSubIndex] )
  4555. {
  4556. case 'w':
  4557. case 'W':
  4558. ulTestOptions |= TEST_WORD6;
  4559. break;
  4560. case '?':
  4561. DisplayUsage(argv[0]);
  4562. exit(1);
  4563. case 'i':
  4564. if (argv[nArgIndex][nOptionSubIndex+1]=='w')
  4565. ulTestOptions |= TEST_INTEROP_W;
  4566. else if (argv[nArgIndex][nOptionSubIndex+1]=='r')
  4567. ulTestOptions |= TEST_INTEROP_R;
  4568. else
  4569. {
  4570. DisplayUsage(argv[0]);
  4571. printf("You must specify 'r' or 'w' for interop!\n");
  4572. exit(-1);
  4573. }
  4574. nOptionSubIndex++;
  4575. break;
  4576. case 'd':
  4577. case 'D':
  4578. if( NULL != pszFileToDump )
  4579. {
  4580. printf( "Error: Only one file may be dumped\n" );
  4581. DisplayUsage( argv[0] );
  4582. }
  4583. else
  4584. {
  4585. pszFileToDump = &argv[nArgIndex][nOptionSubIndex+1];
  4586. fNextArgument = TRUE;
  4587. }
  4588. if( '\0' == *pszFileToDump )
  4589. {
  4590. printf( "Error: Missing filename for dump option\n" );
  4591. DisplayUsage( argv[0] );
  4592. exit(1);
  4593. }
  4594. break;
  4595. case 'g':
  4596. case 'G':
  4597. if( NULL != pszFileToMunge )
  4598. {
  4599. printf( "Error: Only one file may be munged\n" );
  4600. DisplayUsage( argv[0] );
  4601. exit(1);
  4602. }
  4603. else
  4604. {
  4605. pszFileToMunge = &argv[nArgIndex][nOptionSubIndex+1];
  4606. fNextArgument = TRUE;
  4607. }
  4608. if( '\0' == *pszFileToMunge )
  4609. {
  4610. printf( "Error: Missing filename for munge option\n" );
  4611. DisplayUsage( argv[0] );
  4612. exit(1);
  4613. }
  4614. break;
  4615. default:
  4616. printf( "Option '%c' ignored\n",
  4617. argv[nArgIndex][nOptionSubIndex] );
  4618. break;
  4619. } // switch( argv[nArgIndex][1] )
  4620. } // for( int nOptionSubIndex = 1; ...
  4621. } // if( argv[nArgIndex][0] == '/'
  4622. else
  4623. {
  4624. break;
  4625. }
  4626. } // for( ULONG nArgIndex = 2; nArgIndex < argc; nArgIndex++ )
  4627. // If any other command-line parameters were given, ignore them.
  4628. for( int nExtraArg = nArgIndex+1; nExtraArg < argc; nExtraArg++ )
  4629. {
  4630. printf( "Illegal argument ignored: %s\n", argv[nExtraArg] );
  4631. }
  4632. OLECHAR ocsFile[256], ocsTest[256], ocsTest2[256], ocsTestOffice[256];
  4633. CHAR szDir[256];
  4634. HRESULT hr;
  4635. IStorage *pstg;
  4636. int i=0;
  4637. if ( NULL != pszFileToDump )
  4638. {
  4639. printf("DUMPING: %s\n", pszFileToDump);
  4640. printf("========================\n");
  4641. STOT( pszFileToDump, ocsFile, strlen(pszFileToDump)+1 );
  4642. Check(S_OK, StgOpenStorage( ocsFile,
  4643. (IStorage*)NULL,
  4644. (DWORD)STGM_DIRECT | STGM_READWRITE |
  4645. STGM_SHARE_EXCLUSIVE,
  4646. NULL,
  4647. 0L,
  4648. &pstg ));
  4649. DumpOleStorage( pstg, ocsFile );
  4650. Check(0, pstg->Release()); // ensure we released the last reference
  4651. exit(0);
  4652. }
  4653. // Is there a file to munge?
  4654. if ( NULL != pszFileToMunge )
  4655. {
  4656. STOT(pszFileToMunge, ocsFile, strlen(pszFileToMunge)+1 );
  4657. Check(S_OK, StgOpenStorage( ocsFile,
  4658. NULL,
  4659. (DWORD) STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4660. NULL,
  4661. 0L,
  4662. &pstg ));
  4663. MungeStorage( pstg );
  4664. PrintOC(ocsFile);
  4665. printf( " successfully munged\n");
  4666. Check(0, pstg->Release());
  4667. exit(0);
  4668. }
  4669. // Verify that the user provided a directory path.
  4670. if (nArgIndex >= argc)
  4671. {
  4672. printf( "Test directory not provided on command-line\n" );
  4673. DisplayUsage( argv[0] );
  4674. exit(1);
  4675. }
  4676. // Verify that the user-provided directory path
  4677. // exists
  4678. struct _stat filestat;
  4679. if (_stat(argv[nArgIndex], &filestat)!=0 ||
  4680. !(filestat.st_mode && S_IFDIR))
  4681. {
  4682. printf("Error in opening %s as a directory", argv[nArgIndex] );
  4683. exit(1);
  4684. }
  4685. #ifdef _WIN32 // don't bother to create a directory for test files on UNIX
  4686. // since there are some problems with creating files with
  4687. // path names
  4688. if (!(ulTestOptions & TEST_INTEROP_R) && !(ulTestOptions & TEST_INTEROP_W))
  4689. {
  4690. // Find an new directory name to use for temporary
  4691. // files ("testdirX", where "X" is a number).
  4692. do
  4693. {
  4694. strcpy(szDir, argv[nArgIndex]);
  4695. sprintf(strchr(szDir,0), "\\testdir%d", i++);
  4696. } while ( (_mkdir(szDir, 0x744) == -1) && (i<20) );
  4697. if (i>=20)
  4698. {
  4699. printf("Too many testdirX subdirectories, delete some and re-run\n");
  4700. exit(-1);
  4701. }
  4702. }
  4703. else
  4704. {
  4705. // use current directory for interop testing
  4706. szDir[0] = '.';
  4707. szDir[1] = 0;
  4708. }
  4709. #endif
  4710. #ifdef _WIN32
  4711. printf( "Generated files will be put in \"%s\"\n", szDir );
  4712. // Create "tesdoc"
  4713. STOT(szDir, ocsFile, strlen(szDir)+1);
  4714. ocscpy(ocsTest, ocsFile);
  4715. DECLARE_OLESTR(ocsTestDoc, "\\testdoc");
  4716. ocscat(ocsTest, ocsTestDoc);
  4717. #else
  4718. DECLARE_OLESTR(ocsTestDoc, "testdoc");
  4719. ocscpy(ocsTest, ocsTestDoc);
  4720. #endif
  4721. hr = StgCreateDocfile(ocsTest, STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  4722. 0, &_pstgTemp);
  4723. if (hr != S_OK)
  4724. {
  4725. printf("Can't create %s\n", ocsTest);
  4726. exit(1);
  4727. }
  4728. // Create "testdoc2"
  4729. #ifdef _WIN32
  4730. DECLARE_OLESTR(ocsTestDoc2,"\\testdoc2");
  4731. ocscpy(ocsTest2, ocsFile);
  4732. ocscat(ocsTest2, ocsTestDoc2);
  4733. #else
  4734. DECLARE_OLESTR(ocsTestDoc2,"testdoc2");
  4735. ocscpy(ocsTest2, ocsTestDoc2);
  4736. #endif
  4737. hr = StgCreateDocfile(ocsTest2, STGM_CREATE | STGM_READWRITE |
  4738. STGM_SHARE_EXCLUSIVE,
  4739. 0, &_pstgTempCopyTo);
  4740. if (hr != S_OK)
  4741. {
  4742. printf("Can't create %ls\n", ocsTest);
  4743. exit(1);
  4744. }
  4745. Check(S_OK, PopulateRGPropVar( g_rgcpropvarAll, g_rgcpropspecAll ));
  4746. printf( "\nStandard Tests\n" );
  4747. printf( "--------------\n" );
  4748. test_WriteReadAllProperties(ulTestOptions);
  4749. test_PropertyInterfaces(_pstgTemp);
  4750. // test with Unicode, then ansi files
  4751. test_CodePages(ocsFile, ulTestOptions, TRUE);
  4752. test_CodePages(ocsFile, ulTestOptions, FALSE);
  4753. // Test the IStorage::CopyTo operation, using all combinations of
  4754. // direct and transacted mode for the base and PropSet storages.
  4755. for( int iteration = 0; iteration < 4; iteration++ )
  4756. {
  4757. DECLARE_OLESTR(aocStorageName, "#0 Test CopyTo");
  4758. aocStorageName[1] = (OLECHAR) iteration + (OLECHAR)'0';
  4759. test_CopyTo( _pstgTemp, _pstgTempCopyTo,
  4760. STGM_DIRECT,
  4761. STGM_DIRECT,
  4762. aocStorageName );
  4763. }
  4764. // Generate the stock ticker property set example
  4765. // from the OLE programmer's reference spec.
  4766. test_OLESpecTickerExample( _pstgTemp );
  4767. #ifdef _WIN32
  4768. ocscpy(ocsTestOffice, ocsFile);
  4769. DECLARE_OLESTR(ocsOffice, "\\Office");
  4770. ocscat(ocsTestOffice, ocsOffice);
  4771. #else
  4772. DECLARE_OLESTR(ocsOffice, "Office");
  4773. ocscpy(ocsTestOffice, ocsOffice);
  4774. #endif
  4775. test_Office( ocsTestOffice );
  4776. test_PropVariantValidation( _pstgTemp );
  4777. test_PropVariantCopy();
  4778. if( ulTestOptions )
  4779. {
  4780. printf( "\nOptional Tests\n" );
  4781. printf( "--------------\n" );
  4782. // If requested, test for compatibility with Word 6.0 files.
  4783. if ( ulTestOptions & TEST_WORD6 )
  4784. test_Word6(_pstgTemp);
  4785. if ( ulTestOptions & TEST_INTEROP_W)
  4786. {
  4787. test_interop_write();
  4788. }
  4789. if ( ulTestOptions & TEST_INTEROP_R)
  4790. {
  4791. test_interop_read();
  4792. }
  4793. } // if( ulTestOptions )
  4794. Cleanup();
  4795. printf("\nPASSED\n");
  4796. return 0;
  4797. }