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.

955 lines
20 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. #ifdef DEBUG
  44. if (SUCCEEDED(hres))
  45. {
  46. _pszRCAddRefName = _pszElemName;
  47. // __FILE__ and __LINE__ should come from original file
  48. CRefCounted::_RCCreate(__FILE__, __LINE__);
  49. }
  50. #endif
  51. }
  52. else
  53. {
  54. hres = E_OUTOFMEMORY;
  55. }
  56. return hres;
  57. }
  58. HRESULT CNamedElem::_FreeName()
  59. {
  60. ASSERT(_pszElemName);
  61. LocalFree((HLOCAL)_pszElemName);
  62. return S_OK;
  63. }
  64. //=============================================================================
  65. //=============================================================================
  66. //== CNamedElemList ==
  67. //=============================================================================
  68. //=============================================================================
  69. ///////////////////////////////////////////////////////////////////////////////
  70. // Public
  71. HRESULT CNamedElemList::Init(NAMEDELEMCREATEFCT createfct,
  72. NAMEDELEMGETFILLENUMFCT enumfct)
  73. {
  74. HRESULT hres;
  75. _createfct = createfct;
  76. _enumfct = enumfct;
  77. _pcs = new CRefCountedCritSect();
  78. if (_pcs)
  79. {
  80. InitializeCriticalSection(_pcs);
  81. hres = S_OK;
  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. if (FAILED(hres))
  235. {
  236. // continue enum even if a device is not fully installed
  237. hres = S_OK;
  238. }
  239. #ifdef DEBUG
  240. if (SUCCEEDED(hres))
  241. {
  242. TRACE(TF_NAMEDELEMLISTMODIF, TEXT("Added to '%s': '%s'"),
  243. _szDebugName, pszElemName);
  244. }
  245. #endif
  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. _pszRCAddRefName = _szDebugName;
  318. _szDebugName[0] = 0;
  319. #endif
  320. }
  321. CNamedElemList::~CNamedElemList()
  322. {
  323. _EmptyList();
  324. if (_pcs)
  325. {
  326. DeleteCriticalSection(_pcs);
  327. _pcs->RCRelease();
  328. }
  329. }
  330. ///////////////////////////////////////////////////////////////////////////////
  331. // Private
  332. // All these fcts have to be called from within The critical section
  333. HRESULT CNamedElemList::_Add(LPCTSTR pszElemName, CNamedElem** ppelem)
  334. {
  335. CNamedElem* pelem;
  336. HRESULT hres = _createfct(&pelem);
  337. if (SUCCEEDED(hres))
  338. {
  339. hres = pelem->Init(pszElemName);
  340. if (SUCCEEDED(hres))
  341. {
  342. CElemSlot* pes = new CElemSlot();
  343. if (pes)
  344. {
  345. // This takes an additionnal ref on pelem
  346. hres = pes->Init(pelem, NULL, _pesHead);
  347. if (SUCCEEDED(hres))
  348. {
  349. if (_pesHead)
  350. {
  351. _pesHead->SetPrev(pes);
  352. }
  353. _pesHead = pes;
  354. }
  355. else
  356. {
  357. pes->RCRelease();
  358. }
  359. }
  360. else
  361. {
  362. hres = E_OUTOFMEMORY;
  363. }
  364. }
  365. pelem->RCRelease();
  366. if (FAILED(hres))
  367. {
  368. pelem = NULL;
  369. }
  370. }
  371. if (ppelem)
  372. {
  373. if (pelem)
  374. {
  375. pelem->RCAddRef();
  376. }
  377. *ppelem = pelem;
  378. }
  379. return hres;
  380. }
  381. HRESULT CNamedElemList::_GetTail(CElemSlot** ppes)
  382. {
  383. HRESULT hr;
  384. CElemSlot* pesLastValid = _GetValidHead();
  385. if (pesLastValid)
  386. {
  387. CElemSlot* pesOld = pesLastValid;
  388. while (NULL != (pesLastValid = pesLastValid->GetNextValid()))
  389. {
  390. pesOld->RCRelease();
  391. pesOld = pesLastValid;
  392. }
  393. pesLastValid = pesOld;
  394. hr = S_OK;
  395. }
  396. else
  397. {
  398. hr = S_FALSE;
  399. }
  400. // pesLastValid is already RCAddRef'ed
  401. *ppes = pesLastValid;
  402. return hr;
  403. }
  404. HRESULT CNamedElemList::_GetElemSlot(LPCTSTR pszElemName, CElemSlot** ppes)
  405. {
  406. HRESULT hres = S_FALSE;
  407. CElemSlot* pes = _GetValidHead();
  408. CElemSlot* pesOld = pes;
  409. while (pes && SUCCEEDED(hres) && (S_FALSE == hres))
  410. {
  411. CNamedElem* pelem;
  412. hres = pes->GetNamedElem(&pelem);
  413. if (SUCCEEDED(hres))
  414. {
  415. TCHAR szElemName[MAX_PATH];
  416. LPTSTR pszElemNameLocal = szElemName;
  417. DWORD cchReq;
  418. hres = pelem->GetName(szElemName, ARRAYSIZE(szElemName), &cchReq);
  419. if (E_BUFFERTOOSMALL == hres)
  420. {
  421. pszElemNameLocal = (LPTSTR)LocalAlloc(LPTR, cchReq *
  422. sizeof(TCHAR));
  423. if (pszElemNameLocal)
  424. {
  425. hres = pelem->GetName(pszElemNameLocal, cchReq, &cchReq);
  426. }
  427. else
  428. {
  429. hres = E_OUTOFMEMORY;
  430. }
  431. }
  432. pelem->RCRelease();
  433. if (SUCCEEDED(hres))
  434. {
  435. if (!lstrcmpi(pszElemNameLocal, pszElemName))
  436. {
  437. // Found it!
  438. pes->RCAddRef();
  439. *ppes = pes;
  440. hres = S_OK;
  441. }
  442. else
  443. {
  444. pes = pes->GetNextValid();
  445. hres = S_FALSE;
  446. }
  447. }
  448. if (pszElemNameLocal && (pszElemNameLocal != szElemName))
  449. {
  450. LocalFree((HLOCAL)pszElemNameLocal);
  451. }
  452. }
  453. pesOld->RCRelease();
  454. pesOld = pes;
  455. }
  456. return hres;
  457. }
  458. HRESULT CNamedElemList::_Remove(LPCTSTR pszElemName)
  459. {
  460. ASSERT(pszElemName);
  461. CElemSlot* pes;
  462. HRESULT hres = _GetElemSlot(pszElemName, &pes);
  463. if (SUCCEEDED(hres) && (S_FALSE != hres))
  464. {
  465. if (pes == _pesHead)
  466. {
  467. // New head
  468. _pesHead = pes->GetNextValid();
  469. if (_pesHead)
  470. {
  471. // We do not keep a ref on the head
  472. _pesHead->RCRelease();
  473. }
  474. }
  475. hres = pes->Remove();
  476. // 2: one to balance the _GetElemSlot and one to remove from list
  477. pes->RCRelease();
  478. pes->RCRelease();
  479. }
  480. return hres;
  481. }
  482. HRESULT CNamedElemList::_EmptyList()
  483. {
  484. HRESULT hres = S_FALSE;
  485. CElemSlot* pes = _GetValidHead();
  486. while (SUCCEEDED(hres) && pes)
  487. {
  488. CElemSlot* pesOld = pes;
  489. hres = pes->Remove();
  490. pes = pes->GetNextValid();
  491. pesOld->RCRelease();
  492. }
  493. _pesHead = NULL;
  494. return hres;
  495. }
  496. CElemSlot* CNamedElemList::_GetValidHead()
  497. {
  498. CElemSlot* pes = _pesHead;
  499. if (pes)
  500. {
  501. if (pes->IsValid())
  502. {
  503. pes->RCAddRef();
  504. }
  505. else
  506. {
  507. pes = pes->GetNextValid();
  508. }
  509. }
  510. return pes;
  511. }
  512. #ifdef DEBUG
  513. HRESULT CNamedElemList::InitDebug(LPWSTR pszDebugName)
  514. {
  515. HRESULT hres = SafeStrCpyN(_szDebugName, pszDebugName,
  516. ARRAYSIZE(_szDebugName));
  517. if (SUCCEEDED(hres))
  518. {
  519. _RCCreate(__FILE__, __LINE__);
  520. }
  521. return hres;
  522. }
  523. void CNamedElemList::AssertNoDuplicate()
  524. {
  525. EnterCriticalSection(_pcs);
  526. CElemSlot* pes = _GetValidHead();
  527. while (pes)
  528. {
  529. CElemSlot* pesOld = pes;
  530. CNamedElem* pelem;
  531. WCHAR szName[1024];
  532. HRESULT hres = pes->GetNamedElem(&pelem);
  533. if (SUCCEEDED(hres))
  534. {
  535. DWORD cchReq;
  536. hres = pelem->GetName(szName, ARRAYSIZE(szName), &cchReq);
  537. if (SUCCEEDED(hres))
  538. {
  539. CElemSlot* pesIn = pes->GetNextValid();
  540. while (pesIn)
  541. {
  542. CElemSlot* pesInOld = pesIn;
  543. CNamedElem* pelemIn;
  544. WCHAR szNameIn[1024];
  545. hres = pesIn->GetNamedElem(&pelemIn);
  546. if (SUCCEEDED(hres))
  547. {
  548. DWORD cchReqIn;
  549. hres = pelemIn->GetName(szNameIn, ARRAYSIZE(szNameIn),
  550. &cchReqIn);
  551. if (SUCCEEDED(hres))
  552. {
  553. ASSERT(lstrcmp(szName, szNameIn));
  554. }
  555. pelemIn->RCRelease();
  556. }
  557. pesIn = pesIn->GetNextValid();
  558. pesInOld->RCRelease();
  559. }
  560. }
  561. pelem->RCRelease();
  562. }
  563. pes = pes->GetNextValid();
  564. pesOld->RCRelease();
  565. }
  566. LeaveCriticalSection(_pcs);
  567. }
  568. void CNamedElemList::AssertAllElemsRefCount1()
  569. {
  570. EnterCriticalSection(_pcs);
  571. ASSERT(1 == _RCGetRefCount());
  572. CElemSlot* pes = _GetValidHead();
  573. while (pes)
  574. {
  575. CElemSlot* pesOld = pes;
  576. // Actually check for 2, since it was just AddRefed
  577. ASSERT(2 == pes->_RCGetRefCount());
  578. CNamedElem* pelem;
  579. HRESULT hres = pes->GetNamedElem(&pelem);
  580. if (SUCCEEDED(hres))
  581. {
  582. ASSERT(2 == pelem->_RCGetRefCount());
  583. pelem->RCRelease();
  584. }
  585. pes = pes->GetNextValid();
  586. pesOld->RCRelease();
  587. }
  588. LeaveCriticalSection(_pcs);
  589. }
  590. #endif
  591. //=============================================================================
  592. //=============================================================================
  593. //== CNamedElemEnum ==
  594. //=============================================================================
  595. //=============================================================================
  596. ///////////////////////////////////////////////////////////////////////////////
  597. // Public
  598. HRESULT CNamedElemEnum::Next(CNamedElem** ppelem)
  599. {
  600. HRESULT hres = S_FALSE;
  601. EnterCriticalSection(_pcsList);
  602. if (_pesCurrent)
  603. {
  604. CElemSlot* pes = _pesCurrent;
  605. *ppelem = NULL;
  606. if (pes)
  607. {
  608. if (!_fFirst || !pes->IsValid())
  609. {
  610. pes = pes->GetPrevValid();
  611. }
  612. }
  613. if (!_fFirst && _pesCurrent)
  614. {
  615. _pesCurrent->RCRelease();
  616. }
  617. if (pes)
  618. {
  619. hres = pes->GetNamedElem(ppelem);
  620. }
  621. _pesCurrent = pes;
  622. _fFirst = FALSE;
  623. }
  624. LeaveCriticalSection(_pcsList);
  625. return hres;
  626. }
  627. CNamedElemEnum::CNamedElemEnum() : _pesCurrent(NULL), _pcsList(NULL)
  628. {
  629. #ifdef DEBUG
  630. static TCHAR _szDebugName[] = TEXT("CNamedElemEnum");
  631. _pszRCAddRefName = _szDebugName;
  632. #endif
  633. }
  634. CNamedElemEnum::~CNamedElemEnum()
  635. {
  636. if (_pcsList)
  637. {
  638. _pcsList->RCRelease();
  639. }
  640. if (_pesCurrent)
  641. {
  642. _pesCurrent->RCRelease();
  643. }
  644. }
  645. ///////////////////////////////////////////////////////////////////////////////
  646. // Private
  647. HRESULT CNamedElemEnum::_Init(CElemSlot* pesHead, CRefCountedCritSect* pcsList)
  648. {
  649. pcsList->RCAddRef();
  650. _pcsList = pcsList;
  651. _fFirst = TRUE;
  652. _pesCurrent = pesHead;
  653. if (_pesCurrent)
  654. {
  655. _pesCurrent->RCAddRef();
  656. }
  657. return S_OK;
  658. }
  659. //=============================================================================
  660. //=============================================================================
  661. //== CElemSlot ==
  662. //=============================================================================
  663. //=============================================================================
  664. ///////////////////////////////////////////////////////////////////////////////
  665. // Public
  666. HRESULT CElemSlot::Init(CNamedElem* pelem, CElemSlot* pesPrev,
  667. CElemSlot* pesNext)
  668. {
  669. _pelem = pelem;
  670. pelem->RCAddRef();
  671. _fValid = TRUE;
  672. _pesPrev = pesPrev;
  673. _pesNext = pesNext;
  674. return S_OK;
  675. }
  676. HRESULT CElemSlot::Remove()
  677. {
  678. _fValid = FALSE;
  679. _pelem->RCRelease();
  680. _pelem = NULL;
  681. return S_OK;
  682. }
  683. HRESULT CElemSlot::GetNamedElem(CNamedElem** ppelem)
  684. {
  685. ASSERT(_fValid);
  686. _pelem->RCAddRef();
  687. *ppelem = _pelem;
  688. return S_OK;
  689. }
  690. void CElemSlot::SetPrev(CElemSlot* pes)
  691. {
  692. _pesPrev = pes;
  693. }
  694. CElemSlot* CElemSlot::GetNextValid()
  695. {
  696. CElemSlot* pes = _pesNext;
  697. while (pes && !pes->IsValid())
  698. {
  699. pes = pes->_pesNext;
  700. }
  701. if (pes)
  702. {
  703. pes->RCAddRef();
  704. }
  705. return pes;
  706. }
  707. CElemSlot* CElemSlot::GetPrevValid()
  708. {
  709. CElemSlot* pes = _pesPrev;
  710. while (pes && !pes->IsValid())
  711. {
  712. pes = pes->_pesPrev;
  713. }
  714. if (pes)
  715. {
  716. pes->RCAddRef();
  717. }
  718. return pes;
  719. }
  720. BOOL CElemSlot::IsValid()
  721. {
  722. return _fValid;
  723. }
  724. CElemSlot::CElemSlot() : _fValid(FALSE), _pesPrev(NULL), _pesNext(NULL)
  725. {
  726. #ifdef DEBUG
  727. static TCHAR _szDebugName[] = TEXT("CElemSlot");
  728. _pszRCAddRefName = _szDebugName;
  729. #endif
  730. }
  731. CElemSlot::~CElemSlot()
  732. {
  733. ASSERT(!_fValid);
  734. if (_pesPrev)
  735. {
  736. _pesPrev->_pesNext = _pesNext;
  737. }
  738. if (_pesNext)
  739. {
  740. _pesNext->_pesPrev = _pesPrev;
  741. }
  742. }
  743.