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.

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