Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

812 lines
26 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: tests.cxx
  7. //
  8. // Contents: DRT tests
  9. //
  10. // History: 23-Sep-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include "headers.cxx"
  14. #pragma hdrstop
  15. #include "tests.hxx"
  16. #include "ilb.hxx"
  17. void t_create(void)
  18. {
  19. WStorage *pstgRoot, *pstgChild, *pstgChild2;
  20. WStream *pstm;
  21. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  22. 0, &pstgRoot);
  23. pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0,
  24. &pstgChild);
  25. pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0, 0,
  26. &pstgChild2);
  27. pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
  28. &pstm);
  29. pstm->Unwrap();
  30. pstgChild2->Commit(0);
  31. pstgChild2->Unwrap();
  32. pstgChild->Commit(0);
  33. pstgChild->Unwrap();
  34. VerifyStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))");
  35. pstgRoot->Unwrap();
  36. }
  37. void t_open(void)
  38. {
  39. WStorage *pstgRoot, *pstgChild, *pstgChild2;
  40. WStream *pstm;
  41. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  42. 0, &pstgRoot);
  43. CreateStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))");
  44. pstgRoot->Commit(0);
  45. pstgRoot->Unwrap();
  46. WStgOpenStorage(DRTDF, NULL, ROOTP(WSTG_READWRITE), NULL,
  47. 0, &pstgRoot);
  48. pstgRoot->OpenStorage(STR("Child"), NULL, STGP(WSTG_READWRITE), NULL, 0,
  49. &pstgChild);
  50. pstgChild->OpenStorage(STR("Child2"), NULL, STGP(WSTG_READWRITE), NULL, 0,
  51. &pstgChild2);
  52. pstgChild2->OpenStream(STR("Stream"), NULL, STMP(WSTG_READWRITE), 0,
  53. &pstm);
  54. pstm->Unwrap();
  55. pstgChild2->Unwrap();
  56. pstgChild->Unwrap();
  57. pstgRoot->Unwrap();
  58. }
  59. void t_addref(void)
  60. {
  61. WStorage *pstg;
  62. WStream *pstm;
  63. ULONG ul;
  64. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  65. 0, &pstg);
  66. pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  67. #ifndef FLAT
  68. if ((ul = pstm->AddRef()) != 2)
  69. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  70. if ((ul = pstm->Release()) != 1)
  71. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  72. pstm->Unwrap();
  73. if ((ul = pstg->AddRef()) != 2)
  74. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  75. if ((ul = pstg->Release()) != 1)
  76. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  77. #else
  78. if ((ul = pstm->AddRef()) <= 0)
  79. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  80. if ((ul = pstm->Release()) <= 0)
  81. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  82. pstm->Unwrap();
  83. if ((ul = pstg->AddRef()) <= 0)
  84. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  85. if ((ul = pstg->Release()) <= 0)
  86. error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
  87. #endif
  88. pstg->Unwrap();
  89. }
  90. void t_tmodify(void)
  91. {
  92. WStorage *pstgRoot, *pstgChild, *pstgChild2;
  93. WStream *pstm;
  94. // This test must use transacted mode to reproduce the
  95. // expected behavior
  96. ForceTransacted();
  97. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  98. 0, &pstgRoot);
  99. pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0,
  100. 0, &pstgChild);
  101. pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0,
  102. 0, &pstgChild2);
  103. pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  104. pstm->Unwrap();
  105. pstgChild2->Commit(0);
  106. VerifyStructure(pstgChild2->GetI(), "sStream");
  107. // Test renaming a closed stream
  108. pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
  109. VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
  110. // Test rename reversion
  111. pstgChild2->Revert();
  112. VerifyStructure(pstgChild2->GetI(), "sStream");
  113. // Test destruction of closed object
  114. pstgChild2->DestroyElement(STR("Stream"));
  115. pstgChild2->Commit(0);
  116. // Test create of previously deleted object
  117. pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  118. pstgChild2->Commit(0);
  119. VerifyStructure(pstgChild2->GetI(), "sStream");
  120. #if 0
  121. // 08/11/93 - Renaming open children no longer allowed
  122. // Test renaming an open stream
  123. pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
  124. VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
  125. #endif
  126. pstgChild2->Revert();
  127. VerifyStructure(pstgChild2->GetI(), "sStream");
  128. pstgChild2->DestroyElement(STR("Stream"));
  129. pstgChild2->Commit(0);
  130. pstm->Unwrap();
  131. pstgChild2->Unwrap();
  132. VerifyStructure(pstgChild->GetI(), "dChild2()");
  133. // Test rename of storage
  134. pstgChild->RenameElement(STR("Child2"), STR("RenamedChild"));
  135. pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
  136. &pstm);
  137. pstm->Unwrap();
  138. pstgChild->DestroyElement(STR("Stream"));
  139. pstgChild->Commit(0);
  140. // Test SetElementTimes
  141. FILETIME tm;
  142. STATSTG stat;
  143. tm.dwLowDateTime = 0x12345678;
  144. tm.dwHighDateTime = 0x01bcdef0;
  145. // Set when element not open
  146. pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL);
  147. pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL);
  148. pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm);
  149. pstgChild->OpenStorage(STR("RenamedChild"), NULL, STGP(WSTG_READWRITE),
  150. NULL, 0, &pstgChild2);
  151. pstgChild2->Stat(&stat, STATFLAG_NONAME);
  152. if (!IsEqualTime(stat.ctime, tm) ||
  153. !IsEqualTime(stat.mtime, tm))
  154. error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n");
  155. // Test SetClass and SetStateBits
  156. pstgChild2->SetClass(IID_IStorage);
  157. fExitOnFail = FALSE;
  158. pstgChild2->SetStateBits(0xff00ff00, 0xffffffff);
  159. pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee);
  160. fExitOnFail = TRUE;
  161. pstgChild2->Stat(&stat, STATFLAG_NONAME);
  162. if (!IsEqualCLSID(stat.clsid, IID_IStorage))
  163. error(EXIT_BADSC, "Class ID set to %s\n", GuidText(&stat.clsid));
  164. if (stat.grfStateBits != 0x11881188)
  165. errorprint("State bits set improperly: has %lX vs. %lX\n",
  166. stat.grfStateBits, 0x11881188);
  167. pstgChild2->Revert();
  168. pstgChild2->Stat(&stat, STATFLAG_NONAME);
  169. if (!IsEqualCLSID(stat.clsid, CLSID_NULL))
  170. error(EXIT_BADSC, "Class ID reverted to %s\n", GuidText(&stat.clsid));
  171. if (stat.grfStateBits != 0)
  172. errorprint("State bits reverted improperly: has %lX vs. %lX\n",
  173. stat.grfStateBits, 0);
  174. pstgChild2->Unwrap();
  175. pstgChild->Unwrap();
  176. VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
  177. pstgRoot->Revert();
  178. VerifyStructure(pstgRoot->GetI(), "");
  179. pstgRoot->Commit(0);
  180. VerifyStructure(pstgRoot->GetI(), "");
  181. pstgRoot->Unwrap();
  182. Unforce();
  183. }
  184. void t_dmodify(void)
  185. {
  186. WStorage *pstgRoot, *pstgChild, *pstgChild2;
  187. WStream *pstm;
  188. ULONG cbSize1, cbSize2;
  189. // This test must use direct mode to reproduce the
  190. // expected behavior
  191. ForceDirect();
  192. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  193. 0, &pstgRoot);
  194. pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0,
  195. 0, &pstgChild);
  196. pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0,
  197. 0, &pstgChild2);
  198. pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  199. pstm->Unwrap();
  200. VerifyStructure(pstgChild2->GetI(), "sStream");
  201. // Test renaming a closed stream
  202. pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
  203. VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
  204. // Test destroying a stream
  205. pstgChild2->DestroyElement(STR("RenamedStream"));
  206. #if 0
  207. // 08/11/93 - Renaming open child no longer allowed
  208. // Test renaming an open stream
  209. pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  210. VerifyStructure(pstgChild2->GetI(), "sStream");
  211. pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
  212. VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
  213. pstgChild2->DestroyElement(STR("RenamedStream"));
  214. pstm->Unwrap();
  215. #endif
  216. pstgChild2->Unwrap();
  217. VerifyStructure(pstgChild->GetI(), "dChild2()");
  218. // Test renaming a storage
  219. pstgChild->RenameElement(STR("Child2"), STR("RenamedChild"));
  220. pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
  221. &pstm);
  222. pstm->Unwrap();
  223. pstgChild->DestroyElement(STR("Stream"));
  224. // Test SetElementTimes
  225. FILETIME tm;
  226. STATSTG stat;
  227. tm.dwLowDateTime = 0x12345678;
  228. tm.dwHighDateTime = 0x01bcdef0;
  229. // Set when element not open
  230. pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL);
  231. pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL);
  232. pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm);
  233. pstgChild->OpenStorage(STR("RenamedChild"), NULL, STMP(WSTG_READWRITE),
  234. NULL, 0, &pstgChild2);
  235. pstgChild2->Stat(&stat, STATFLAG_NONAME);
  236. if (!IsEqualTime(stat.ctime, tm) ||
  237. !IsEqualTime(stat.mtime, tm))
  238. error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n");
  239. // Test SetClass and SetStateBits
  240. pstgChild2->SetClass(IID_IStorage);
  241. fExitOnFail = FALSE;
  242. pstgChild2->SetStateBits(0xff00ff00, 0xffffffff);
  243. pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee);
  244. fExitOnFail = TRUE;
  245. pstgChild2->Stat(&stat, STATFLAG_NONAME);
  246. if (!IsEqualCLSID(stat.clsid, IID_IStorage))
  247. error(EXIT_BADSC, "Class ID set improperly\n");
  248. if (stat.grfStateBits != 0x11881188)
  249. errorprint("State bits set improperly: has %lX vs. %lX\n",
  250. stat.grfStateBits, 0x11881188);
  251. pstgChild2->Unwrap();
  252. pstgChild->Unwrap();
  253. VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
  254. pstgRoot->Revert();
  255. VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
  256. pstgRoot->Commit(0);
  257. VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
  258. pstgRoot->DestroyElement(STR("Child"));
  259. VerifyStructure(pstgRoot->GetI(), "");
  260. // Verify that space is reclaimed after modifications
  261. pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  262. pstm->SetSize(65536);
  263. pstm->Unwrap();
  264. cbSize1 = Length(DRTDF);
  265. pstgRoot->DestroyElement(STR("Stream"));
  266. pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  267. pstm->SetSize(65536);
  268. pstm->Unwrap();
  269. cbSize2 = Length(DRTDF);
  270. if (cbSize1 != cbSize2)
  271. error(EXIT_BADSC, "Space is not being reclaimed, original %lu, "
  272. "now %lu\n", cbSize1, cbSize2);
  273. pstgRoot->Unwrap();
  274. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  275. WSTG_DELETEONRELEASE, 0, &pstgRoot);
  276. // removal cases
  277. // 1) no right child
  278. CreateStructure(pstgRoot->GetI(), "d64,d32");
  279. VerifyStructure(pstgRoot->GetI(), "d64,d32");
  280. pstgRoot->DestroyElement(STR("64"));
  281. VerifyStructure(pstgRoot->GetI(), "d32");
  282. // 2) right child has no left child
  283. CreateStructure(pstgRoot->GetI(), "d64");
  284. VerifyStructure(pstgRoot->GetI(), "d32,d64");
  285. pstgRoot->DestroyElement(STR("32"));
  286. VerifyStructure(pstgRoot->GetI(), "d64");
  287. // 3) right child has left child
  288. CreateStructure(pstgRoot->GetI(), "d96,d80");
  289. VerifyStructure(pstgRoot->GetI(), "d64,d80,d96");
  290. pstgRoot->DestroyElement(STR("64"));
  291. VerifyStructure(pstgRoot->GetI(), "d80,d96");
  292. // 4) right child's left child has children
  293. CreateStructure(pstgRoot->GetI(), "d88,d84,d92");
  294. VerifyStructure(pstgRoot->GetI(), "d80,d84,d88,d92,d96");
  295. pstgRoot->DestroyElement(STR("80"));
  296. VerifyStructure(pstgRoot->GetI(), "d84,d88,d92,d96");
  297. pstgRoot->Unwrap();
  298. Unforce();
  299. }
  300. void t_stat(void)
  301. {
  302. WStorage *pstgRoot, *pstgChild;
  303. WStream *pstm;
  304. STATSTG stat;
  305. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  306. 0, &pstgRoot);
  307. pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0,
  308. &pstgChild);
  309. pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  310. pstm->Stat(&stat, 0);
  311. VerifyStat(&stat, STR("Stream"), STGTY_STREAM, STMP(WSTG_READWRITE));
  312. drtMemFree(stat.pwcsName);
  313. pstm->Stat(&stat, STATFLAG_NONAME);
  314. VerifyStat(&stat, NULL, STGTY_STREAM, STMP(WSTG_READWRITE));
  315. pstm->Unwrap();
  316. pstgChild->Stat(&stat, 0);
  317. VerifyStat(&stat, STR("Child"), STGTY_STORAGE, STGP(WSTG_READWRITE));
  318. drtMemFree(stat.pwcsName);
  319. pstgChild->Stat(&stat, STATFLAG_NONAME);
  320. VerifyStat(&stat, NULL, STGTY_STORAGE, STGP(WSTG_READWRITE));
  321. pstgChild->Unwrap();
  322. pstgRoot->Stat(&stat, 0);
  323. OLECHAR atcFullPath[_MAX_PATH];
  324. GetFullPath(DRTDF, atcFullPath);
  325. VerifyStat(&stat, atcFullPath, STGTY_STORAGE, ROOTP(WSTG_READWRITE));
  326. drtMemFree(stat.pwcsName);
  327. pstgRoot->Stat(&stat, STATFLAG_NONAME);
  328. VerifyStat(&stat, NULL, STGTY_STORAGE, ROOTP(WSTG_READWRITE));
  329. pstgRoot->Unwrap();
  330. }
  331. static char NUMBERS[] = "12345678901234567890123456789012345678901234567890";
  332. void t_stream(void)
  333. {
  334. WStorage *pstg;
  335. WStream *pstm, *pstmC;
  336. char buf[sizeof(NUMBERS)*2];
  337. ULONG cb, ulPos;
  338. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg);
  339. pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  340. pstm->Write(NUMBERS, sizeof(NUMBERS), &cb);
  341. pstm->Commit(0);
  342. pstm->Seek(0, WSTM_SEEK_SET, &ulPos);
  343. if (ulPos != 0)
  344. error(EXIT_BADSC, "Incorrect seek, ptr is %lu\n", ulPos);
  345. pstm->Read(buf, sizeof(NUMBERS), &cb);
  346. if (strcmp(buf, NUMBERS))
  347. error(EXIT_BADSC, "Incorrect stream contents\n");
  348. pstm->SetSize(sizeof(NUMBERS)/2);
  349. pstm->Seek(0, WSTM_SEEK_SET, NULL);
  350. fExitOnFail = FALSE;
  351. pstm->Read(buf, sizeof(NUMBERS), &cb);
  352. fExitOnFail = TRUE;
  353. if (cb != sizeof(NUMBERS)/2)
  354. error(EXIT_BADSC, "SetSize failed to size stream properly\n");
  355. if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2))
  356. error(EXIT_BADSC, "SetSize corrupted contents\n");
  357. pstm->Clone(&pstmC);
  358. pstm->Seek(0, WSTM_SEEK_SET, NULL);
  359. pstm->CopyTo(pstmC, sizeof(NUMBERS)/2, NULL, NULL);
  360. pstm->Seek(0, WSTM_SEEK_SET, NULL);
  361. pstm->CopyTo(pstmC, sizeof(NUMBERS)&~1, NULL, NULL);
  362. pstm->Seek(0, WSTM_SEEK_SET, NULL);
  363. pstm->Read(buf, (sizeof(NUMBERS)&~1)*2, &cb);
  364. if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2) ||
  365. memcmp(buf+sizeof(NUMBERS)/2, NUMBERS, sizeof(NUMBERS)/2) ||
  366. memcmp(buf+(sizeof(NUMBERS)&~1), NUMBERS, sizeof(NUMBERS)/2) ||
  367. memcmp(buf+3*(sizeof(NUMBERS)/2), NUMBERS, sizeof(NUMBERS)/2))
  368. error(EXIT_BADSC, "Stream contents incorrect\n");
  369. pstmC->Unwrap();
  370. pstm->Unwrap();
  371. pstg->Unwrap();
  372. }
  373. // Number of entries for enumeration test
  374. #define ENUMENTRIES 10
  375. // Flag indicating a name has already shown up in enumeration,
  376. // must not conflict with STGTY_*
  377. #define ENTRY_SEEN 0x100
  378. // Check the validity of an enumeration element
  379. static void elt_check(STATSTG *pstat, CStrList *psl)
  380. {
  381. SStrEntry *pse;
  382. pse = psl->Find(pstat->pwcsName);
  383. if (pse == NULL)
  384. error(EXIT_BADSC, "Spurious element '%s'\n", pstat->pwcsName);
  385. else if ((pse->user.dw & ~ENTRY_SEEN) != pstat->type)
  386. error(EXIT_BADSC, "Element '%s' has wrong type - "
  387. "has %lX vs. %lX\n", pstat->pwcsName, pstat->type,
  388. pse->user.dw & ~ENTRY_SEEN);
  389. else if (pse->user.dw & ENTRY_SEEN)
  390. error(EXIT_BADSC, "Element '%s' has already been seen\n",
  391. pstat->pwcsName);
  392. pse->user.dw |= ENTRY_SEEN;
  393. }
  394. // Do final validity checks for enumeration
  395. static void enum_list_check(CStrList *psl)
  396. {
  397. SStrEntry *pse;
  398. for (pse = psl->GetHead(); pse; pse = pse->pseNext)
  399. {
  400. if ((pse->user.dw & ENTRY_SEEN) == 0)
  401. error(EXIT_BADSC, "Element '%s' not found\n", pse->atc);
  402. pse->user.dw &= ~ENTRY_SEEN;
  403. }
  404. }
  405. void t_enum(void)
  406. {
  407. int i;
  408. OLECHAR atcName[CWCSTORAGENAME];
  409. WStorage *pstg, *pstg2;
  410. WStream *pstm;
  411. SStrEntry *pse;
  412. CStrList sl;
  413. // Create some entries to enumerate
  414. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg);
  415. for (i = 0; i<ENUMENTRIES; i++)
  416. {
  417. olecsprintf(atcName, STR("Name%d"), rand());
  418. pse = sl.Add(atcName);
  419. if (rand()%100 < 50)
  420. {
  421. pse->user.dw = STGTY_STORAGE;
  422. pstg->CreateStorage(atcName, STGP(WSTG_READWRITE), 0, 0, &pstg2);
  423. pstg2->Unwrap();
  424. }
  425. else
  426. {
  427. pse->user.dw = STGTY_STREAM;
  428. pstg->CreateStream(atcName, STMP(WSTG_READWRITE), 0, 0, &pstm);
  429. pstm->Unwrap();
  430. }
  431. }
  432. WEnumSTATSTG *penm;
  433. STATSTG stat[2*ENUMENTRIES];
  434. SCODE sc;
  435. // Test plain, single element enumeration
  436. pstg->EnumElements(0, NULL, 0, &penm);
  437. for (;;)
  438. {
  439. sc = DfGetScode(penm->Next(1, stat, NULL));
  440. if (sc == S_FALSE)
  441. break;
  442. elt_check(stat, &sl);
  443. drtMemFree(stat->pwcsName);
  444. }
  445. enum_list_check(&sl);
  446. ULONG cFound;
  447. // Test rewind and multiple element enumeration with too many elements
  448. penm->Reset();
  449. sc = DfGetScode(penm->Next(ENUMENTRIES*2, stat, &cFound));
  450. if (sc != S_FALSE)
  451. error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
  452. "S_FALSE\n", ScText(sc), sc);
  453. if (cFound != ENUMENTRIES)
  454. error(EXIT_BADSC, "Enumerator found %lu entries instead of "
  455. "%d entries\n", cFound, ENUMENTRIES);
  456. for (; cFound > 0; cFound--)
  457. {
  458. elt_check(&stat[cFound-1], &sl);
  459. drtMemFree(stat[cFound-1].pwcsName);
  460. }
  461. enum_list_check(&sl);
  462. // Test skip and multiple enumeration with exact number of elements
  463. penm->Reset();
  464. penm->Skip(ENUMENTRIES/2);
  465. sc = DfGetScode(penm->Next(ENUMENTRIES-ENUMENTRIES/2, stat, &cFound));
  466. if (sc != S_OK)
  467. error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
  468. "S_OK\n", ScText(sc), sc);
  469. if (cFound != ENUMENTRIES-ENUMENTRIES/2)
  470. error(EXIT_BADSC, "Enumerator found %lu entries instead of "
  471. "%d entries\n", cFound, ENUMENTRIES-ENUMENTRIES/2);
  472. for (; cFound > 0; cFound--)
  473. {
  474. elt_check(&stat[cFound-1], &sl);
  475. drtMemFree(stat[cFound-1].pwcsName);
  476. }
  477. sc = DfGetScode(penm->Next(1, stat, NULL));
  478. if (sc != S_FALSE)
  479. error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
  480. "S_FALSE\n", ScText(sc), sc);
  481. penm->Unwrap();
  482. pstg->Unwrap();
  483. }
  484. #define SCT_CLASSID IID_ILockBytes
  485. #define SCT_STATEBITS 0xfef1f0f0
  486. void t_stgcopyto(void)
  487. {
  488. WStorage *pstgFrom, *pstgTo;
  489. STATSTG statFrom, statTo;
  490. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  491. WSTG_DELETEONRELEASE, 0, &pstgFrom);
  492. pstgFrom->Stat(&statFrom, 0);
  493. // Set some interesting values to make sure they're copied
  494. pstgFrom->SetClass(SCT_CLASSID);
  495. fExitOnFail = FALSE;
  496. pstgFrom->SetStateBits(SCT_STATEBITS, 0xffffffff);
  497. fExitOnFail = TRUE;
  498. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  499. WSTG_DELETEONRELEASE, 0, &pstgTo);
  500. CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs");
  501. CreateStructure(pstgTo->GetI(), "dA(dY(sZ),sBs)");
  502. pstgFrom->CopyTo(0, NULL, NULL, pstgTo);
  503. VerifyStructure(pstgTo->GetI(),
  504. "dA(dB(dC(sA,sB,sC),sCs),dY(sZ),sBs),sAs");
  505. pstgTo->Stat(&statTo, 0);
  506. if (!IsEqualCLSID(statTo.clsid, SCT_CLASSID))
  507. error(EXIT_BADSC, "Class ID mismatch after copy\n");
  508. if (statTo.grfStateBits != SCT_STATEBITS)
  509. errorprint("State bits mismatch: has %lX vs. %lX\n",
  510. statTo.grfStateBits, SCT_STATEBITS);
  511. pstgFrom->Unwrap();
  512. pstgTo->Unwrap();
  513. if (Exists(statFrom.pwcsName))
  514. error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName);
  515. drtMemFree(statFrom.pwcsName);
  516. if (Exists(statTo.pwcsName))
  517. error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName);
  518. drtMemFree(statTo.pwcsName);
  519. }
  520. #define MARSHAL_STM STR("Marshal")
  521. void do_marshal(WStorage *pstg, WStream *pstm)
  522. {
  523. WStorage *pstgMarshal;
  524. WStream *pstmMarshal;
  525. WStgCreateDocfile(MARSHALDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
  526. 0, &pstgMarshal);
  527. pstgMarshal->CreateStream(MARSHAL_STM, STMP(WSTG_READWRITE), 0, 0,
  528. &pstmMarshal);
  529. WCoMarshalInterface(pstmMarshal, IID_IStorage, pstg->GetI(), 0, NULL,
  530. MSHLFLAGS_NORMAL);
  531. WCoMarshalInterface(pstmMarshal, IID_IStream, pstm->GetI(), 0, NULL,
  532. MSHLFLAGS_NORMAL);
  533. WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstg->GetI(), 0, NULL,
  534. MSHLFLAGS_NORMAL);
  535. WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstm->GetI(), 0, NULL,
  536. MSHLFLAGS_NORMAL);
  537. pstmMarshal->Unwrap();
  538. pstgMarshal->Commit(0);
  539. pstgMarshal->Unwrap();
  540. }
  541. static char STREAM_DATA[] = "This is data to be written";
  542. void do_unmarshal(WStorage **ppstg, WStream **ppstm,
  543. IUnknown **ppstg2, IUnknown **ppstm2)
  544. {
  545. IStorage *pistg;
  546. WStorage *pstgMarshal;
  547. WStream *pstmMarshal;
  548. IStream *pistm;
  549. WStgOpenStorage(MARSHALDF, NULL, ROOTP(WSTG_READWRITE), NULL, 0,
  550. &pstgMarshal);
  551. pstgMarshal->OpenStream(MARSHAL_STM, NULL, STMP(WSTG_READWRITE), 0,
  552. &pstmMarshal);
  553. WCoUnmarshalInterface(pstmMarshal, IID_IStorage, (void **)&pistg);
  554. *ppstg = WStorage::Wrap(pistg);
  555. WCoUnmarshalInterface(pstmMarshal, IID_IStream, (void **)&pistm);
  556. *ppstm = WStream::Wrap(pistm);
  557. WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstg2);
  558. WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstm2);
  559. pstmMarshal->Unwrap();
  560. pstgMarshal->Unwrap();
  561. }
  562. void t_marshal(void)
  563. {
  564. WStorage *pstg, *pstgM;
  565. WStream *pstm, *pstmM;
  566. IUnknown *pstgM2, *pstmM2;
  567. ULONG cbRead, cbWritten;
  568. char buf[sizeof(STREAM_DATA)];
  569. WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  570. WSTG_DELETEONRELEASE, 0, &pstg);
  571. pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
  572. pstm->Write(STREAM_DATA, sizeof(STREAM_DATA), &cbWritten);
  573. CreateStructure(pstg->GetI(), "dChild(dChild(sStream))");
  574. do_marshal(pstg, pstm);
  575. do_unmarshal(&pstgM, &pstmM, &pstgM2, &pstmM2);
  576. pstm->Unwrap();
  577. pstg->Unwrap();
  578. pstmM->Seek(0, WSTM_SEEK_SET, NULL);
  579. pstmM->Read(buf, sizeof(STREAM_DATA), &cbRead);
  580. if (strcmp(buf, STREAM_DATA))
  581. error(EXIT_BADSC, "Stream data mismatch\n");
  582. pstmM->Unwrap();
  583. pstmM2->Release();
  584. VerifyStructure(pstgM->GetI(), "dChild(dChild(sStream)),sStream");
  585. pstgM->Unwrap();
  586. pstgM2->Release();
  587. }
  588. void t_stgmisc(void)
  589. {
  590. WStorage *pstg;
  591. SCODE sc;
  592. STATSTG stat;
  593. // Can't make this call in transacted mode because we want
  594. // the storage signature to make it into the file right away
  595. WStgCreateDocfile(DRTDF, WSTG_READWRITE | WSTG_CREATE |
  596. WSTG_SHARE_EXCLUSIVE, 0, &pstg);
  597. if (!fOfs)
  598. {
  599. sc = DfGetScode(WStgIsStorageFile(DRTDF));
  600. if (sc == S_FALSE)
  601. error(EXIT_BADSC, "Open file - Should be a storage object\n");
  602. pstg->Unwrap();
  603. sc = DfGetScode(WStgIsStorageFile(DRTDF));
  604. if (sc == S_FALSE)
  605. error(EXIT_BADSC, "Closed file - Should be a storage object\n");
  606. }
  607. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  608. WSTG_DELETEONRELEASE, 0, &pstg);
  609. pstg->Stat(&stat, 0);
  610. if (!Exists(stat.pwcsName))
  611. error(EXIT_BADSC, "Storage '%s' not created\n", stat.pwcsName);
  612. pstg->Unwrap();
  613. if (Exists(stat.pwcsName))
  614. error(EXIT_BADSC, "Storage '%s' not deleted on release\n",
  615. stat.pwcsName);
  616. drtMemFree(stat.pwcsName);
  617. }
  618. void t_ilb(void)
  619. {
  620. WStorage *pstg;
  621. SCODE sc;
  622. // create an ILockBytes
  623. ILockBytes *pilb = new CMapBytes();
  624. if (pilb == NULL)
  625. error(EXIT_BADSC, "Unable to allocate an ILockBytes\n");
  626. // create a storage on the ILockBytes
  627. WStgCreateDocfileOnILockBytes(pilb,
  628. WSTG_READWRITE |
  629. WSTG_CREATE |
  630. WSTG_SHARE_EXCLUSIVE,
  631. 0, &pstg);
  632. // verify the ILockBytes
  633. sc = DfGetScode(WStgIsStorageILockBytes(pilb));
  634. if (sc == S_FALSE)
  635. error(EXIT_BADSC, "Open ILockBytes - Should be a storage object\n");
  636. // release the storage
  637. pstg->Unwrap();
  638. // verify the ILockBytes
  639. sc = DfGetScode(WStgIsStorageILockBytes(pilb));
  640. if (sc == S_FALSE)
  641. error(EXIT_BADSC, "Released ILockBytes - Should be a storage object\n");
  642. // open the ILockBytes
  643. WStgOpenStorageOnILockBytes(pilb, NULL, ROOTP(WSTG_READWRITE),
  644. NULL, 0, &pstg);
  645. // release the storage
  646. pstg->Unwrap();
  647. // release the ILockBytes
  648. pilb->Release();
  649. }
  650. void t_movecopy(void)
  651. {
  652. WStorage *pstgFrom, *pstgTo;
  653. STATSTG statFrom, statTo;
  654. // create a source
  655. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  656. WSTG_DELETEONRELEASE, 0, &pstgFrom);
  657. pstgFrom->Stat(&statFrom, 0);
  658. // create a destination
  659. WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
  660. WSTG_DELETEONRELEASE, 0, &pstgTo);
  661. pstgTo->Stat(&statTo, 0);
  662. // populate source
  663. CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs");
  664. // move a storage
  665. pstgFrom->MoveElementTo(STR("A"), pstgTo, STR("M"), STGMOVE_MOVE);
  666. VerifyStructure(pstgFrom->GetI(),
  667. "sAs");
  668. VerifyStructure(pstgTo->GetI(),
  669. "dM(dB(dC(sA,sB,sC),sCs),sBs)");
  670. // copy a stream
  671. pstgFrom->MoveElementTo(STR("As"), pstgTo, STR("Bs"), STGMOVE_COPY);
  672. VerifyStructure(pstgFrom->GetI(),
  673. "sAs");
  674. VerifyStructure(pstgTo->GetI(),
  675. "dM(dB(dC(sA,sB,sC),sCs),sBs),sBs");
  676. pstgFrom->Unwrap();
  677. pstgTo->Unwrap();
  678. if (Exists(statFrom.pwcsName))
  679. error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName);
  680. drtMemFree(statFrom.pwcsName);
  681. if (Exists(statTo.pwcsName))
  682. error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName);
  683. drtMemFree(statTo.pwcsName);
  684. }