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.

706 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: S T A B L E . C P P
  7. //
  8. // Contents: Implements operations that are valid on stack entries and
  9. // stack tables.
  10. //
  11. // Notes:
  12. //
  13. // Author: shaunco 15 Jan 1999
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #include "nceh.h"
  19. #include "netcfg.h"
  20. #include "stable.h"
  21. BOOL
  22. CStackTable::FStackEntryInTable (
  23. IN const CComponent* pUpper,
  24. IN const CComponent* pLower) const
  25. {
  26. const CStackEntry* pStackEntry;
  27. Assert (this);
  28. Assert (pUpper);
  29. Assert (pLower);
  30. for (pStackEntry = begin(); pStackEntry != end(); pStackEntry++)
  31. {
  32. if ((pUpper == pStackEntry->pUpper) &&
  33. (pLower == pStackEntry->pLower))
  34. {
  35. return TRUE;
  36. }
  37. }
  38. return FALSE;
  39. }
  40. VOID
  41. CStackTable::RemoveStackEntry(
  42. IN const CComponent* pUpper,
  43. IN const CComponent* pLower)
  44. {
  45. CStackEntry* pStackEntry;
  46. Assert (this);
  47. Assert (pUpper);
  48. Assert (pLower);
  49. for (pStackEntry = begin(); pStackEntry != end(); pStackEntry++)
  50. {
  51. if ((pUpper == pStackEntry->pUpper) &&
  52. (pLower == pStackEntry->pLower))
  53. {
  54. erase(pStackEntry);
  55. break;
  56. }
  57. }
  58. }
  59. HRESULT
  60. CStackTable::HrCopyStackTable (
  61. IN const CStackTable* pSourceTable)
  62. {
  63. HRESULT hr;
  64. Assert (this);
  65. Assert (pSourceTable);
  66. NC_TRY
  67. {
  68. *this = *pSourceTable;
  69. hr = S_OK;
  70. }
  71. NC_CATCH_ALL
  72. {
  73. hr = E_OUTOFMEMORY;
  74. }
  75. TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrCopyStackTable");
  76. return hr;
  77. }
  78. HRESULT
  79. CStackTable::HrInsertStackEntriesForComponent (
  80. IN const CComponent* pComponent,
  81. IN const CComponentList* pComponents,
  82. IN DWORD dwFlags /* INS_FLAGS */)
  83. {
  84. HRESULT hr;
  85. CStackEntry StackEntry;
  86. CComponentList::const_iterator iter;
  87. const CComponent* pScan;
  88. Assert (this);
  89. Assert (pComponent);
  90. Assert (pComponents);
  91. hr = S_OK;
  92. // Insert the stack entries for other components which bind with this one.
  93. //
  94. for (iter = pComponents->begin();
  95. iter != pComponents->end();
  96. iter++)
  97. {
  98. pScan = *iter;
  99. Assert (pScan);
  100. if (pScan == pComponent)
  101. {
  102. continue;
  103. }
  104. if (pScan->FCanDirectlyBindTo (pComponent, NULL, NULL))
  105. {
  106. StackEntry.pUpper = pScan;
  107. StackEntry.pLower = pComponent;
  108. }
  109. else if (pComponent->FCanDirectlyBindTo (pScan, NULL, NULL))
  110. {
  111. StackEntry.pUpper = pComponent;
  112. StackEntry.pLower = pScan;
  113. }
  114. else
  115. {
  116. continue;
  117. }
  118. // Insert the stack entry. This should only fail if we are
  119. // out of memory.
  120. //
  121. hr = HrInsertStackEntry (&StackEntry, dwFlags);
  122. // If we fail to insert the entry, undo all of the previous
  123. // insertions of this component and return.
  124. //
  125. if (S_OK != hr)
  126. {
  127. RemoveEntriesWithComponent (pComponent);
  128. break;
  129. }
  130. }
  131. TraceHr (ttidError, FAL, hr, FALSE,
  132. "CStackTable::HrInsertStackEntriesForComponent");
  133. return hr;
  134. }
  135. HRESULT
  136. CStackTable::HrInsertStackEntry (
  137. IN const CStackEntry* pStackEntry,
  138. IN DWORD dwFlags)
  139. {
  140. HRESULT hr;
  141. Assert (this);
  142. Assert (pStackEntry);
  143. Assert (dwFlags);
  144. Assert ((INS_SORTED == dwFlags) || (INS_NON_SORTED == dwFlags));
  145. const CComponent* pUpper = pStackEntry->pUpper;
  146. const CComponent* pLower = pStackEntry->pLower;
  147. Assert (pUpper && pLower && (pUpper != pLower));
  148. Assert (!FStackEntryInTable (pUpper, pLower));
  149. CStackEntry* pScan = end();
  150. if (dwFlags & INS_SORTED)
  151. {
  152. CStackEntry* pFirstInClass = NULL;
  153. CStackEntry* pFirstSameUpper = NULL;
  154. // Find the beginning of the group of entries belonging to the
  155. // same class or lower as the one we are inserting.
  156. //
  157. for (pScan = begin(); pScan != end(); pScan++)
  158. {
  159. if ((UINT)pUpper->Class() >= (UINT)pScan->pUpper->Class())
  160. {
  161. pFirstInClass = pScan;
  162. break;
  163. }
  164. }
  165. // Find the first entry with the same pUpper (if there is one).
  166. //
  167. for (; pScan != end(); pScan++)
  168. {
  169. if (pUpper == pScan->pUpper)
  170. {
  171. pFirstSameUpper = pScan;
  172. break;
  173. }
  174. }
  175. // If we found the first entry with a matching pUpper, find the
  176. // specific entry to insert before.
  177. //
  178. if (pFirstSameUpper)
  179. {
  180. BOOL fLowerIsNetBt;
  181. // This may seem ugly, but will save a lot of code in a
  182. // notify object. If inserting pLower of netbt, make sure
  183. // it comes after netbt_smb.
  184. //
  185. fLowerIsNetBt = (0 == wcscmp (pLower->m_pszInfId, L"ms_netbt"));
  186. if (fLowerIsNetBt)
  187. {
  188. while ((pScan != end()) && (pUpper == pScan->pUpper))
  189. {
  190. pScan++;
  191. }
  192. }
  193. else if (pLower->FIsWanAdapter() && !m_fWanAdaptersFirst)
  194. {
  195. // For WAN adapters, either insert them before or after
  196. // all other adapters as determined by m_fWanAdaptersFirst.
  197. // If they don't come first, they come last, so scan
  198. // to the end of the group with the same upper.
  199. //
  200. while ((pScan != end()) && (pUpper == pScan->pUpper))
  201. {
  202. pScan++;
  203. }
  204. }
  205. }
  206. // Otherwise, (if we didn't find any entry with the same upper),
  207. // but we did find the beginning of the class group, set pScan
  208. // to the class marker because that is where we will insert.
  209. //
  210. else if (pFirstInClass)
  211. {
  212. pScan = pFirstInClass;
  213. }
  214. else
  215. {
  216. Assert (pScan == end());
  217. }
  218. }
  219. // Now insert the entry before the element we found as appropriate.
  220. //
  221. NC_TRY
  222. {
  223. insert (pScan, *pStackEntry);
  224. hr = S_OK;
  225. }
  226. NC_CATCH_ALL
  227. {
  228. hr = E_OUTOFMEMORY;
  229. }
  230. TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrInsertStackEntry");
  231. return hr;
  232. }
  233. HRESULT
  234. CStackTable::HrMoveStackEntries (
  235. IN const CStackEntry* pSrc,
  236. IN const CStackEntry* pDst,
  237. IN MOVE_FLAG Flag,
  238. IN CModifyContext* pModifyCtx)
  239. {
  240. CStackEntry* pScanSrc;
  241. CStackEntry* pScanDst;
  242. // Search for the matching source entry in the table. We need
  243. // the pointer to the entry in the table so we can remove it before
  244. // we re-insert it before or after pDst.
  245. //
  246. pScanSrc = find (begin(), end(), *pSrc);
  247. // If we didn't find the entry, the caller has passed us an invalid
  248. // argument.
  249. //
  250. if (pScanSrc == end())
  251. {
  252. return E_INVALIDARG;
  253. }
  254. if (pDst)
  255. {
  256. // pDst is optional, but if it is specified, it have the same upper
  257. // but different lower than pSrc.
  258. //
  259. if ((pSrc->pUpper != pDst->pUpper) ||
  260. (pSrc->pLower == pDst->pLower))
  261. {
  262. return E_INVALIDARG;
  263. }
  264. pScanDst = find (begin(), end(), *pDst);
  265. // If we didn't find the entry, the caller has passed us an invalid
  266. // argument.
  267. //
  268. if (pScanDst == end())
  269. {
  270. return E_INVALIDARG;
  271. }
  272. // Since we only have an insert operation, moving after is the
  273. // same as inserting before the element following pScanDst.
  274. //
  275. if ((MOVE_AFTER == Flag) && (pScanDst != end()))
  276. {
  277. pScanDst++;
  278. }
  279. }
  280. else
  281. {
  282. // Find the first or last in the group with the same upper
  283. // as pScanSrc.
  284. //
  285. pScanDst = pScanSrc;
  286. if (MOVE_AFTER == Flag)
  287. {
  288. // Find the last in the group and insert after that.
  289. //
  290. while (pScanDst->pUpper == pScanSrc->pUpper)
  291. {
  292. pScanDst++;
  293. if (pScanDst == end())
  294. {
  295. break;
  296. }
  297. }
  298. }
  299. else
  300. {
  301. // Find the first in the group and insert before that.
  302. //
  303. while (1)
  304. {
  305. pScanDst--;
  306. if (pScanDst == begin())
  307. {
  308. break;
  309. }
  310. // If we've stepped out of the group, we need to point
  311. // back at the first element since we are inserting.
  312. //
  313. if (pScanDst->pUpper != pScanSrc->pUpper)
  314. {
  315. pScanDst++;
  316. break;
  317. }
  318. }
  319. }
  320. }
  321. // Remove pScanSrc and insert it pSrc before pScanDst.
  322. //
  323. Assert ((pScanSrc >= begin()) && pScanSrc < end());
  324. erase (pScanSrc);
  325. // Erasing pScanSrc will move everything that follows it up.
  326. // If pScanDst comes after pScanSrc, we need to back it up by one.
  327. //
  328. Assert ((pScanDst >= begin()) && pScanSrc <= end());
  329. if (pScanSrc < pScanDst)
  330. {
  331. pScanDst--;
  332. }
  333. Assert ((pScanDst >= begin()) && pScanSrc <= end());
  334. insert (pScanDst, *pSrc);
  335. // We now need to add pSrc->pUpper and all components above
  336. // it to the modify context's dirty component list. This will
  337. // allow us to rewrite the newly ordered bindings during ApplyChanges.
  338. //
  339. HRESULT hr = pModifyCtx->HrDirtyComponentAndComponentsAbove (pSrc->pUpper);
  340. TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrMoveStackEntries");
  341. return hr;
  342. }
  343. HRESULT
  344. CStackTable::HrReserveRoomForEntries (
  345. IN UINT cEntries)
  346. {
  347. HRESULT hr;
  348. NC_TRY
  349. {
  350. reserve (cEntries);
  351. hr = S_OK;
  352. }
  353. NC_CATCH_ALL
  354. {
  355. hr = E_OUTOFMEMORY;
  356. }
  357. TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrReserveRoomForEntries");
  358. return hr;
  359. }
  360. VOID
  361. CStackTable::RemoveEntriesWithComponent (
  362. IN const CComponent* pComponent)
  363. {
  364. CStackEntry* pStackEntry;
  365. Assert (this);
  366. Assert (pComponent);
  367. pStackEntry = begin();
  368. while (pStackEntry != end())
  369. {
  370. if ((pComponent == pStackEntry->pUpper) ||
  371. (pComponent == pStackEntry->pLower))
  372. {
  373. erase (pStackEntry);
  374. }
  375. else
  376. {
  377. pStackEntry++;
  378. }
  379. }
  380. }
  381. HRESULT
  382. CStackTable::HrUpdateEntriesForComponent (
  383. IN const CComponent* pComponent,
  384. IN const CComponentList* pComponents,
  385. IN DWORD dwFlags)
  386. {
  387. HRESULT hr;
  388. CStackEntry StackEntry;
  389. CComponentList::const_iterator iter;
  390. const CComponent* pScan;
  391. CStackTable NewStackEntries;
  392. CStackEntry* pStackEntry = NULL;
  393. Assert (this);
  394. Assert (pComponent);
  395. Assert (pComponents);
  396. hr = S_OK;
  397. TraceTag(ttidBeDiag,
  398. "UpdateBindingInterfaces for %S",
  399. pComponent->PszGetPnpIdOrInfId());
  400. // Save the stack entries for other components which bind with this one.
  401. //
  402. for (iter = pComponents->begin();
  403. iter != pComponents->end();
  404. iter++)
  405. {
  406. pScan = *iter;
  407. Assert (pScan);
  408. if (pScan == pComponent)
  409. {
  410. continue;
  411. }
  412. if (pScan->FCanDirectlyBindTo (pComponent, NULL, NULL))
  413. {
  414. StackEntry.pUpper = pScan;
  415. StackEntry.pLower = pComponent;
  416. }
  417. else if (pComponent->FCanDirectlyBindTo (pScan, NULL, NULL))
  418. {
  419. StackEntry.pUpper = pComponent;
  420. StackEntry.pLower = pScan;
  421. }
  422. else
  423. {
  424. continue;
  425. }
  426. // Save the stack entry for comparation later
  427. NewStackEntries.push_back(StackEntry);
  428. }
  429. //Check whether the current stack entry table is consist with NewStackEntries
  430. //if not, then update the current stack entry table
  431. pStackEntry = begin();
  432. while (pStackEntry != end())
  433. {
  434. if ((pComponent == pStackEntry->pUpper) ||
  435. (pComponent == pStackEntry->pLower))
  436. {
  437. if (!NewStackEntries.FStackEntryInTable(pStackEntry->pUpper, pStackEntry->pLower))
  438. {
  439. //if the stack entry is not in the new component binding entry list, remove it
  440. //from the current stack entry list
  441. erase (pStackEntry);
  442. TraceTag(ttidBeDiag,
  443. "erasing binding interface Uppper %S - Lower %S",
  444. pStackEntry->pUpper->PszGetPnpIdOrInfId(),
  445. pStackEntry->pLower->PszGetPnpIdOrInfId());
  446. //dont need to increase the iterator since we just removed the current one
  447. continue;
  448. }
  449. else
  450. {
  451. //if the stack entry is also in NewStackEntries, just keep it untouched
  452. //in current entry list. Remove that entry from NewStackEntries so that we don't add
  453. // it again to the current entry list later
  454. NewStackEntries.RemoveStackEntry(pStackEntry->pUpper, pStackEntry->pLower);
  455. TraceTag(ttidBeDiag,
  456. "Keep the binding interface untouched: Uppper %S - Lower %S",
  457. pStackEntry->pUpper->PszGetPnpIdOrInfId(),
  458. pStackEntry->pLower->PszGetPnpIdOrInfId());
  459. }
  460. }
  461. pStackEntry++;
  462. }
  463. //At this step, the NewStackEntries only contains the stack entries that are in the new binding list
  464. //but are NOT in the current entry list. So add them in.
  465. pStackEntry = NewStackEntries.begin();
  466. while (pStackEntry != NewStackEntries.end())
  467. {
  468. Assert(!FStackEntryInTable(pStackEntry->pUpper, pStackEntry->pLower));
  469. TraceTag(ttidBeDiag,
  470. "Adding the bind interface: Uppper %S - Lower %S",
  471. pStackEntry->pUpper->PszGetPnpIdOrInfId(),
  472. pStackEntry->pLower->PszGetPnpIdOrInfId());
  473. hr = HrInsertStackEntry(pStackEntry, dwFlags);
  474. if (S_OK != hr)
  475. {
  476. break;
  477. }
  478. pStackEntry++;
  479. }
  480. // If we fail to insert the entry, undo all of the previous
  481. // insertions of this component and return.
  482. //
  483. if (S_OK != hr)
  484. {
  485. RemoveEntriesWithComponent (pComponent);
  486. }
  487. TraceError("UpdateEntriesWithComponent", hr);
  488. return hr;
  489. }
  490. VOID
  491. CStackTable::SetWanAdapterOrder (
  492. IN BOOL fWanAdaptersFirst)
  493. {
  494. m_fWanAdaptersFirst = fWanAdaptersFirst;
  495. // Note: TODO - reorder table
  496. }
  497. VOID
  498. GetComponentsAboveComponent (
  499. IN const CComponent* pComponent,
  500. IN OUT GCCONTEXT* pCtx)
  501. {
  502. const CStackEntry* pStackEntry;
  503. // For all rows in the stack table where the lower component
  504. // is the one passed in...
  505. //
  506. for (pStackEntry = pCtx->pStackTable->begin();
  507. pStackEntry != pCtx->pStackTable->end();
  508. pStackEntry++)
  509. {
  510. if (pComponent != pStackEntry->pLower)
  511. {
  512. continue;
  513. }
  514. pCtx->hr = pCtx->pComponents->HrInsertComponent (
  515. pStackEntry->pUpper, INS_IGNORE_IF_DUP | INS_SORTED);
  516. // Special case: NCF_DONTEXPOSELOWER
  517. // If the upper component has the NCF_DONTEXPOSELOWER characteristic,
  518. // don't recurse.
  519. //
  520. if (!pCtx->fIgnoreDontExposeLower &&
  521. (pStackEntry->pUpper->m_dwCharacter & NCF_DONTEXPOSELOWER))
  522. {
  523. continue;
  524. }
  525. // End Special case
  526. // Recurse on the upper component...
  527. //
  528. GetComponentsAboveComponent (pStackEntry->pUpper, pCtx);
  529. if (S_OK != pCtx->hr)
  530. {
  531. return;
  532. }
  533. }
  534. }
  535. VOID
  536. GetBindingsBelowComponent (
  537. IN const CComponent* pComponent,
  538. IN OUT GBCONTEXT* pCtx)
  539. {
  540. BOOL fFoundOne = FALSE;
  541. const CStackEntry* pStackEntry;
  542. // Append this component to the end of the context's working bindpath.
  543. //
  544. pCtx->hr = pCtx->BindPath.HrAppendComponent (pComponent);
  545. if (S_OK != pCtx->hr)
  546. {
  547. return;
  548. }
  549. // Special case: NCF_DONTEXPOSELOWER
  550. // If this is not the original component we are asked to find the
  551. // component for (i.e. not the top-level call) and if the component
  552. // has the NCF_DONTEXPOSELOWER characteristic, stop recursion since
  553. // this means we don't get to see components below it.
  554. //
  555. if ((pComponent != pCtx->pSourceComponent) &&
  556. (pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER))
  557. {
  558. ;
  559. }
  560. // End Special case
  561. else
  562. {
  563. // For all rows in the stack table where the upper component
  564. // is the one passed in...
  565. //
  566. for (pStackEntry = pCtx->pCore->StackTable.begin();
  567. pStackEntry != pCtx->pCore->StackTable.end();
  568. pStackEntry++)
  569. {
  570. if (pComponent != pStackEntry->pUpper)
  571. {
  572. continue;
  573. }
  574. // Detect circular bindings. If the lower component of this
  575. // stack entry is already on the bindpath we are building, we
  576. // have a circular binding. Break it now, by not recursing any
  577. // further.
  578. //
  579. if (pCtx->BindPath.FContainsComponent (pStackEntry->pLower))
  580. {
  581. g_pDiagCtx->Printf (ttidBeDiag, "Circular binding detected...\n");
  582. continue;
  583. }
  584. fFoundOne = TRUE;
  585. // Recurse on the lower component...
  586. //
  587. GetBindingsBelowComponent (pStackEntry->pLower, pCtx);
  588. if (S_OK != pCtx->hr)
  589. {
  590. return;
  591. }
  592. }
  593. }
  594. // If we didn't find any rows with pComponent as an upper, it
  595. // means we hit the depth of the bindpath. Time to add it to
  596. // the binding set as a complete path unless this is the orignal
  597. // component we were asked to find the bindpath for.
  598. //
  599. if (!fFoundOne && (pComponent != pCtx->pSourceComponent))
  600. {
  601. // Add the bindpath to the bindset if we're not pruning disabled
  602. // bindings or the bindpath isn't disabled.
  603. //
  604. if (!pCtx->fPruneDisabledBindings ||
  605. !pCtx->pCore->FIsBindPathDisabled (&pCtx->BindPath,
  606. IBD_EXACT_MATCH_ONLY))
  607. {
  608. pCtx->hr = pCtx->pBindSet->HrAddBindPath (&pCtx->BindPath,
  609. INS_APPEND | pCtx->dwAddBindPathFlags);
  610. }
  611. }
  612. const CComponent* pRemoved;
  613. pRemoved = pCtx->BindPath.RemoveLastComponent();
  614. // This should be the component we appened above.
  615. //
  616. Assert (pRemoved == pComponent);
  617. }