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.

983 lines
21 KiB

  1. #include "namellst.h"
  2. #include "sfstr.h"
  3. #include "dbg.h"
  4. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  5. //=============================================================================
  6. //=============================================================================
  7. //== CNamedElem ==
  8. //=============================================================================
  9. //=============================================================================
  10. ///////////////////////////////////////////////////////////////////////////////
  11. // Public
  12. HRESULT CNamedElem::GetName(LPTSTR psz, DWORD cch, DWORD* pcchRequired)
  13. {
  14. return SafeStrCpyNReq(psz, _pszElemName, cch, pcchRequired);
  15. }
  16. #ifdef DEBUG
  17. LPCTSTR CNamedElem::DbgGetName()
  18. {
  19. return _pszElemName;
  20. }
  21. #endif
  22. ///////////////////////////////////////////////////////////////////////////////
  23. // Protected
  24. CNamedElem::CNamedElem() : _pszElemName(NULL)
  25. {}
  26. CNamedElem::~CNamedElem()
  27. {
  28. if (_pszElemName)
  29. {
  30. _FreeName();
  31. }
  32. }
  33. HRESULT CNamedElem::_SetName(LPCTSTR pszElemName)
  34. {
  35. ASSERT(!_pszElemName);
  36. HRESULT hres;
  37. DWORD cch = lstrlen(pszElemName) + 1;
  38. ASSERT(cch);
  39. _pszElemName = (LPTSTR)LocalAlloc(LPTR, cch * sizeof(TCHAR));
  40. if (_pszElemName)
  41. {
  42. hres = SafeStrCpyN(_pszElemName, pszElemName, cch);
  43. }
  44. else
  45. {
  46. hres = E_OUTOFMEMORY;
  47. }
  48. return hres;
  49. }
  50. HRESULT CNamedElem::_FreeName()
  51. {
  52. ASSERT(_pszElemName);
  53. LocalFree((HLOCAL)_pszElemName);
  54. return S_OK;
  55. }
  56. //=============================================================================
  57. //=============================================================================
  58. //== CNamedElemList ==
  59. //=============================================================================
  60. //=============================================================================
  61. ///////////////////////////////////////////////////////////////////////////////
  62. // Public
  63. HRESULT CNamedElemList::Init(NAMEDELEMCREATEFCT createfct,
  64. NAMEDELEMGETFILLENUMFCT enumfct)
  65. {
  66. HRESULT hres;
  67. _createfct = createfct;
  68. _enumfct = enumfct;
  69. _pcs = new CRefCountedCritSect();
  70. if (_pcs)
  71. {
  72. if (InitializeCriticalSectionAndSpinCount(_pcs, 0))
  73. {
  74. hres = S_OK;
  75. }
  76. else
  77. {
  78. delete _pcs;
  79. _pcs = NULL;
  80. hres = E_FAIL;
  81. }
  82. }
  83. else
  84. {
  85. hres = E_OUTOFMEMORY;
  86. }
  87. return hres;
  88. }
  89. HRESULT CNamedElemList::GetOrAdd(LPCTSTR pszElemName, CNamedElem** ppelem)
  90. {
  91. HRESULT hres = E_INVALIDARG;
  92. *ppelem = NULL;
  93. if (pszElemName)
  94. {
  95. CElemSlot* pes;
  96. EnterCriticalSection(_pcs);
  97. hres = _GetElemSlot(pszElemName, &pes);
  98. if (SUCCEEDED(hres))
  99. {
  100. if (S_FALSE != hres)
  101. {
  102. // Got one
  103. hres = pes->GetNamedElem(ppelem);
  104. pes->RCRelease();
  105. }
  106. else
  107. {
  108. // None found
  109. hres = _Add(pszElemName, ppelem);
  110. if (SUCCEEDED(hres))
  111. {
  112. #ifdef DEBUG
  113. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Added to '%s': '%s'"),
  114. _szDebugName, pszElemName);
  115. #endif
  116. hres = S_FALSE;
  117. }
  118. }
  119. }
  120. LeaveCriticalSection(_pcs);
  121. }
  122. return hres;
  123. }
  124. HRESULT CNamedElemList::Get(LPCTSTR pszElemName, CNamedElem** ppelem)
  125. {
  126. HRESULT hres = E_INVALIDARG;
  127. *ppelem = NULL;
  128. if (pszElemName)
  129. {
  130. CElemSlot* pes;
  131. EnterCriticalSection(_pcs);
  132. hres = _GetElemSlot(pszElemName, &pes);
  133. if (SUCCEEDED(hres))
  134. {
  135. if (S_FALSE != hres)
  136. {
  137. // Got one
  138. hres = pes->GetNamedElem(ppelem);
  139. pes->RCRelease();
  140. }
  141. }
  142. LeaveCriticalSection(_pcs);
  143. }
  144. return hres;
  145. }
  146. HRESULT CNamedElemList::Add(LPCTSTR pszElemName, CNamedElem** ppelem)
  147. {
  148. HRESULT hres = E_INVALIDARG;
  149. if (pszElemName)
  150. {
  151. EnterCriticalSection(_pcs);
  152. hres = _Add(pszElemName, ppelem);
  153. LeaveCriticalSection(_pcs);
  154. #ifdef DEBUG
  155. if (SUCCEEDED(hres))
  156. {
  157. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Added to '%s': '%s'"),
  158. _szDebugName, pszElemName);
  159. }
  160. #endif
  161. }
  162. return hres;
  163. }
  164. HRESULT CNamedElemList::Remove(LPCTSTR pszElemName)
  165. {
  166. HRESULT hres = E_INVALIDARG;
  167. if (pszElemName)
  168. {
  169. EnterCriticalSection(_pcs);
  170. hres = _Remove(pszElemName);
  171. LeaveCriticalSection(_pcs);
  172. #ifdef DEBUG
  173. if (SUCCEEDED(hres))
  174. {
  175. if (S_FALSE != hres)
  176. {
  177. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Removed from '%s': '%s'"),
  178. _szDebugName, pszElemName);
  179. }
  180. else
  181. {
  182. TRACE(TF_NAMEDELEMLISTMODIF,
  183. TEXT("TRIED to remove from '%s': '%s'"),
  184. _szDebugName, pszElemName);
  185. }
  186. }
  187. #endif
  188. }
  189. return hres;
  190. }
  191. HRESULT CNamedElemList::ReEnum()
  192. {
  193. HRESULT hres = E_FAIL;
  194. if (_enumfct)
  195. {
  196. #ifdef DEBUG
  197. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("ReEnum '%s' beginning"),
  198. _szDebugName);
  199. #endif
  200. EnterCriticalSection(_pcs);
  201. hres = _EmptyList();
  202. if (SUCCEEDED(hres))
  203. {
  204. CFillEnum* pfillenum;
  205. hres = _enumfct(&pfillenum);
  206. if (SUCCEEDED(hres))
  207. {
  208. TCHAR szElemName[MAX_PATH];
  209. LPTSTR pszElemName = szElemName;
  210. DWORD cchReq;
  211. do
  212. {
  213. hres = pfillenum->Next(szElemName, ARRAYSIZE(szElemName),
  214. &cchReq);
  215. if (S_FALSE != hres)
  216. {
  217. if (E_BUFFERTOOSMALL == hres)
  218. {
  219. pszElemName = (LPTSTR)LocalAlloc(LPTR, cchReq *
  220. sizeof(TCHAR));
  221. if (pszElemName)
  222. {
  223. hres = pfillenum->Next(pszElemName, cchReq,
  224. &cchReq);
  225. }
  226. else
  227. {
  228. hres = E_OUTOFMEMORY;
  229. }
  230. }
  231. if (SUCCEEDED(hres) && (S_FALSE != hres))
  232. {
  233. hres = _Add(pszElemName, NULL);
  234. #ifdef DEBUG
  235. if (SUCCEEDED(hres))
  236. {
  237. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Added to '%s': '%s'"),
  238. _szDebugName, pszElemName);
  239. }
  240. #endif
  241. if (FAILED(hres))
  242. {
  243. // We want to continue the enumeration
  244. hres = S_OK;
  245. }
  246. }
  247. if (pszElemName && (pszElemName != szElemName))
  248. {
  249. LocalFree((HLOCAL)pszElemName);
  250. }
  251. }
  252. }
  253. while (SUCCEEDED(hres) && (S_FALSE != hres));
  254. pfillenum->RCRelease();
  255. }
  256. }
  257. LeaveCriticalSection(_pcs);
  258. #ifdef DEBUG
  259. if (SUCCEEDED(hres))
  260. {
  261. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("ReEnumed '%s'"), _szDebugName);
  262. }
  263. #endif
  264. }
  265. return hres;
  266. }
  267. HRESULT CNamedElemList::EmptyList()
  268. {
  269. HRESULT hres;
  270. EnterCriticalSection(_pcs);
  271. hres = _EmptyList();
  272. LeaveCriticalSection(_pcs);
  273. #ifdef DEBUG
  274. if (SUCCEEDED(hres))
  275. {
  276. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Emptied '%s'"), _szDebugName);
  277. }
  278. #endif
  279. return hres;
  280. }
  281. HRESULT CNamedElemList::GetEnum(CNamedElemEnum** ppenum)
  282. {
  283. HRESULT hres;
  284. CNamedElemEnum* penum = new CNamedElemEnum();
  285. if (penum)
  286. {
  287. CElemSlot* pesTail;
  288. EnterCriticalSection(_pcs);
  289. hres = _GetTail(&pesTail);
  290. if (SUCCEEDED(hres))
  291. {
  292. hres = penum->_Init(pesTail, _pcs);
  293. if (SUCCEEDED(hres))
  294. {
  295. *ppenum = penum;
  296. }
  297. else
  298. {
  299. delete penum;
  300. }
  301. if (pesTail)
  302. {
  303. pesTail->RCRelease();
  304. }
  305. }
  306. LeaveCriticalSection(_pcs);
  307. }
  308. else
  309. {
  310. hres = E_OUTOFMEMORY;
  311. }
  312. return hres;
  313. }
  314. CNamedElemList::CNamedElemList() : _pcs(NULL), _pesHead(NULL)
  315. {
  316. #ifdef DEBUG
  317. _szDebugName[0] = 0;
  318. #endif
  319. }
  320. void CNamedElemList::RealRemoveElemSlotCallback(CElemSlot* pes)
  321. {
  322. ASSERT(pes == _pesHead);
  323. _pesHead = pes->GetNext();
  324. if (_pesHead)
  325. {
  326. // we don't keep a ref on the head
  327. _pesHead->RCRelease();
  328. _pesHead->SetCallbackPointer(this);
  329. }
  330. }
  331. CNamedElemList::~CNamedElemList()
  332. {
  333. if (_pcs)
  334. {
  335. EnterCriticalSection(_pcs);
  336. if (_pesHead)
  337. {
  338. // This list is going away. We don't want this CElemSlot to
  339. // callback on an invalid pointer.
  340. _pesHead->SetCallbackPointer(NULL);
  341. }
  342. _EmptyList();
  343. LeaveCriticalSection(_pcs);
  344. DeleteCriticalSection(_pcs);
  345. _pcs->RCRelease();
  346. }
  347. }
  348. ///////////////////////////////////////////////////////////////////////////////
  349. // Private
  350. // All these fcts have to be called from within The critical section
  351. HRESULT CNamedElemList::_Add(LPCTSTR pszElemName, CNamedElem** ppelem)
  352. {
  353. CNamedElem* pelem;
  354. HRESULT hres = _createfct(&pelem);
  355. if (SUCCEEDED(hres))
  356. {
  357. hres = pelem->Init(pszElemName);
  358. if (SUCCEEDED(hres))
  359. {
  360. CElemSlot* pes = new CElemSlot();
  361. if (pes)
  362. {
  363. // This takes an additionnal ref on pelem
  364. hres = pes->Init(pelem, NULL, _pesHead);
  365. if (SUCCEEDED(hres))
  366. {
  367. if (_pesHead)
  368. {
  369. _pesHead->SetCallbackPointer(NULL);
  370. _pesHead->SetPrev(pes);
  371. }
  372. _pesHead = pes;
  373. _pesHead->SetCallbackPointer(this);
  374. }
  375. else
  376. {
  377. pes->RCRelease();
  378. }
  379. }
  380. else
  381. {
  382. hres = E_OUTOFMEMORY;
  383. }
  384. }
  385. pelem->RCRelease();
  386. if (FAILED(hres))
  387. {
  388. pelem = NULL;
  389. }
  390. }
  391. if (ppelem)
  392. {
  393. if (pelem)
  394. {
  395. pelem->RCAddRef();
  396. }
  397. *ppelem = pelem;
  398. }
  399. return hres;
  400. }
  401. HRESULT CNamedElemList::_GetTail(CElemSlot** ppes)
  402. {
  403. HRESULT hr;
  404. CElemSlot* pesLastValid = _GetValidHead();
  405. if (pesLastValid)
  406. {
  407. CElemSlot* pesOld = pesLastValid;
  408. while (NULL != (pesLastValid = pesLastValid->GetNextValid()))
  409. {
  410. pesOld->RCRelease();
  411. pesOld = pesLastValid;
  412. }
  413. pesLastValid = pesOld;
  414. hr = S_OK;
  415. }
  416. else
  417. {
  418. hr = S_FALSE;
  419. }
  420. // pesLastValid is already RCAddRef'ed
  421. *ppes = pesLastValid;
  422. return hr;
  423. }
  424. HRESULT CNamedElemList::_GetElemSlot(LPCTSTR pszElemName, CElemSlot** ppes)
  425. {
  426. HRESULT hres = S_FALSE;
  427. CElemSlot* pes = _GetValidHead();
  428. CElemSlot* pesOld = pes;
  429. while (pes && SUCCEEDED(hres) && (S_FALSE == hres))
  430. {
  431. CNamedElem* pelem;
  432. hres = pes->GetNamedElem(&pelem);
  433. if (SUCCEEDED(hres))
  434. {
  435. TCHAR szElemName[MAX_PATH];
  436. LPTSTR pszElemNameLocal = szElemName;
  437. DWORD cchReq;
  438. hres = pelem->GetName(szElemName, ARRAYSIZE(szElemName), &cchReq);
  439. if (E_BUFFERTOOSMALL == hres)
  440. {
  441. pszElemNameLocal = (LPTSTR)LocalAlloc(LPTR, cchReq *
  442. sizeof(TCHAR));
  443. if (pszElemNameLocal)
  444. {
  445. hres = pelem->GetName(pszElemNameLocal, cchReq, &cchReq);
  446. }
  447. else
  448. {
  449. hres = E_OUTOFMEMORY;
  450. }
  451. }
  452. pelem->RCRelease();
  453. if (SUCCEEDED(hres))
  454. {
  455. if (!lstrcmpi(pszElemNameLocal, pszElemName))
  456. {
  457. // Found it!
  458. pes->RCAddRef();
  459. *ppes = pes;
  460. hres = S_OK;
  461. }
  462. else
  463. {
  464. ASSERT(pesOld == pes);
  465. pes = pes->GetNextValid();
  466. hres = S_FALSE;
  467. }
  468. }
  469. if (pszElemNameLocal && (pszElemNameLocal != szElemName))
  470. {
  471. LocalFree((HLOCAL)pszElemNameLocal);
  472. }
  473. }
  474. pesOld->RCRelease();
  475. pesOld = pes;
  476. }
  477. return hres;
  478. }
  479. HRESULT CNamedElemList::_Remove(LPCTSTR pszElemName)
  480. {
  481. ASSERT(pszElemName);
  482. CElemSlot* pes;
  483. HRESULT hres = _GetElemSlot(pszElemName, &pes);
  484. if (SUCCEEDED(hres) && (S_FALSE != hres))
  485. {
  486. hres = pes->Remove();
  487. // 2: one to balance the _GetElemSlot and one to remove from list
  488. pes->RCRelease();
  489. pes->RCRelease();
  490. }
  491. return hres;
  492. }
  493. HRESULT CNamedElemList::_EmptyList()
  494. {
  495. HRESULT hres = S_FALSE;
  496. CElemSlot* pes = _GetValidHead();
  497. if (_pesHead)
  498. {
  499. _pesHead->SetCallbackPointer(NULL);
  500. }
  501. while (pes)
  502. {
  503. CElemSlot* pesOld = pes;
  504. pes->Remove();
  505. pes = pes->GetNextValid();
  506. // 2: one to balance the _GetValidHead/GetNextValid and one to remove
  507. // from list
  508. pesOld->RCRelease();
  509. pesOld->RCRelease();
  510. }
  511. _pesHead = NULL;
  512. return hres;
  513. }
  514. CElemSlot* CNamedElemList::_GetValidHead()
  515. {
  516. CElemSlot* pes = _pesHead;
  517. if (pes)
  518. {
  519. if (pes->IsValid())
  520. {
  521. pes->RCAddRef();
  522. }
  523. else
  524. {
  525. pes = pes->GetNextValid();
  526. }
  527. }
  528. return pes;
  529. }
  530. #ifdef DEBUG
  531. HRESULT CNamedElemList::InitDebug(LPWSTR pszDebugName)
  532. {
  533. return SafeStrCpyN(_szDebugName, pszDebugName,
  534. ARRAYSIZE(_szDebugName));
  535. }
  536. void CNamedElemList::AssertNoDuplicate()
  537. {
  538. EnterCriticalSection(_pcs);
  539. CElemSlot* pes = _GetValidHead();
  540. while (pes)
  541. {
  542. CElemSlot* pesOld = pes;
  543. CNamedElem* pelem;
  544. WCHAR szName[1024];
  545. HRESULT hres = pes->GetNamedElem(&pelem);
  546. if (SUCCEEDED(hres))
  547. {
  548. DWORD cchReq;
  549. hres = pelem->GetName(szName, ARRAYSIZE(szName), &cchReq);
  550. if (SUCCEEDED(hres))
  551. {
  552. CElemSlot* pesIn = pes->GetNextValid();
  553. while (pesIn)
  554. {
  555. CElemSlot* pesInOld = pesIn;
  556. CNamedElem* pelemIn;
  557. WCHAR szNameIn[1024];
  558. hres = pesIn->GetNamedElem(&pelemIn);
  559. if (SUCCEEDED(hres))
  560. {
  561. DWORD cchReqIn;
  562. hres = pelemIn->GetName(szNameIn, ARRAYSIZE(szNameIn),
  563. &cchReqIn);
  564. if (SUCCEEDED(hres))
  565. {
  566. ASSERT(lstrcmp(szName, szNameIn));
  567. }
  568. pelemIn->RCRelease();
  569. }
  570. pesIn = pesIn->GetNextValid();
  571. pesInOld->RCRelease();
  572. }
  573. }
  574. pelem->RCRelease();
  575. }
  576. pes = pes->GetNextValid();
  577. pesOld->RCRelease();
  578. }
  579. LeaveCriticalSection(_pcs);
  580. }
  581. void CNamedElemList::AssertAllElemsRefCount1()
  582. {
  583. EnterCriticalSection(_pcs);
  584. CElemSlot* pes = _GetValidHead();
  585. while (pes)
  586. {
  587. CElemSlot* pesOld = pes;
  588. CNamedElem* pelem;
  589. HRESULT hres = pes->GetNamedElem(&pelem);
  590. if (SUCCEEDED(hres))
  591. {
  592. pelem->RCRelease();
  593. }
  594. pes = pes->GetNextValid();
  595. pesOld->RCRelease();
  596. }
  597. LeaveCriticalSection(_pcs);
  598. }
  599. #endif
  600. //=============================================================================
  601. //=============================================================================
  602. //== CNamedElemEnum ==
  603. //=============================================================================
  604. //=============================================================================
  605. ///////////////////////////////////////////////////////////////////////////////
  606. // Public
  607. HRESULT CNamedElemEnum::Next(CNamedElem** ppelem)
  608. {
  609. HRESULT hres = S_FALSE;
  610. *ppelem = NULL;
  611. EnterCriticalSection(_pcsList);
  612. if (_pesCurrent)
  613. {
  614. CElemSlot* pes = _pesCurrent;
  615. if (!_fFirst || !pes->IsValid())
  616. {
  617. pes = pes->GetPrevValid();
  618. _pesCurrent->RCRelease();
  619. _pesCurrent = pes;
  620. }
  621. if (pes)
  622. {
  623. hres = pes->GetNamedElem(ppelem);
  624. }
  625. _fFirst = FALSE;
  626. }
  627. LeaveCriticalSection(_pcsList);
  628. return hres;
  629. }
  630. CNamedElemEnum::CNamedElemEnum() : _pesCurrent(NULL), _pcsList(NULL)
  631. {
  632. #ifdef DEBUG
  633. static TCHAR _szDebugName[] = TEXT("CNamedElemEnum");
  634. #endif
  635. }
  636. CNamedElemEnum::~CNamedElemEnum()
  637. {
  638. if (_pcsList)
  639. {
  640. EnterCriticalSection(_pcsList);
  641. if (_pesCurrent)
  642. {
  643. _pesCurrent->RCRelease();
  644. }
  645. LeaveCriticalSection(_pcsList);
  646. _pcsList->RCRelease();
  647. }
  648. }
  649. ///////////////////////////////////////////////////////////////////////////////
  650. // Private
  651. HRESULT CNamedElemEnum::_Init(CElemSlot* pesHead, CRefCountedCritSect* pcsList)
  652. {
  653. pcsList->RCAddRef();
  654. _pcsList = pcsList;
  655. _fFirst = TRUE;
  656. EnterCriticalSection(_pcsList);
  657. _pesCurrent = pesHead;
  658. if (_pesCurrent)
  659. {
  660. _pesCurrent->RCAddRef();
  661. }
  662. LeaveCriticalSection(_pcsList);
  663. return S_OK;
  664. }
  665. //=============================================================================
  666. //=============================================================================
  667. //== CElemSlot ==
  668. //=============================================================================
  669. //=============================================================================
  670. ///////////////////////////////////////////////////////////////////////////////
  671. // Public
  672. HRESULT CElemSlot::Init(CNamedElem* pelem, CElemSlot* pesPrev,
  673. CElemSlot* pesNext)
  674. {
  675. _pelem = pelem;
  676. pelem->RCAddRef();
  677. _fValid = TRUE;
  678. _pesPrev = pesPrev;
  679. _pesNext = pesNext;
  680. return S_OK;
  681. }
  682. HRESULT CElemSlot::Remove()
  683. {
  684. _fValid = FALSE;
  685. _pelem->RCRelease();
  686. _pelem = NULL;
  687. return S_OK;
  688. }
  689. HRESULT CElemSlot::GetNamedElem(CNamedElem** ppelem)
  690. {
  691. ASSERT(_fValid);
  692. _pelem->RCAddRef();
  693. *ppelem = _pelem;
  694. return S_OK;
  695. }
  696. void CElemSlot::SetPrev(CElemSlot* pes)
  697. {
  698. _pesPrev = pes;
  699. }
  700. CElemSlot* CElemSlot::GetNextValid()
  701. {
  702. CElemSlot* pes = _pesNext;
  703. while (pes && !pes->IsValid())
  704. {
  705. pes = pes->_pesNext;
  706. }
  707. if (pes)
  708. {
  709. pes->RCAddRef();
  710. }
  711. return pes;
  712. }
  713. CElemSlot* CElemSlot::GetNext()
  714. {
  715. if (_pesNext)
  716. {
  717. _pesNext->RCAddRef();
  718. }
  719. return _pesNext;
  720. }
  721. CElemSlot* CElemSlot::GetPrevValid()
  722. {
  723. CElemSlot* pes = _pesPrev;
  724. while (pes && !pes->IsValid())
  725. {
  726. pes = pes->_pesPrev;
  727. }
  728. if (pes)
  729. {
  730. pes->RCAddRef();
  731. }
  732. return pes;
  733. }
  734. BOOL CElemSlot::IsValid()
  735. {
  736. return _fValid;
  737. }
  738. void CElemSlot::SetCallbackPointer(CNamedElemList* pnel)
  739. {
  740. _pnel = pnel;
  741. }
  742. CElemSlot::CElemSlot() : _fValid(FALSE), _pesPrev(NULL), _pesNext(NULL),
  743. _pnel(NULL)
  744. {
  745. #ifdef DEBUG
  746. static TCHAR _szDebugName[] = TEXT("CElemSlot");
  747. #endif
  748. }
  749. CElemSlot::~CElemSlot()
  750. {
  751. ASSERT(!_fValid);
  752. if (_pnel)
  753. {
  754. // This elem is the head of the list
  755. _pnel->RealRemoveElemSlotCallback(this);
  756. }
  757. if (_pesPrev)
  758. {
  759. _pesPrev->_pesNext = _pesNext;
  760. }
  761. if (_pesNext)
  762. {
  763. _pesNext->_pesPrev = _pesPrev;
  764. }
  765. }