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.

1731 lines
39 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved
  3. Module Name:
  4. wsbcltn.cpp
  5. Abstract:
  6. These classes provide support for collections (lists) of "collectable"
  7. objects.
  8. Author:
  9. Chuck Bardeen [cbardeen] 29-Oct-1996
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #include "wsbcltn.h"
  14. HRESULT
  15. CWsbCollection::Contains(
  16. IN IUnknown* pCollectable
  17. )
  18. /*++
  19. Implements:
  20. IWsbCollection::Contains().
  21. --*/
  22. {
  23. HRESULT hr = S_OK;
  24. CComPtr<IWsbCollectable> pOut;
  25. WsbTraceIn(OLESTR("CWsbCollection::Contains"), OLESTR(""));
  26. hr = Find(pCollectable, IID_IWsbCollectable, (void**) &pOut);
  27. if (hr == WSB_E_NOTFOUND) {
  28. hr = S_FALSE;
  29. }
  30. WsbTraceOut(OLESTR("CWsbCollection::Contains"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  31. return(hr);
  32. }
  33. HRESULT
  34. CWsbCollection::FinalConstruct(
  35. void
  36. )
  37. /*++
  38. Implements:
  39. CComObjectRoot::FinalConstruct().
  40. --*/
  41. {
  42. HRESULT hr = S_OK;
  43. try {
  44. m_bCritSecCreated = FALSE;
  45. WsbAffirmHr(CWsbPersistStream::FinalConstruct());
  46. m_entries = 0;
  47. WsbAffirmStatus(InitializeCriticalSectionAndSpinCount(&m_CritSec, 0));
  48. m_bCritSecCreated = TRUE;
  49. } WsbCatch(hr);
  50. return(hr);
  51. }
  52. void
  53. CWsbCollection::FinalRelease(
  54. void
  55. )
  56. /*++
  57. Implements:
  58. CComObjectRoot::FinalRelease().
  59. --*/
  60. {
  61. if (m_bCritSecCreated) {
  62. DeleteCriticalSection(&m_CritSec);
  63. }
  64. CWsbPersistStream::FinalRelease();
  65. }
  66. HRESULT
  67. CWsbCollection::Find(
  68. IN IUnknown* pCollectable,
  69. IN REFIID riid,
  70. OUT void** ppElement
  71. )
  72. /*++
  73. Implements:
  74. IWsbCollection::Find().
  75. --*/
  76. {
  77. CComPtr<IWsbEnum> pEnum;
  78. HRESULT hr = S_OK;
  79. BOOL matched = FALSE;
  80. WsbTraceIn(OLESTR("CWsbCollection::Find"), OLESTR("riid = <%ls>"), WsbGuidAsString(riid));
  81. try {
  82. WsbAssert(0 != ppElement, E_POINTER);
  83. WsbAffirmHr(Enum(&pEnum));
  84. WsbAffirmHr(pEnum->Find(pCollectable, riid, ppElement));
  85. } WsbCatch(hr);
  86. WsbTraceOut(OLESTR("CWsbCollection::Find"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  87. return(hr);
  88. }
  89. HRESULT
  90. CWsbCollection::GetEntries(
  91. OUT ULONG* pEntries
  92. )
  93. /*++
  94. Implements:
  95. IWsbCollection::GetEntries().
  96. --*/
  97. {
  98. HRESULT hr = S_OK;
  99. WsbTraceIn(OLESTR("CWsbCollection::GetEntries"), OLESTR(""));
  100. try {
  101. WsbAssert(0 != pEntries, E_POINTER);
  102. *pEntries = m_entries;
  103. } WsbCatch(hr);
  104. WsbTraceOut(OLESTR("CWsbCollection::GetEntries"), OLESTR("hr = <%ls>, entries = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString(pEntries));
  105. return(S_OK);
  106. }
  107. HRESULT
  108. CWsbCollection::IsEmpty(
  109. void
  110. )
  111. /*++
  112. Implements:
  113. IWsbCollection::IsEmpty().
  114. --*/
  115. {
  116. HRESULT hr = S_OK;
  117. WsbTraceIn(OLESTR("CWsbCollection::IsEmpty"), OLESTR(""));
  118. if (0 != m_entries) {
  119. hr = S_FALSE;
  120. }
  121. WsbTraceOut(OLESTR("CWsbCollection::IsEmpty"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  122. return(hr);
  123. }
  124. HRESULT
  125. CWsbCollection::IsLocked(
  126. void
  127. )
  128. /*++
  129. Implements:
  130. IWsbCollection::IsLocked().
  131. --*/
  132. {
  133. HRESULT hr = S_OK;
  134. BOOL tryEnter = FALSE;
  135. WsbTraceIn(OLESTR("CWsbCollection::IsLocked"), OLESTR(""));
  136. tryEnter = TryEnterCriticalSection(&m_CritSec);
  137. if (tryEnter == 0) {
  138. //
  139. // Another thread has the collection locked
  140. //
  141. hr = S_OK;
  142. } else {
  143. //
  144. // We got the lock, so unlock it
  145. LeaveCriticalSection(&m_CritSec);
  146. hr = S_FALSE;
  147. }
  148. WsbTraceOut(OLESTR("CWsbCollection::IsLocked"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  149. return( hr );
  150. }
  151. HRESULT
  152. CWsbCollection::Lock(
  153. void
  154. )
  155. /*++
  156. Implements:
  157. CComObjectRoot::Lock().
  158. --*/
  159. {
  160. WsbTrace(OLESTR("CWsbCollection::Lock - waiting for critical section\n"));
  161. EnterCriticalSection(&m_CritSec);
  162. WsbTrace(OLESTR("CWsbCollection::Lock - got critical section\n"));
  163. return(S_OK);
  164. }
  165. HRESULT
  166. CWsbCollection::OccurencesOf(
  167. IN IUnknown* pCollectable,
  168. OUT ULONG* pOccurences
  169. )
  170. /*++
  171. Implements:
  172. IWsbCollection::OccurrencesOf().
  173. --*/
  174. {
  175. CComPtr<IWsbCollectable> pCollectableEnum;
  176. CComPtr<IWsbEnum> pEnum;
  177. HRESULT hr = S_OK;
  178. WsbTraceIn(OLESTR("CWsbCollection::OccurencesOf"), OLESTR(""));
  179. Lock();
  180. try {
  181. WsbAssert(0 != pCollectable, E_POINTER);
  182. WsbAssert(0 != pOccurences, E_POINTER);
  183. // Initialize the return value.
  184. *pOccurences = 0;
  185. // Get an enumerator.
  186. WsbAffirmHr(Enum(&pEnum));
  187. // Start at the front of the list.
  188. for (hr = pEnum->Find(pCollectable, IID_IWsbCollectable, (void**) &pCollectableEnum);
  189. SUCCEEDED(hr);
  190. hr = pEnum->FindNext(pCollectable, IID_IWsbCollectable, (void**) &pCollectableEnum)) {
  191. (*pOccurences)++;
  192. pCollectableEnum = 0;
  193. }
  194. // We should always hit the end of the collection, so then
  195. // change the return code to the appropriate value.
  196. if (hr == WSB_E_NOTFOUND) {
  197. if (0 == *pOccurences) {
  198. hr = S_FALSE;
  199. } else {
  200. hr = S_OK;
  201. }
  202. }
  203. } WsbCatch(hr);
  204. Unlock();
  205. WsbTraceOut(OLESTR("CWsbCollection::OccurencesOf"), OLESTR("hr = <%ls>, occurences = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString(pOccurences));
  206. return(hr);
  207. }
  208. HRESULT
  209. CWsbCollection::RemoveAndRelease(
  210. IN IUnknown* pCollectable
  211. )
  212. /*++
  213. Implements:
  214. IWsbCollection::RemoveAndRelease().
  215. --*/
  216. {
  217. HRESULT hr = S_OK;
  218. WsbTraceIn(OLESTR("CWsbCollection::RemoveAndRelease"), OLESTR(""));
  219. try {
  220. WsbAssert(0 != pCollectable, E_POINTER);
  221. WsbAffirmHr(Remove(pCollectable, IID_IWsbCollectable, NULL));
  222. } WsbCatch(hr);
  223. WsbTraceOut(OLESTR("CWsbCollection::RemoveAndRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  224. return(hr);
  225. }
  226. HRESULT
  227. CWsbCollection::Test(
  228. OUT USHORT* passed,
  229. OUT USHORT* failed
  230. )
  231. /*++
  232. Implements:
  233. IWsbTestable::Test().
  234. --*/
  235. {
  236. *passed = 0;
  237. *failed = 0;
  238. HRESULT hr = S_OK;
  239. #if !defined(WSB_NO_TEST)
  240. CComPtr<IWsbGuid> pGuid1;
  241. CComPtr<IWsbGuid> pGuid2;
  242. CComPtr<IWsbGuid> pGuid3;
  243. CComPtr<IWsbGuid> pGuid4;
  244. ULONG entries;
  245. WsbTraceIn(OLESTR("CWsbCollection::Test"), OLESTR(""));
  246. try {
  247. // Clear out any entries that might be present.
  248. hr = S_OK;
  249. try {
  250. WsbAssertHr(RemoveAllAndRelease());
  251. } WsbCatch(hr);
  252. if (hr == S_OK) {
  253. (*passed)++;
  254. } else {
  255. (*failed)++;
  256. }
  257. // There shouldn't be any entries.
  258. hr = S_OK;
  259. try {
  260. WsbAssertHr(GetEntries(&entries));
  261. WsbAssert(0 == entries, E_FAIL);
  262. } WsbCatch(hr);
  263. if (hr == S_OK) {
  264. (*passed)++;
  265. } else {
  266. (*failed)++;
  267. }
  268. // It should be empty.
  269. hr = S_OK;
  270. try {
  271. WsbAssert(IsEmpty() == S_OK, E_FAIL);
  272. } WsbCatch(hr);
  273. if (hr == S_OK) {
  274. (*passed)++;
  275. } else {
  276. (*failed)++;
  277. }
  278. // We need some collectable items to exercise the collection.
  279. WsbAssertHr(CoCreateInstance(CLSID_CWsbGuid, NULL, CLSCTX_ALL, IID_IWsbGuid, (void**) &pGuid1));
  280. WsbAssertHr(pGuid1->SetGuid(CLSID_CWsbGuid));
  281. // Add the item to the collection.
  282. hr = S_OK;
  283. try {
  284. WsbAssertHr(Add(pGuid1));
  285. } WsbCatch(hr);
  286. if (hr == S_OK) {
  287. (*passed)++;
  288. } else {
  289. (*failed)++;
  290. }
  291. // There should be 1 entry.
  292. hr = S_OK;
  293. try {
  294. WsbAssertHr(GetEntries(&entries));
  295. WsbAssert(1 == entries, E_FAIL);
  296. } WsbCatch(hr);
  297. if (hr == S_OK) {
  298. (*passed)++;
  299. } else {
  300. (*failed)++;
  301. }
  302. // It should not be empty.
  303. hr = S_OK;
  304. try {
  305. WsbAssert(IsEmpty() == S_FALSE, E_FAIL);
  306. } WsbCatch(hr);
  307. if (hr == S_OK) {
  308. (*passed)++;
  309. } else {
  310. (*failed)++;
  311. }
  312. // Does it think it has the item?
  313. hr = S_OK;
  314. try {
  315. WsbAssertHr(Find(pGuid1, IID_IWsbGuid, (void**) &pGuid2));
  316. WsbAssert(pGuid1->IsEqual(pGuid2) == S_OK, E_FAIL);
  317. } WsbCatch(hr);
  318. if (hr == S_OK) {
  319. (*passed)++;
  320. } else {
  321. (*failed)++;
  322. }
  323. // Add some more items
  324. pGuid2 = 0;
  325. WsbAssertHr(CoCreateInstance(CLSID_CWsbGuid, NULL, CLSCTX_ALL, IID_IWsbGuid, (void**) &pGuid2));
  326. WsbAssertHr(pGuid2->SetGuid(CLSID_CWsbGuid));
  327. WsbAssertHr(CoCreateInstance(CLSID_CWsbGuid, NULL, CLSCTX_ALL, IID_IWsbGuid, (void**) &pGuid3));
  328. WsbAssertHr(pGuid3->SetGuid(IID_IWsbGuid));
  329. // Add the items to the collection.
  330. hr = S_OK;
  331. try {
  332. WsbAssertHr(Add(pGuid2));
  333. } WsbCatch(hr);
  334. if (hr == S_OK) {
  335. (*passed)++;
  336. } else {
  337. (*failed)++;
  338. }
  339. hr = S_OK;
  340. try {
  341. WsbAssertHr(Add(pGuid3));
  342. } WsbCatch(hr);
  343. if (hr == S_OK) {
  344. (*passed)++;
  345. } else {
  346. (*failed)++;
  347. }
  348. // There should be 3 entries.
  349. hr = S_OK;
  350. try {
  351. WsbAssertHr(GetEntries(&entries));
  352. WsbAssert(3 == entries, E_FAIL);
  353. } WsbCatch(hr);
  354. if (hr == S_OK) {
  355. (*passed)++;
  356. } else {
  357. (*failed)++;
  358. }
  359. // How many copies does it have?
  360. hr = S_OK;
  361. try {
  362. WsbAssertHr(OccurencesOf(pGuid1, &entries));
  363. WsbAssert(2 == entries, E_FAIL);
  364. } WsbCatch(hr);
  365. if (hr == S_OK) {
  366. (*passed)++;
  367. } else {
  368. (*failed)++;
  369. }
  370. hr = S_OK;
  371. try {
  372. WsbAssertHr(OccurencesOf(pGuid3, &entries));
  373. WsbAssert(1 == entries, E_FAIL);
  374. } WsbCatch(hr);
  375. if (hr == S_OK) {
  376. (*passed)++;
  377. } else {
  378. (*failed)++;
  379. }
  380. // Remove one of the two identical items.
  381. hr = S_OK;
  382. try {
  383. WsbAssertHr(Remove(pGuid1, IID_IWsbGuid, (void**) &pGuid4));
  384. WsbAssertHr(pGuid1->IsEqual(pGuid4));
  385. pGuid4 = 0;
  386. } WsbCatch(hr);
  387. if (hr == S_OK) {
  388. (*passed)++;
  389. } else {
  390. (*failed)++;
  391. }
  392. // There should be 2 entries.
  393. hr = S_OK;
  394. try {
  395. WsbAssertHr(GetEntries(&entries));
  396. WsbAssert(2 == entries, E_FAIL);
  397. } WsbCatch(hr);
  398. if (hr == S_OK) {
  399. (*passed)++;
  400. } else {
  401. (*failed)++;
  402. }
  403. // How many copies does it have?
  404. hr = S_OK;
  405. try {
  406. WsbAssertHr(OccurencesOf(pGuid1, &entries));
  407. WsbAssert(1 == entries, E_FAIL);
  408. } WsbCatch(hr);
  409. if (hr == S_OK) {
  410. (*passed)++;
  411. } else {
  412. (*failed)++;
  413. }
  414. hr = S_OK;
  415. try {
  416. WsbAssertHr(OccurencesOf(pGuid3, &entries));
  417. WsbAssert(1 == entries, E_FAIL);
  418. } WsbCatch(hr);
  419. if (hr == S_OK) {
  420. (*passed)++;
  421. } else {
  422. (*failed)++;
  423. }
  424. // Can we find an entry?
  425. hr = S_OK;
  426. try {
  427. WsbAssertHr(Find(pGuid3, IID_IWsbGuid, (void**) &pGuid4));
  428. WsbAssertHr(pGuid4->IsEqual(pGuid3));
  429. pGuid4 = 0;
  430. } WsbCatch(hr);
  431. if (hr == S_OK) {
  432. (*passed)++;
  433. } else {
  434. (*failed)++;
  435. }
  436. // Does the collection still contain it?
  437. hr = S_OK;
  438. try {
  439. WsbAssert(Contains(pGuid1) == S_OK, E_FAIL);
  440. } WsbCatch(hr);
  441. if (hr == S_OK) {
  442. (*passed)++;
  443. } else {
  444. (*failed)++;
  445. }
  446. // Remove the last of the two identical items, and verify
  447. // that it can't be found. Then puit it back.
  448. hr = S_OK;
  449. try {
  450. WsbAssertHr(Remove(pGuid1, IID_IWsbGuid, (void**) &pGuid4));
  451. WsbAssert(Contains(pGuid1) == S_FALSE, E_FAIL);
  452. WsbAssertHr(Add(pGuid4));
  453. pGuid4 = 0;
  454. } WsbCatch(hr);
  455. if (hr == S_OK) {
  456. (*passed)++;
  457. } else {
  458. (*failed)++;
  459. }
  460. // Try out the persistence stuff.
  461. {
  462. CComPtr<IPersistFile> pFile1;
  463. CComPtr<IPersistFile> pFile2;
  464. CComPtr<IWsbCollection> pCollect2;
  465. WsbAssertHr(((IUnknown*)(IWsbCollection*)this)->QueryInterface(IID_IPersistFile, (void**) &pFile1));
  466. WsbAssertHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_ALL, IID_IPersistFile, (void**) &pFile2));
  467. // The item should be dirty.
  468. hr = S_OK;
  469. try {
  470. WsbAssert(pFile1->IsDirty() == S_OK, E_FAIL);
  471. } WsbCatch(hr);
  472. if (hr == S_OK) {
  473. (*passed)++;
  474. } else {
  475. (*failed)++;
  476. }
  477. // Save the item, and remember.
  478. hr = S_OK;
  479. try {
  480. WsbAssertHr(pFile1->Save(OLESTR("c:\\WsbTests\\WsbCollection.tst"), TRUE));
  481. } WsbCatch(hr);
  482. if (hr == S_OK) {
  483. (*passed)++;
  484. } else {
  485. (*failed)++;
  486. }
  487. // It shouldn't be dirty.
  488. hr = S_OK;
  489. try {
  490. WsbAssert(pFile1->IsDirty() == S_FALSE, E_FAIL);
  491. } WsbCatch(hr);
  492. if (hr == S_OK) {
  493. (*passed)++;
  494. } else {
  495. (*failed)++;
  496. }
  497. // Load it back in to another instance.
  498. hr = S_OK;
  499. try {
  500. WsbAssertHr(pFile2->Load(OLESTR("c:\\WsbTests\\WsbCollection.tst"), 0));
  501. WsbAssertHr(pFile2->QueryInterface(IID_IWsbCollection, (void**) &pCollect2));
  502. WsbAssert(pCollect2->Contains(pGuid1) == S_OK, E_FAIL);
  503. } WsbCatch(hr);
  504. if (hr == S_OK) {
  505. (*passed)++;
  506. } else {
  507. (*failed)++;
  508. }
  509. }
  510. // Remove and Release all the items.
  511. hr = S_OK;
  512. try {
  513. WsbAssertHr(RemoveAllAndRelease());
  514. } WsbCatch(hr);
  515. if (hr == S_OK) {
  516. (*passed)++;
  517. } else {
  518. (*failed)++;
  519. }
  520. // It should be empty.
  521. hr = S_OK;
  522. try {
  523. WsbAssert(IsEmpty() == S_OK, E_FAIL);
  524. } WsbCatch(hr);
  525. if (hr == S_OK) {
  526. (*passed)++;
  527. } else {
  528. (*failed)++;
  529. }
  530. } WsbCatch(hr);
  531. // Tally up the results
  532. if (*failed) {
  533. hr = S_FALSE;
  534. } else {
  535. hr = S_OK;
  536. }
  537. WsbTraceOut(OLESTR("CWsbCollection::Test"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  538. #endif // WSB_NO_TEST
  539. return(hr);
  540. }
  541. HRESULT
  542. CWsbCollection::Unlock(
  543. void
  544. )
  545. /*++
  546. Implements:
  547. CComObjectRoot::Unlock().
  548. --*/
  549. {
  550. LeaveCriticalSection(&m_CritSec);
  551. WsbTrace(OLESTR("CWsbCollection::Unlock - freed critical section\n"));
  552. return(S_OK);
  553. }
  554. // Class: CWsbIndexedCollection
  555. HRESULT
  556. CWsbIndexedCollection::Add(
  557. IN IUnknown* pCollectable
  558. )
  559. /*++
  560. Implements:
  561. IWsbCollection::Add().
  562. --*/
  563. {
  564. HRESULT hr = S_OK;
  565. WsbTraceIn(OLESTR("CWsbIndexedCollection::Add"), OLESTR(""));
  566. Lock();
  567. try {
  568. WsbAssert(0 != pCollectable, E_POINTER);
  569. WsbAffirmHr(AddAt(pCollectable, m_entries));
  570. } WsbCatch(hr);
  571. Unlock();
  572. WsbTraceOut(OLESTR("CWsbIndexedCollection::Add"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  573. return(hr);
  574. }
  575. HRESULT
  576. CWsbIndexedCollection::Append(
  577. IUnknown* pCollectable
  578. )
  579. /*++
  580. Implements:
  581. IWsbIndexedCollection::Append().
  582. --*/
  583. {
  584. HRESULT hr = S_OK;
  585. WsbTraceIn(OLESTR("CWsbIndexedCollection::Append"), OLESTR(""));
  586. hr = Add(pCollectable);
  587. WsbTraceOut(OLESTR("CWsbIndexedCollection::Append"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  588. return(hr);
  589. }
  590. HRESULT
  591. CWsbIndexedCollection::Enum(
  592. OUT IWsbEnum** ppEnum
  593. )
  594. /*++
  595. Implements:
  596. IWsbCollection::Enum().
  597. --*/
  598. {
  599. HRESULT hr = S_OK;
  600. CComPtr<IWsbEnum> pEnum;
  601. WsbTraceIn(OLESTR("CWsbIndexedCollection::Enum"), OLESTR(""));
  602. try {
  603. WsbAssert(0 != ppEnum, E_POINTER);
  604. // Create the instance, initialize it to point to this collection, and
  605. // return the pointer to the caller.
  606. WsbAffirmHr(CoCreateInstance(CLSID_CWsbIndexedEnum, NULL, CLSCTX_ALL, IID_IWsbEnum, (void**) &pEnum));
  607. WsbAffirmHr(pEnum->Init((IWsbCollection*) ((IWsbIndexedCollection*) this)));
  608. *ppEnum = pEnum;
  609. (*ppEnum)->AddRef();
  610. } WsbCatch(hr);
  611. WsbTraceOut(OLESTR("CWsbIndexedCollection::Enum"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  612. return(hr);
  613. }
  614. HRESULT
  615. CWsbIndexedCollection::EnumUnknown(
  616. OUT IEnumUnknown** ppEnum
  617. )
  618. /*++
  619. Implements:
  620. IWsbCollection::EnumUnknown().
  621. --*/
  622. {
  623. HRESULT hr = S_OK;
  624. CComPtr<IWsbEnum> pWsbEnum;
  625. WsbTraceIn(OLESTR("CWsbIndexedCollection::EnumUnknown"), OLESTR(""));
  626. try {
  627. WsbAssert(0 != ppEnum, E_POINTER);
  628. // Get the IWsbEnum interface, and then query for the IEnumUknown interface.
  629. WsbAffirmHr(Enum(&pWsbEnum));
  630. WsbAffirmHr(pWsbEnum->QueryInterface(IID_IEnumUnknown, (void**) ppEnum));
  631. } WsbCatch(hr);
  632. WsbTraceOut(OLESTR("CWsbIndexedCollection::EnumUnknown"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  633. return(hr);
  634. }
  635. HRESULT
  636. CWsbIndexedCollection::First(
  637. IN REFIID riid,
  638. OUT void** ppElement
  639. )
  640. /*++
  641. Implements:
  642. IWsbCollection::First().
  643. --*/
  644. {
  645. HRESULT hr = S_OK;
  646. WsbTraceIn(OLESTR("CWsbIndexedCollection::First"), OLESTR("iid = <%ls>"), WsbGuidAsString(riid));
  647. try {
  648. WsbAssert(0 != ppElement, E_POINTER);
  649. WsbAffirm(m_entries != 0, WSB_E_NOTFOUND);
  650. WsbAffirmHr(At(0, riid, ppElement));
  651. } WsbCatch(hr);
  652. WsbTraceOut(OLESTR("CWsbIndexedCollection::First"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  653. return(hr);
  654. }
  655. HRESULT
  656. CWsbIndexedCollection::Index(
  657. IN IUnknown* pCollectable,
  658. OUT ULONG* pIndex
  659. )
  660. /*++
  661. Implements:
  662. IWsbIndexedCollection::Index().
  663. --*/
  664. {
  665. HRESULT hr = S_OK;
  666. CComPtr<IWsbCollectable> pOut;
  667. WsbTraceIn(OLESTR("CWsbIndexedCollection::Index"), OLESTR(""));
  668. try {
  669. WsbAssert(0 != pCollectable, E_POINTER);
  670. WsbAssert(0 != pIndex, E_POINTER);
  671. // Find the first occurence of the item.
  672. WsbAffirmHr(CopyIfMatches(WSB_COLLECTION_MIN_INDEX, m_entries, pCollectable, 1, IID_IWsbCollectable, (void**) &pOut, NULL, pIndex));
  673. } WsbCatch(hr);
  674. WsbTraceOut(OLESTR("CWsbIndexedCollection::Index"), OLESTR("hr = <%ls>, index = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString(pIndex));
  675. return(hr);
  676. }
  677. HRESULT
  678. CWsbIndexedCollection::Last(
  679. IN REFIID riid,
  680. OUT void** ppElement
  681. )
  682. /*++
  683. Implements:
  684. IWsbCollection::Last().
  685. --*/
  686. {
  687. HRESULT hr = S_OK;
  688. WsbTraceIn(OLESTR("CWsbIndexedCollection::Last"), OLESTR("iid = <%ls>"), WsbGuidAsString(riid));
  689. try {
  690. // As long as we have some entires, get the last one.
  691. WsbAssert(0 != ppElement, E_POINTER);
  692. WsbAffirm(m_entries != 0, WSB_E_NOTFOUND);
  693. WsbAffirmHr(At(m_entries - 1, riid, ppElement));
  694. } WsbCatch(hr);
  695. WsbTraceOut(OLESTR("CWsbIndexedCollection::Last"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  696. return(hr);
  697. }
  698. HRESULT
  699. CWsbIndexedCollection::Prepend(
  700. IN IUnknown* pCollectable
  701. )
  702. /*++
  703. Implements:
  704. IWsbIndexedCollection::Prepend().
  705. --*/
  706. {
  707. HRESULT hr = S_OK;
  708. WsbTraceIn(OLESTR("CWsbIndexedCollection::Prepend"), OLESTR(""));
  709. try {
  710. WsbAssert(0 != pCollectable, E_POINTER);
  711. WsbAffirmHr(AddAt(pCollectable, 0));
  712. } WsbCatch(hr);
  713. WsbTraceOut(OLESTR("CWsbIndexedCollection::Prepend"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  714. return(hr);
  715. }
  716. HRESULT
  717. CWsbIndexedCollection::Remove(
  718. IN IUnknown* pCollectable,
  719. IN REFIID riid,
  720. OUT void** ppElement
  721. )
  722. /*++
  723. Implements:
  724. IWsbCollection::Remove().
  725. --*/
  726. {
  727. HRESULT hr = S_OK;
  728. ULONG index;
  729. WsbTraceIn(OLESTR("CWsbIndexedCollection::Remove"), OLESTR(""));
  730. Lock();
  731. try {
  732. // Can we find it in our array?
  733. WsbAffirmHr(Index(pCollectable, &index));
  734. // Remove it from the specified offset.
  735. WsbAffirmHr(RemoveAt(index, riid, ppElement));
  736. } WsbCatch(hr);
  737. Unlock();
  738. WsbTraceOut(OLESTR("CWsbIndexedCollection::Remove"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  739. return(hr);
  740. }
  741. HRESULT
  742. CWsbIndexedCollection::RemoveAllAndRelease(
  743. void
  744. )
  745. /*++
  746. Implements:
  747. IWsbIndexedCollection::RemoveAllAndRelease().
  748. --*/
  749. {
  750. HRESULT hr = S_OK;
  751. WsbTraceIn(OLESTR("CWsbIndexedCollection::RemoveAllAndRelease"), OLESTR(""));
  752. Lock();
  753. try {
  754. // Start at the end of the list, and keep removing from the
  755. // back. For some types of collections, this may not be the most
  756. // efficient way to remove all the elements.
  757. if (m_entries > 0) {
  758. ULONG index = m_entries - 1;
  759. while (index > 0) {
  760. WsbAffirmHr(RemoveAt(index, IID_IWsbCollectable, NULL));
  761. --index;
  762. }
  763. WsbAffirmHr(RemoveAt(index, IID_IWsbCollectable, NULL));
  764. }
  765. } WsbCatch(hr);
  766. Unlock();
  767. WsbTraceOut(OLESTR("CWsbIndexedCollection::RemoveAllAndRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  768. return(hr);
  769. }
  770. HRESULT
  771. CWsbIndexedCollection::Test(
  772. OUT USHORT* passed,
  773. OUT USHORT* failed
  774. )
  775. /*++
  776. Implements:
  777. IWsbTestable::Test().
  778. --*/
  779. {
  780. *passed = 0;
  781. *failed = 0;
  782. HRESULT hr = S_OK;
  783. #if !defined(WSB_NO_TEST)
  784. WsbTraceIn(OLESTR("CWsbIndexedCollection::Test"), OLESTR(""));
  785. try {
  786. // First run the standard tests for all collections.
  787. WsbAffirmHr(CWsbCollection::Test(passed, failed));
  788. // Now do the test that are specific for an indexed collection
  789. // Tally up the results
  790. if (*failed) {
  791. hr = S_FALSE;
  792. } else {
  793. hr = S_OK;
  794. }
  795. } WsbCatch(hr);
  796. WsbTraceOut(OLESTR("CWsbIndexedCollection::Test"), OLESTR("hr =<%ls>, testsRun = <%u>"), WsbHrAsString(hr));
  797. #endif // WSB_NO_TEST
  798. return(hr);
  799. }
  800. // Class: CWsbOrderedCollection
  801. HRESULT
  802. CWsbOrderedCollection::AddAt(
  803. IN IUnknown* pCollectable,
  804. IN ULONG index
  805. )
  806. /*++
  807. Implements:
  808. IWsbIndexedCollection::AddAt().
  809. --*/
  810. {
  811. HRESULT hr = S_OK;
  812. IWsbCollectable** pCollectableNew;
  813. WsbTraceIn(OLESTR("CWsbOrderedCollection::AddAt"), OLESTR("index = <%lu>"), index);
  814. Lock();
  815. try {
  816. // Are we beyond the end of the collection?
  817. WsbAffirm(index <= m_entries, WSB_E_OUTOFBOUNDS);
  818. // Is it full?
  819. if (m_entries >= m_maxEntries) {
  820. // Could we grow?
  821. WsbAffirm(((WSB_COLLECTION_MAX_INDEX - m_maxEntries) >= m_growBy), WSB_E_TOOLARGE);
  822. // Try to allocate a bigger array.
  823. pCollectableNew = (IWsbCollectable**) WsbRealloc((void*) m_pCollectable, (m_maxEntries + m_growBy) * sizeof(IWsbCollectable*));
  824. WsbAffirm(pCollectableNew != NULL, E_OUTOFMEMORY);
  825. m_pCollectable = pCollectableNew;
  826. m_maxEntries += m_growBy;
  827. }
  828. // If we have room, then add it to the collection.
  829. // First shift any existing entries.
  830. for (ULONG tmpIndex = m_entries; tmpIndex > index; tmpIndex--) {
  831. m_pCollectable[tmpIndex] = m_pCollectable[tmpIndex - 1];
  832. }
  833. // Now add the new entry.
  834. m_entries++;
  835. WsbAffirmHr(pCollectable->QueryInterface(IID_IWsbCollectable,
  836. (void**)&m_pCollectable[index]));
  837. m_isDirty = TRUE;
  838. } WsbCatch(hr);
  839. Unlock();
  840. WsbTraceOut(OLESTR("CWsbOrderedCollection::AddAt"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  841. return(hr);
  842. }
  843. HRESULT
  844. CWsbOrderedCollection::At(
  845. IN ULONG index,
  846. IN REFIID riid,
  847. OUT void** ppElement
  848. )
  849. /*++
  850. Implements:
  851. IWsbIndexedCollection::At().
  852. --*/
  853. {
  854. HRESULT hr = S_OK;
  855. WsbTraceIn(OLESTR("CWsbOrderedCollection::At"), OLESTR("index = <%lu>, riid = <%ls>"), index, WsbGuidAsString(riid));
  856. Lock();
  857. try {
  858. WsbAffirm(index < m_entries, WSB_E_OUTOFBOUNDS);
  859. WsbAssert(0 != ppElement, E_POINTER);
  860. // If they asked for an interface, then try to get the desired
  861. // interface for the item specified.
  862. WsbAffirmHr((m_pCollectable[index])->QueryInterface(riid, (void**) ppElement));
  863. } WsbCatch(hr);
  864. Unlock();
  865. WsbTraceOut(OLESTR("CWsbOrderedCollection::At"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  866. return(hr);
  867. }
  868. HRESULT
  869. CWsbOrderedCollection::Copy(
  870. IN ULONG start,
  871. IN ULONG stop,
  872. IN REFIID riid,
  873. OUT void** elements,
  874. OUT ULONG* pElementsFetched
  875. )
  876. /*++
  877. Implements:
  878. IWsbIndexedCollection::Copy().
  879. --*/
  880. {
  881. HRESULT hr = S_OK;
  882. ULONG toDo;
  883. ULONG copied = 0;
  884. ULONG index;
  885. BOOL isIncrement = TRUE;
  886. WsbTraceIn(OLESTR("CWsbOrderedCollection::Copy"), OLESTR("start = <%lu>, stop = <%lu>, riid = <%ls>"), start, stop, WsbGuidAsString(riid));
  887. Lock();
  888. try {
  889. WsbAssert(0 != elements, E_POINTER);
  890. WsbAssert(0 != pElementsFetched, E_POINTER);
  891. WsbAffirm(start < m_entries, WSB_E_NOTFOUND);
  892. // Determine how many elements to copy, and the order in which we are
  893. // going (increasing vs. decreasing).
  894. if (start <= stop) {
  895. toDo = stop - start + 1;
  896. } else {
  897. toDo = start - stop + 1;
  898. isIncrement = FALSE;
  899. }
  900. // Iterate over all the items in the range specified, and copy
  901. // the interface in to the target array.
  902. for (copied = 0, index = start; ((copied < toDo) && (index < m_entries)); copied++, isIncrement ? index++ : index--) {
  903. WsbAffirmHr(m_pCollectable[index]->QueryInterface(riid, (void**) &(elements[copied])));
  904. }
  905. // Let them know if we didn't fill up the return buffer.
  906. if (copied < toDo) {
  907. hr = S_FALSE;
  908. }
  909. } WsbCatch(hr);
  910. *pElementsFetched = copied;
  911. Unlock();
  912. WsbTraceOut(OLESTR("CWsbOrderedCollection::Copy"), OLESTR("hr = <%ls>, elementsFetched = <%lu>"), WsbHrAsString(hr), copied);
  913. return(hr);
  914. }
  915. HRESULT
  916. CWsbOrderedCollection::CopyIfMatches(
  917. ULONG start,
  918. ULONG stop,
  919. IUnknown* pObject,
  920. ULONG element,
  921. REFIID riid,
  922. void** elements,
  923. ULONG* pElementsFetched,
  924. ULONG* pStoppedAt
  925. )
  926. /*++
  927. Implements:
  928. IWsbIndexedCollection::CopyIfMatches().
  929. --*/
  930. {
  931. HRESULT hr = S_OK;
  932. ULONG copied = 0;
  933. ULONG index = start;
  934. ULONG end = stop;
  935. BOOL done = FALSE;
  936. CComPtr<IWsbCollectable> pCollectable;
  937. WsbTraceIn(OLESTR("CWsbOrderedCollection::CopyIfMatches"), OLESTR("start = <%lu>, stop = <%lu>, riid = <%ls>"), start, stop, WsbGuidAsString(riid));
  938. Lock();
  939. try {
  940. WsbAssert(0 != elements, E_POINTER);
  941. WsbAssert(0 != pStoppedAt, E_POINTER);
  942. WsbAssert((1 == element) || (0 != pElementsFetched), E_POINTER);
  943. WsbAssert(0 != element, E_INVALIDARG);
  944. WsbAffirm(start < m_entries, WSB_E_NOTFOUND);
  945. WsbAffirmHr(pObject->QueryInterface(IID_IWsbCollectable,
  946. (void **)&pCollectable));
  947. if (start <= stop) {
  948. // Incrementing.
  949. if (stop >= m_entries) {
  950. end = m_entries - 1;
  951. }
  952. // Continue from here to the end of the range.
  953. while (!done) {
  954. if (pCollectable->IsEqual(m_pCollectable[index]) == S_OK) {
  955. WsbAffirmHr(m_pCollectable[index]->QueryInterface(riid, (void**) &(elements[copied])));
  956. copied++;
  957. }
  958. if ((copied < element) && (index < end)) {
  959. index++;
  960. }
  961. else {
  962. done = TRUE;
  963. }
  964. }
  965. } else {
  966. // Decrementing..
  967. while (!done) {
  968. if (m_pCollectable[index]->IsEqual(pCollectable) == S_OK) {
  969. WsbAffirmHr(m_pCollectable[index]->QueryInterface(riid, (void**) &(elements[copied])));
  970. copied++;
  971. }
  972. if ((copied < element) && (index > end)) {
  973. index--;
  974. }
  975. else {
  976. done = TRUE;
  977. }
  978. }
  979. }
  980. if (0 != pElementsFetched) {
  981. *pElementsFetched = copied;
  982. }
  983. *pStoppedAt = index;
  984. // If we didn't find anything, then let them know.
  985. WsbAffirm(0 != copied, WSB_E_NOTFOUND);
  986. // Let them know if we didn't fill the output buffer,
  987. // and t=let them know the last index that was checked.
  988. if (copied < element) {
  989. hr = S_FALSE;
  990. }
  991. } WsbCatch(hr);
  992. Unlock();
  993. WsbTraceOut(OLESTR("CWsbOrderedCollection::CopyIfMatches"), OLESTR("hr = <%ls>, elementsFetched = <%lu>, stoppedAt = <%ls>"), WsbHrAsString(hr), copied, WsbPtrToUlongAsString(pStoppedAt));
  994. return(hr);
  995. }
  996. HRESULT
  997. CWsbOrderedCollection::FinalConstruct(
  998. void
  999. )
  1000. /*++
  1001. Implements:
  1002. CComObjectRoot::FinalConstruct().
  1003. --*/
  1004. {
  1005. HRESULT hr = S_OK;
  1006. try {
  1007. WsbAffirmHr(CWsbCollection::FinalConstruct());
  1008. m_pCollectable = NULL;
  1009. m_maxEntries = 0;
  1010. m_growBy = 256;
  1011. } WsbCatch(hr);
  1012. return(hr);
  1013. }
  1014. void
  1015. CWsbOrderedCollection::FinalRelease(
  1016. void
  1017. )
  1018. /*++
  1019. Implements:
  1020. CComObjectRoot::FinalRelease().
  1021. --*/
  1022. {
  1023. if (0 != m_pCollectable) {
  1024. Lock();
  1025. RemoveAllAndRelease();
  1026. WsbFree((void*) m_pCollectable);
  1027. Unlock();
  1028. }
  1029. CWsbCollection::FinalRelease();
  1030. }
  1031. HRESULT
  1032. CWsbOrderedCollection::GetClassID(
  1033. OUT CLSID* pClsid
  1034. )
  1035. /*++
  1036. Implements:
  1037. IPersist::GetClassID().
  1038. --*/
  1039. {
  1040. HRESULT hr = S_OK;
  1041. WsbTraceIn(OLESTR("CWsbOrderedCollection::GetClassID"), OLESTR(""));
  1042. try {
  1043. WsbAssert(0 != pClsid, E_POINTER);
  1044. *pClsid = CLSID_CWsbOrderedCollection;
  1045. } WsbCatch(hr);
  1046. WsbTraceOut(OLESTR("CWsbOrderedCollection::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  1047. return(hr);
  1048. }
  1049. HRESULT
  1050. CWsbOrderedCollection::GetSizeMax(
  1051. OUT ULARGE_INTEGER* pSize
  1052. )
  1053. /*++
  1054. Implements:
  1055. IPersistStream::GetSizeMax().
  1056. --*/
  1057. {
  1058. HRESULT hr = S_OK;
  1059. IPersistStream* pPersistStream;
  1060. ULARGE_INTEGER size;
  1061. WsbTraceIn(OLESTR("CWsbOrderedCollection::GetSizeMax"), OLESTR(""));
  1062. try {
  1063. WsbAssert(0 == pSize, E_POINTER);
  1064. // The size of the header information.
  1065. pSize->QuadPart = 3 * WsbPersistSizeOf(ULONG);
  1066. // If we have entries, then add in the size for the maximum number
  1067. // of entries, assuming that they are all the same size.
  1068. if (m_entries != 0) {
  1069. WsbAffirmHr(First(IID_IPersistStream, (void**) &pPersistStream));
  1070. WsbAffirmHr(pPersistStream->GetSizeMax(&size));
  1071. pSize->QuadPart += (m_maxEntries * (size.QuadPart));
  1072. }
  1073. } WsbCatch(hr);
  1074. WsbTraceOut(OLESTR("CWsbOrderedCollection::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
  1075. return(hr);
  1076. }
  1077. HRESULT
  1078. CWsbOrderedCollection::Load(
  1079. IN IStream* pStream
  1080. )
  1081. /*++
  1082. Implements:
  1083. IPersistStream::Load().
  1084. --*/
  1085. {
  1086. HRESULT hr = S_OK;
  1087. CComPtr<IWsbCollectable> pCollectable;
  1088. ULONG entries;
  1089. ULONG growBy;
  1090. ULONG maxEntries;
  1091. WsbTraceIn(OLESTR("CWsbOrderedCollection::Load"),
  1092. OLESTR("m_entries = %ld, m_maxEntries = %ld, m_growBy = %ld, m_pCollectable = %p"),
  1093. m_entries, m_maxEntries, m_growBy, m_pCollectable);
  1094. Lock();
  1095. try {
  1096. IWsbCollectable** pTmp;
  1097. // Make sure the collection starts empty
  1098. if (m_entries != 0) {
  1099. WsbAffirmHr(RemoveAllAndRelease());
  1100. }
  1101. // Do the easy stuff, but make sure that this order matches the order
  1102. // in the save method.
  1103. WsbAffirmHr(WsbLoadFromStream(pStream, &entries));
  1104. WsbAffirmHr(WsbLoadFromStream(pStream, &maxEntries));
  1105. WsbAffirmHr(WsbLoadFromStream(pStream, &growBy));
  1106. WsbAffirm(entries <= maxEntries, WSB_E_PERSISTENCE_FILE_CORRUPT);
  1107. // Allocate space for the array.
  1108. if (entries > m_maxEntries) {
  1109. pTmp = (IWsbCollectable**) WsbRealloc(m_pCollectable,
  1110. maxEntries * sizeof(IWsbCollectable*));
  1111. WsbAffirm(0 != pTmp, E_OUTOFMEMORY);
  1112. // Remember our new buffer.
  1113. m_pCollectable = pTmp;
  1114. m_maxEntries = maxEntries;
  1115. }
  1116. m_growBy = growBy;
  1117. // Now do the items in the collection.
  1118. for (ULONG index = 0; (index < entries); index++) {
  1119. WsbAffirmHr(OleLoadFromStream(pStream, IID_IWsbCollectable, (void**) &pCollectable));
  1120. WsbAffirmHr(Append(pCollectable));
  1121. pCollectable = 0;
  1122. }
  1123. } WsbCatch(hr);
  1124. Unlock();
  1125. WsbTraceOut(OLESTR("CWsbOrderedCollection::Load"),
  1126. OLESTR("m_entries = %ld, m_maxEntries = %ld, m_growBy = %ld, m_pCollectable = %p"),
  1127. m_entries, m_maxEntries, m_growBy, m_pCollectable);
  1128. return(hr);
  1129. }
  1130. HRESULT
  1131. CWsbOrderedCollection::RemoveAt(
  1132. IN ULONG index,
  1133. IN REFIID riid,
  1134. OUT void** ppElement
  1135. )
  1136. /*++
  1137. Implements:
  1138. IWsbIndexedCollection::RemoveAt().
  1139. --*/
  1140. {
  1141. HRESULT hr = S_OK;
  1142. WsbTraceIn(OLESTR("CWsbOrderedCollection::RemoveAt"), OLESTR("index = <%lu>, riid = <%ls>"), index, WsbGuidAsString(riid));
  1143. Lock();
  1144. try {
  1145. // Make sure that the index is in range.
  1146. WsbAffirm(index < m_entries, WSB_E_OUTOFBOUNDS);
  1147. // If they asked for an interface, then try to get the desired
  1148. // interface for the item specified.
  1149. if (0 != ppElement) {
  1150. WsbAffirmHr(m_pCollectable[index]->QueryInterface(riid, (void**) ppElement));
  1151. }
  1152. // Remove the item
  1153. m_pCollectable[index]->Release();
  1154. // Now shift all the items in the collection.
  1155. for (ULONG tmpIndex = index; (tmpIndex < (m_entries - 1)); tmpIndex++) {
  1156. m_pCollectable[tmpIndex] = m_pCollectable[tmpIndex + 1];
  1157. }
  1158. m_entries--;
  1159. m_isDirty = TRUE;
  1160. // If the collection has really shrunk in size, then we
  1161. // should free up some memory.
  1162. if ((m_maxEntries - m_entries) >= (2 * m_growBy)) {
  1163. // Try to allocate a smaller array.
  1164. IWsbCollectable** pCollectableNew = (IWsbCollectable**) WsbRealloc((void*) m_pCollectable, (m_maxEntries - m_growBy) * sizeof(IWsbCollectable*));
  1165. WsbAffirm(pCollectableNew != NULL, E_OUTOFMEMORY);
  1166. m_pCollectable = pCollectableNew;
  1167. m_maxEntries -= m_growBy;
  1168. }
  1169. } WsbCatch(hr);
  1170. Unlock();
  1171. WsbTraceOut(OLESTR("CWsbOrderedCollection::RemoveAt"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1172. return(hr);
  1173. }
  1174. HRESULT
  1175. CWsbOrderedCollection::Save(
  1176. IN IStream* pStream,
  1177. IN BOOL clearDirty
  1178. )
  1179. /*++
  1180. Implements:
  1181. IPersistStream::Save().
  1182. --*/
  1183. {
  1184. HRESULT hr = S_OK;
  1185. WsbTraceIn(OLESTR("CWsbOrderedCollection::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  1186. Lock();
  1187. try {
  1188. // Check for consistency first
  1189. WsbAffirm(m_entries <= m_maxEntries, WSB_E_INVALID_DATA);
  1190. // Do the easy stuff, but make sure that this order matches the order
  1191. // in the load method.
  1192. WsbAffirmHr(WsbSaveToStream(pStream, m_entries));
  1193. WsbAffirmHr(WsbSaveToStream(pStream, m_maxEntries));
  1194. WsbAffirmHr(WsbSaveToStream(pStream, m_growBy));
  1195. // Now do the items in the collection.
  1196. if (m_entries > 0) {
  1197. CComPtr<IWsbEnum> pEnum;
  1198. CComPtr<IPersistStream> pPersistStream;
  1199. // We need to enumerate the items in the collection.
  1200. WsbAffirmHr(Enum(&pEnum));
  1201. for (hr = pEnum->First(IID_IPersistStream, (void**) &pPersistStream);
  1202. SUCCEEDED(hr);
  1203. hr = pEnum->Next(IID_IPersistStream, (void**) &pPersistStream)) {
  1204. hr = OleSaveToStream(pPersistStream, pStream);
  1205. pPersistStream = 0;
  1206. }
  1207. WsbAssert(hr == WSB_E_NOTFOUND, hr);
  1208. hr = S_OK;
  1209. }
  1210. // If we got it saved and we were asked to clear the dirty bit, then
  1211. // do so now.
  1212. if (clearDirty) {
  1213. m_isDirty = FALSE;
  1214. }
  1215. } WsbCatch(hr);
  1216. Unlock();
  1217. WsbTraceOut(OLESTR("CWsbOrderedCollection::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1218. return(hr);
  1219. }