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.

1748 lines
54 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: M O D I F Y . C P P
  7. //
  8. // Contents: Routines used to setup modifications to the network
  9. // configuration.
  10. //
  11. // Notes:
  12. //
  13. // Author: shaunco 15 Jan 1999
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include "classinst.h"
  19. #include "filtdevs.h"
  20. #include "guisetup.h"
  21. #include "inetcfg.h"
  22. #include "lockdown.h"
  23. #include "ncmsz.h"
  24. #include "ncreg.h"
  25. #include "ncsvc.h"
  26. #include "ndispnp.h"
  27. #include "netcfg.h"
  28. #include "persist.h"
  29. #include "pnpbind.h"
  30. #include "pszarray.h"
  31. #include "util.h"
  32. #include "wscfg.h"
  33. #include "ncwins.h"
  34. #include "ncperms.h"
  35. CNetConfig*
  36. CModifyContext::PNetConfig ()
  37. {
  38. TraceFileFunc(ttidNetcfgBase);
  39. CNetConfig* pNetConfig;
  40. Assert ((LONG_PTR)this > FIELD_OFFSET(CNetConfig, ModifyCtx));
  41. // Get our containing CNetConfig pointer.
  42. //
  43. pNetConfig = CONTAINING_RECORD(this, CNetConfig, ModifyCtx);
  44. pNetConfig->Core.DbgVerifyData ();
  45. return pNetConfig;
  46. }
  47. HRESULT
  48. CModifyContext::HrDirtyComponent (
  49. IN const CComponent* pComponent)
  50. {
  51. TraceFileFunc(ttidNetcfgBase);
  52. Assert (S_OK == m_hr);
  53. Assert (m_fPrepared);
  54. Assert (pComponent);
  55. m_hr = m_DirtyComponents.HrInsertComponent (pComponent,
  56. INS_IGNORE_IF_DUP | INS_SORTED);
  57. #if DBG
  58. m_fComponentExplicitlyDirtied = TRUE;
  59. #endif
  60. TraceHr (ttidError, FAL, m_hr, FALSE,
  61. "CModifyContext::HrDirtyComponentAndComponentsAbove");
  62. return m_hr;
  63. }
  64. HRESULT
  65. CModifyContext::HrDirtyComponentAndComponentsAbove (
  66. IN const CComponent* pComponent)
  67. {
  68. TraceFileFunc(ttidNetcfgBase);
  69. GCCONTEXT Ctx;
  70. Assert (S_OK == m_hr);
  71. Assert (m_fPrepared);
  72. Assert (pComponent);
  73. // And insert the component itself.
  74. //
  75. m_hr = HrDirtyComponent (pComponent);
  76. // Only dirty the ones above if this component doesn't have the
  77. // NCF_DONTEXPOSELOWER characteristic.
  78. //
  79. if ((S_OK == m_hr) && !(pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER))
  80. {
  81. // Initialize the members of our context structure for recursion.
  82. //
  83. ZeroMemory (&Ctx, sizeof(Ctx));
  84. Ctx.pStackTable = &(PNetConfig()->Core.StackTable);
  85. Ctx.pComponents = &m_DirtyComponents;
  86. // Insert all of the component above.
  87. //
  88. GetComponentsAboveComponent (pComponent, &Ctx);
  89. m_hr = Ctx.hr;
  90. }
  91. TraceHr (ttidError, FAL, m_hr, FALSE,
  92. "CModifyContext::HrDirtyComponentAndComponentsAbove");
  93. return m_hr;
  94. }
  95. HRESULT
  96. CModifyContext::HrApplyIfOkOrCancel (
  97. IN BOOL fApply)
  98. {
  99. TraceFileFunc(ttidNetcfgBase);
  100. HRESULT hr;
  101. CNetConfig* pNetConfig;
  102. Assert (m_fPrepared);
  103. pNetConfig = PNetConfig();
  104. // Only apply if the context result is S_OK.
  105. //
  106. if (fApply && (S_OK == m_hr))
  107. {
  108. // Setupapi calls that we make during ApplyChanges have the
  109. // potential to return control to our clients windows message loop.
  110. // When this happens, and our clients are poorly written, they
  111. // may try to re-enter us on the same thread. This is disaster
  112. // waiting to happen, so we need to prevent it by raising our
  113. // reentrancy protection level before we start apply changes.
  114. //
  115. pNetConfig->Notify.PINetCfg()->RaiseRpl (RPL_DISALLOW);
  116. ApplyChanges ();
  117. pNetConfig->Notify.PINetCfg()->LowerRpl (RPL_DISALLOW);
  118. // Delete those components from m_CoreStartedWith that are not
  119. // in the current core and reset the modify context.
  120. //
  121. m_CoreStartedWith.Components.FreeComponentsNotInOtherComponentList (
  122. &pNetConfig->Core.Components);
  123. m_CoreStartedWith.Clear();
  124. hr = S_OK;
  125. // Return the correct HRESULT to the caller. If we've successfully
  126. // applied, but need a reboot, return so.
  127. //
  128. if (m_fRebootRecommended || m_fRebootRequired)
  129. {
  130. hr = NETCFG_S_REBOOT;
  131. }
  132. }
  133. else
  134. {
  135. // Cancel and release all notify objects. Do this for what is
  136. // in the core as well as what we started with. (There will
  137. // be some overlap, but they will only be released once.)
  138. // We need to do both sets so we don't miss releasing components
  139. // that have been removed. (Removed components won't be in
  140. // current core, but they will be in the core that we started
  141. // with.) Likewise, if we just released the core we started with,
  142. // we'd miss releasing those components that were added.)
  143. //
  144. pNetConfig->Notify.ReleaseAllNotifyObjects (pNetConfig->Core.Components, TRUE);
  145. pNetConfig->Notify.ReleaseAllNotifyObjects (m_CoreStartedWith.Components, TRUE);
  146. // Delete those components from m_CoreStartedWith that are not
  147. // in the current core. Then delete all the components in the
  148. // current core and reload from our persistent storage.
  149. // (This has the nice effect of invalidating all outstanding
  150. // INetCfgComponent interfaces.)
  151. //
  152. m_CoreStartedWith.Components.FreeComponentsNotInOtherComponentList (
  153. &pNetConfig->Core.Components);
  154. pNetConfig->Core.Free ();
  155. // Eject both cores (didn't you just know this metaphor was coming ;-)
  156. // and reload the core from our persisted binary. This magically,
  157. // and completely rolls everything back.
  158. //
  159. m_CoreStartedWith.Clear();
  160. pNetConfig->Core.Clear();
  161. // Return reason for failure through hr.
  162. //
  163. hr = m_hr;
  164. // Reload the configuration and, if successful, it means m_hr
  165. // will be S_OK. If unsuccessful, m_hr will be the error and will
  166. // prevent subsequent operations.
  167. //
  168. m_hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, pNetConfig);
  169. }
  170. // Very important to set m_fPrepared back to FALSE so that HrPrepare gets
  171. // called for the next modifcation and correctly copy the core etc.
  172. //
  173. m_fPrepared = FALSE;
  174. m_AddedBindPaths.Clear();
  175. m_DeletedBindPaths.Clear();
  176. m_DirtyComponents.Clear();
  177. #if DBG
  178. m_fComponentExplicitlyDirtied = FALSE;
  179. #endif
  180. Assert (!m_fPrepared);
  181. Assert (m_CoreStartedWith.FIsEmpty());
  182. Assert (m_AddedBindPaths.FIsEmpty());
  183. Assert (m_DeletedBindPaths.FIsEmpty());
  184. Assert (m_DirtyComponents.FIsEmpty());
  185. Assert (0 == m_ulRecursionDepth);
  186. Assert (!m_fComponentExplicitlyDirtied);
  187. Assert ((S_OK == hr) || (NETCFG_S_REBOOT == hr) || FAILED(hr));
  188. TraceHr (ttidError, FAL, hr, NETCFG_S_REBOOT == hr,
  189. "CModifyContext::HrApplyIfOkOrCancel");
  190. return hr;
  191. }
  192. HRESULT
  193. CModifyContext::HrPrepare ()
  194. {
  195. TraceFileFunc(ttidNetcfgBase);
  196. Assert (S_OK == m_hr);
  197. Assert (!m_fPrepared);
  198. Assert (m_CoreStartedWith.FIsEmpty());
  199. Assert (m_AddedBindPaths.FIsEmpty());
  200. Assert (m_DeletedBindPaths.FIsEmpty());
  201. Assert (m_DirtyComponents.FIsEmpty());
  202. Assert (0 == m_ulRecursionDepth);
  203. Assert (!m_fComponentExplicitlyDirtied);
  204. CNetConfig* pThis;
  205. pThis = PNetConfig();
  206. // Prepare the bind context. This will ensure all of the external
  207. // data for all components is loaded as well as all ensuring that
  208. // all notify objects have been initialized.
  209. //
  210. m_hr = m_RegBindCtx.HrPrepare (pThis);
  211. if (S_OK != m_hr)
  212. {
  213. goto finished;
  214. }
  215. // Snapshot the current core so that we know what we started with.
  216. // We will use the differences when we apply (if we get that far).
  217. //
  218. m_hr = m_CoreStartedWith.HrCopyCore (&pThis->Core);
  219. if (S_OK != m_hr)
  220. {
  221. goto finished;
  222. }
  223. // Reserve room for 64 components in the core.
  224. // (64 * 4 = 256 bytes on 32-bit platforms)
  225. //
  226. m_hr = pThis->Core.Components.HrReserveRoomForComponents (64);
  227. if (S_OK != m_hr)
  228. {
  229. goto finished;
  230. }
  231. // Reserve room for 64 stack entries in the core.
  232. // (64 * (4 + 4) = 512 bytes on 32-bit platforms)
  233. //
  234. m_hr = pThis->Core.StackTable.HrReserveRoomForEntries (64);
  235. if (S_OK != m_hr)
  236. {
  237. goto finished;
  238. }
  239. // Reserve room in our added list for 64 bindpaths of 8 components.
  240. // (64 * 16 = 1K bytes on 32-bit platforms)
  241. //
  242. m_hr = m_AddedBindPaths.HrReserveRoomForBindPaths (64);
  243. if (S_OK != m_hr)
  244. {
  245. goto finished;
  246. }
  247. // Reserve room in our deleted list for 64 bindpaths of 8 components.
  248. // (64 * 16 = 1K bytes on 32-bit platforms)
  249. //
  250. m_hr = m_DeletedBindPaths.HrReserveRoomForBindPaths (64);
  251. if (S_OK != m_hr)
  252. {
  253. goto finished;
  254. }
  255. // Reserve room for 64 components in the dirty component list.
  256. // (64 * 4) = 256 bytes on 32-bit platforms)
  257. //
  258. m_hr = m_DirtyComponents.HrReserveRoomForComponents (64);
  259. if (S_OK != m_hr)
  260. {
  261. goto finished;
  262. }
  263. m_fPrepared = TRUE;
  264. finished:
  265. TraceHr (ttidError, FAL, m_hr, FALSE, "CModifyContext::HrPrepare");
  266. return m_hr;
  267. }
  268. HRESULT
  269. CModifyContext::HrBeginBatchOperation ()
  270. {
  271. TraceFileFunc(ttidNetcfgBase);
  272. Assert (S_OK == m_hr);
  273. Assert (m_fPrepared);
  274. Assert (0 == m_ulRecursionDepth);
  275. TraceTag (ttidBeDiag, "Begin batch operation...");
  276. PushRecursionDepth();
  277. return m_hr;
  278. }
  279. HRESULT
  280. CModifyContext::HrEndBatchOperation (
  281. IN EBO_FLAG Flag)
  282. {
  283. TraceFileFunc(ttidNetcfgBase);
  284. HRESULT hr;
  285. Assert (m_fPrepared);
  286. Assert (1 == m_ulRecursionDepth);
  287. if (EBO_COMMIT_NOW == Flag)
  288. {
  289. TraceTag (ttidBeDiag, "End batch (commiting changes)...");
  290. hr = HrPopRecursionDepth ();
  291. }
  292. else
  293. {
  294. Assert (EBO_DEFER_COMMIT_UNTIL_APPLY == Flag);
  295. TraceTag (ttidBeDiag, "End batch (deferring commit until Apply)...");
  296. m_ulRecursionDepth = 0;
  297. hr = S_OK;
  298. }
  299. Assert (0 == m_ulRecursionDepth);
  300. TraceHr (ttidError, FAL, hr, FALSE,
  301. "CModifyContext::HrEndBatchOperation");
  302. return hr;
  303. }
  304. VOID
  305. CModifyContext::PushRecursionDepth ()
  306. {
  307. TraceFileFunc(ttidNetcfgBase);
  308. Assert (S_OK == m_hr);
  309. Assert (m_fPrepared);
  310. m_ulRecursionDepth++;
  311. }
  312. HRESULT
  313. CModifyContext::HrPopRecursionDepth ()
  314. {
  315. TraceFileFunc(ttidNetcfgBase);
  316. Assert (m_fPrepared);
  317. Assert (m_ulRecursionDepth > 0);
  318. m_ulRecursionDepth--;
  319. if (0 != m_ulRecursionDepth)
  320. {
  321. return m_hr;
  322. }
  323. // We're at the top-level of the install or remove modifcation so
  324. // apply or cancel the changes depending on the state of the context
  325. // result.
  326. //
  327. HRESULT hr;
  328. hr = HrApplyIfOkOrCancel (S_OK == m_hr);
  329. TraceHr (ttidError, FAL, hr, FALSE,
  330. "CModifyContext::HrPopRecursionDepth");
  331. return hr;
  332. }
  333. //----------------------------------------------------------------------------
  334. // This is a convenience method to find and process Winsock Remove
  335. // section for a component which is about to be removed.
  336. HRESULT
  337. CModifyContext::HrProcessWinsockRemove(IN const CComponent *pComponent)
  338. {
  339. TraceFileFunc(ttidNetcfgBase);
  340. HINF hinf = NULL;
  341. HKEY hkeyInstance = NULL;
  342. HRESULT hr;
  343. Assert(pComponent);
  344. hr = pComponent->HrOpenInfFile(&hinf);
  345. if (S_OK == hr)
  346. {
  347. static const WCHAR c_szRemoveSectionSuffix[] = L".Remove";
  348. // We get the remove section name and process all relevant sections
  349. WCHAR szRemoveSection[_MAX_PATH];
  350. DWORD cbBuffer = sizeof (szRemoveSection);
  351. hr = pComponent->HrOpenInstanceKey (KEY_READ,
  352. &hkeyInstance, NULL, NULL);
  353. if(S_OK == hr)
  354. {
  355. hr = HrRegQuerySzBuffer (hkeyInstance, REGSTR_VAL_INFSECTION,
  356. szRemoveSection, &cbBuffer);
  357. if (S_OK == hr)
  358. {
  359. //HrAddOrRemoveWinsockDependancy processes the winsock
  360. //remove section in the given inf file and then calls
  361. //MigrateWinsockConfiguration which will cause the
  362. //necessary PnP notifications to be issued to the
  363. //interested application.
  364. wcscat (szRemoveSection, c_szRemoveSectionSuffix);
  365. hr = HrAddOrRemoveWinsockDependancy (hinf, szRemoveSection);
  366. }
  367. RegSafeCloseKey (hkeyInstance);
  368. }
  369. }
  370. TraceHr (ttidError, FAL, hr, FALSE,
  371. "CModifyContext::HrProcessWinsockRemove (%S)",
  372. pComponent->PszGetPnpIdOrInfId());
  373. return hr;
  374. }
  375. VOID
  376. CModifyContext::ApplyChanges ()
  377. {
  378. TraceFileFunc(ttidNetcfgBase);
  379. HRESULT hr;
  380. CNetConfig* pNetConfig;
  381. CComponentList::const_iterator iter;
  382. CComponent* pComponent;
  383. CFilterDevices FilterDevices (&PNetConfig()->Core);
  384. CPszArray ServiceNames;
  385. CServiceManager ServiceManager;
  386. PCWSTR pszService;
  387. BOOL fRebootNeeded;
  388. BOOL fMigrateWinsock;
  389. BOOL fModifyFilterDevices;
  390. BOOL fSignalNetworkProviderLoaded;
  391. BOOL fUserIsNetConfigOps;
  392. BOOL fCallCoFreeUnusedLibraries;
  393. Assert (S_OK == m_hr);
  394. Assert (m_fPrepared);
  395. Assert (0 == m_ulRecursionDepth);
  396. pNetConfig = PNetConfig();
  397. fMigrateWinsock = FALSE;
  398. fModifyFilterDevices = FALSE;
  399. fSignalNetworkProviderLoaded = FALSE;
  400. fUserIsNetConfigOps = FIsUserNetworkConfigOps();
  401. fCallCoFreeUnusedLibraries = FALSE;
  402. //+-----------------------------------------------------------------------
  403. // Step 0: Prepare m_AddedBindPaths, m_DeletedBindPaths, and
  404. // m_DirtyComponents.
  405. //
  406. // Add the bindpaths that were once disabled, but are now enabled, to
  407. // m_AddedBindPaths. We do this so that PnP notifications are sent for
  408. // them.
  409. //
  410. m_hr = m_AddedBindPaths.HrAddBindPathsInSet1ButNotInSet2 (
  411. &m_CoreStartedWith.DisabledBindings,
  412. &pNetConfig->Core.DisabledBindings);
  413. if (S_OK != m_hr)
  414. {
  415. return;
  416. }
  417. // Add the bindpaths that were once enabled, but are now disabled, to
  418. // m_DeletedBindPaths. We do this so that PnP notifications are sent for
  419. // them.
  420. //
  421. m_hr = m_DeletedBindPaths.HrAddBindPathsInSet1ButNotInSet2 (
  422. &pNetConfig->Core.DisabledBindings,
  423. &m_CoreStartedWith.DisabledBindings);
  424. if (S_OK != m_hr)
  425. {
  426. return;
  427. }
  428. // m_fDirtyComponents should be empty unless we've explicitly dirtied
  429. // one or more. If m_fDirtyComponents were not empty, it would probably
  430. // mean we forgot to clear it after the last Apply or Cancel.
  431. // Conversely, m_DirtyComponents better not be empty if we've explicitly
  432. // dirtied one or more.
  433. //
  434. Assert (FIff(!m_fComponentExplicitlyDirtied, m_DirtyComponents.FIsEmpty()));
  435. // Dirty the affected components (owners and adapters in bindpaths of
  436. // length 2) from the added and deleted bindpaths. We need to write
  437. // bindings for these components.
  438. //
  439. m_hr = m_AddedBindPaths.HrGetAffectedComponentsInBindingSet (
  440. &m_DirtyComponents);
  441. if (S_OK != m_hr)
  442. {
  443. return;
  444. }
  445. m_hr = m_DeletedBindPaths.HrGetAffectedComponentsInBindingSet (
  446. &m_DirtyComponents);
  447. if (S_OK != m_hr)
  448. {
  449. return;
  450. }
  451. // Dirty components that exist in the current core, but not in the core
  452. // we started with. (These are added components).
  453. //
  454. m_hr = m_DirtyComponents.HrAddComponentsInList1ButNotInList2 (
  455. &pNetConfig->Core.Components,
  456. &m_CoreStartedWith.Components);
  457. if (S_OK != m_hr)
  458. {
  459. return;
  460. }
  461. // Dirty components that exist in the core we started with, but not in
  462. // the current core. (These are removed components).
  463. //
  464. m_hr = m_DirtyComponents.HrAddComponentsInList1ButNotInList2 (
  465. &m_CoreStartedWith.Components,
  466. &pNetConfig->Core.Components);
  467. if (S_OK != m_hr)
  468. {
  469. return;
  470. }
  471. g_pDiagCtx->Printf (ttidBeDiag,
  472. "Step 0: The following components are dirty:\n");
  473. for (iter = m_DirtyComponents.begin();
  474. iter != m_DirtyComponents.end();
  475. iter++)
  476. {
  477. pComponent = *iter;
  478. Assert (pComponent);
  479. if (!pNetConfig->Core.Components.FComponentInList (pComponent))
  480. {
  481. g_pDiagCtx->Printf (ttidBeDiag, " %-12S (removed)\n",
  482. pComponent->PszGetPnpIdOrInfId());
  483. }
  484. else if (!m_CoreStartedWith.Components.FComponentInList (pComponent))
  485. {
  486. g_pDiagCtx->Printf (ttidBeDiag, " %-12S (installed)\n",
  487. pComponent->PszGetPnpIdOrInfId());
  488. }
  489. else
  490. {
  491. g_pDiagCtx->Printf (ttidBeDiag, " %S\n",
  492. pComponent->PszGetPnpIdOrInfId());
  493. }
  494. }
  495. // Reserve room for 32 pointers to service names. We use this buffer
  496. // to start and stop services.
  497. //
  498. m_hr = ServiceNames.HrReserveRoomForPointers (32);
  499. if (S_OK != m_hr)
  500. {
  501. return;
  502. }
  503. // See if we are going to modify any filter devices. If we are,
  504. // we'll go through all of the steps of loading filter devices, removing
  505. // any we don't need, installing any new ones, and binding them all up.
  506. // We only modify filter devices if the user is a normal admin and not
  507. // a netcfgop.
  508. //
  509. // This test could be further refined to see if we had any filters which
  510. // were dirty or if we had any dirty adapters which are filtered.
  511. //
  512. if (!fUserIsNetConfigOps)
  513. {
  514. fModifyFilterDevices = pNetConfig->Core.FContainsFilterComponent() ||
  515. m_CoreStartedWith.FContainsFilterComponent();
  516. }
  517. else
  518. {
  519. Assert(!fModifyFilterDevices);
  520. }
  521. if (fModifyFilterDevices)
  522. {
  523. // Allow the filter devices structure to reserve whatever memory it
  524. // may need.
  525. //
  526. m_hr = FilterDevices.HrPrepare ();
  527. if (S_OK != m_hr)
  528. {
  529. return;
  530. }
  531. }
  532. pNetConfig->Core.DisabledBindings.Printf (ttidBeDiag,
  533. " The following bindings are currently disabled:\n");
  534. //+-----------------------------------------------------------------------
  535. // Step 1: Save the network configuration binary.
  536. //
  537. g_pDiagCtx->Printf (ttidBeDiag,
  538. "Step 1: Save the network configuration binary.\n");
  539. HrSaveNetworkConfigurationToRegistry (pNetConfig);
  540. //+-----------------------------------------------------------------------
  541. // Step 2: Write the static bindings for all changed components.
  542. //
  543. g_pDiagCtx->Printf (ttidBeDiag,
  544. "Step 2: Write the following static bindings.\n");
  545. for (iter = m_DirtyComponents.begin();
  546. iter != m_DirtyComponents.end();
  547. iter++)
  548. {
  549. pComponent = *iter;
  550. Assert (pComponent);
  551. // If any protocols are dirty, we'll want to migrate winsock
  552. // configuration later.
  553. //
  554. if (NC_NETTRANS == pComponent->Class())
  555. {
  556. fMigrateWinsock = TRUE;
  557. }
  558. // If the component is in the core, write its bindings.
  559. // If it is not in the core, it means it has been removed and
  560. // we should therefore remove its bindings.
  561. //
  562. if (pNetConfig->Core.Components.FComponentInList (pComponent))
  563. {
  564. hr = m_RegBindCtx.HrWriteBindingsForComponent (pComponent);
  565. // Remember any errors, but continue.
  566. //
  567. if (S_OK != hr)
  568. {
  569. Assert (FAILED(hr));
  570. m_hr = hr;
  571. }
  572. }
  573. else
  574. {
  575. // Only delete if we're not installing another version of this
  576. // component that has a duplicate PnpId. If we had already
  577. // written the bindings for the newly installed one, and then
  578. // deleted the ones for the removed (yet duplicate PnpId), we'd
  579. // effectivly delete the bindings for the new one too. See the
  580. // comments at step 6 for how we can get into this case.
  581. //
  582. if (!FIsEnumerated (pComponent->Class()) ||
  583. !pNetConfig->Core.Components.PFindComponentByPnpId (
  584. pComponent->m_pszPnpId))
  585. {
  586. // There's no reason to fail if we can't delete the bindings.
  587. // The entire component is about to be tossed anyway.
  588. //
  589. (VOID) m_RegBindCtx.HrDeleteBindingsForComponent (pComponent);
  590. }
  591. }
  592. }
  593. //+-----------------------------------------------------------------------
  594. // Step 3: Notify ApplyRegistryChanges
  595. //
  596. g_pDiagCtx->Printf (ttidBeDiag,
  597. "Step 3: Notify: apply registry changes\n");
  598. for (iter = m_DirtyComponents.begin();
  599. iter != m_DirtyComponents.end();
  600. iter++)
  601. {
  602. pComponent = *iter;
  603. Assert (pComponent);
  604. pComponent->Notify.ApplyRegistryChanges (
  605. pNetConfig->Notify.PINetCfg(),
  606. &fRebootNeeded);
  607. if (fRebootNeeded)
  608. {
  609. m_fRebootRecommended = TRUE;
  610. g_pDiagCtx->Printf (ttidBeDiag, " %S notify object wants a reboot\n",
  611. pComponent->m_pszInfId);
  612. }
  613. }
  614. // Migrate Winsock configuration if needed.
  615. // Important to do this after the LANA map is written, afer Notify Applys
  616. // are called, but before any services are started.
  617. //
  618. if (fMigrateWinsock)
  619. {
  620. g_pDiagCtx->Printf (ttidBeDiag, "Migrating winsock configuration.\n");
  621. (VOID) HrMigrateWinsockConfiguration ();
  622. }
  623. //+-----------------------------------------------------------------------
  624. // Step 4: Unbind deleted bindpaths.
  625. //
  626. g_pDiagCtx->Printf (ttidBeDiag,
  627. "Step 4: Unbind the following deleted bindings:\n");
  628. if (!m_DeletedBindPaths.FIsEmpty())
  629. {
  630. // We don't need to send UNBIND notifications for bindpaths that
  631. // involve adapters that have been removed. They will be unbound
  632. // automatically when the adapter is uninstalled. (For the case
  633. // when the class installer is notifying us of a removed adapter,
  634. // its important NOT to try to send an UNBIND notification because
  635. // the adapter has already been uninstalled (hence unbound) and
  636. // our notification might come back in error causing us to need
  637. // a reboot uneccessary.
  638. //
  639. // So, remove the bindpaths in m_DeletedBindPaths that involve
  640. // adapters that have been removed.
  641. //
  642. for (iter = m_DirtyComponents.begin();
  643. iter != m_DirtyComponents.end();
  644. iter++)
  645. {
  646. pComponent = *iter;
  647. Assert (pComponent);
  648. // If its enumerated, and not in the current core, its a
  649. // removed adapter.
  650. //
  651. if (FIsEnumerated (pComponent->Class()) &&
  652. !pNetConfig->Core.Components.FComponentInList (pComponent))
  653. {
  654. m_DeletedBindPaths.RemoveBindPathsWithComponent (pComponent);
  655. }
  656. }
  657. m_DeletedBindPaths.SortForPnpUnbind ();
  658. m_RegBindCtx.PnpBindOrUnbindBindPaths (UNBIND,
  659. &m_DeletedBindPaths,
  660. &fRebootNeeded);
  661. if (fRebootNeeded)
  662. {
  663. m_fRebootRecommended = TRUE;
  664. }
  665. }
  666. //+-----------------------------------------------------------------------
  667. // Step 5: Stop services for removed components.
  668. //
  669. g_pDiagCtx->Printf (ttidBeDiag,
  670. "Step 5: Stop the following services:\n");
  671. Assert (0 == ServiceNames.Count());
  672. for (iter = m_DirtyComponents.begin();
  673. iter != m_DirtyComponents.end();
  674. iter++)
  675. {
  676. pComponent = *iter;
  677. Assert (pComponent);
  678. // Ignore enumerated components because they will have their drivers
  679. // stopped automatically (if appropriate) when they are removed.
  680. // Ignore components that are in the current core (not being removed).
  681. //
  682. if (FIsEnumerated (pComponent->Class()) ||
  683. pNetConfig->Core.Components.FComponentInList (pComponent))
  684. {
  685. continue;
  686. }
  687. // Winsock remove section needs to be processed for every
  688. // component that is being removed in order to update
  689. // Transport key for the winsock registry settings
  690. HrProcessWinsockRemove (pComponent);
  691. // If its a protcol, send an UNLOAD before trying to stop the service.
  692. //
  693. if ((NC_NETTRANS == pComponent->Class()) || (NCF_NDIS_PROTOCOL & pComponent->m_dwCharacter))
  694. {
  695. // Unload can fail as a lot of drivers do not support it.
  696. // Treat it as an 'FYI' indication and don't set the reboot
  697. // flag if it fails.
  698. //
  699. (VOID) HrPnpUnloadDriver (NDIS, pComponent->Ext.PszBindName());
  700. }
  701. // Ignore components that don't have any services.
  702. if (!pComponent->Ext.PszCoServices())
  703. {
  704. continue;
  705. }
  706. for (pszService = pComponent->Ext.PszCoServices();
  707. *pszService;
  708. pszService += wcslen(pszService) + 1)
  709. {
  710. (VOID)ServiceNames.HrAddPointer (pszService);
  711. g_pDiagCtx->Printf (ttidBeDiag, " %S", pszService);
  712. }
  713. g_pDiagCtx->Printf (ttidBeDiag, "\n");
  714. }
  715. if (ServiceNames.Count() > 0)
  716. {
  717. static const CSFLAGS CsStopFlags =
  718. {
  719. FALSE, // FALSE means don't start
  720. SERVICE_CONTROL_STOP, // use this control instead
  721. 15000, // wait up to 15 seconds...
  722. SERVICE_STOPPED, // ... for service to reach this state
  723. FALSE, //
  724. };
  725. hr = ServiceManager.HrControlServicesAndWait (
  726. ServiceNames.Count(),
  727. ServiceNames.begin(),
  728. &CsStopFlags);
  729. if (S_OK != hr)
  730. {
  731. m_fRebootRequired = TRUE;
  732. g_pDiagCtx->Printf (ttidBeDiag, " some service failed to stop (hr = 0x%08X)\n",
  733. hr);
  734. // Unfortunately, there is no easy way to get back which service
  735. // did not stop and then to figure out which component contains
  736. // that service. Sooo, we'll just put every component that is
  737. // being removed in lockdown. This isn't a big deal when the UI
  738. // is doing the removal because it only removes things one at a
  739. // time.
  740. //
  741. for (iter = m_DirtyComponents.begin();
  742. iter != m_DirtyComponents.end();
  743. iter++)
  744. {
  745. pComponent = *iter;
  746. Assert (pComponent);
  747. if (FIsEnumerated (pComponent->Class()) ||
  748. !pComponent->Ext.PszCoServices() ||
  749. pNetConfig->Core.Components.FComponentInList (pComponent))
  750. {
  751. continue;
  752. }
  753. LockdownComponentUntilNextReboot (pComponent->m_pszInfId);
  754. }
  755. }
  756. ServiceNames.Clear();
  757. }
  758. //+-----------------------------------------------------------------------
  759. // Step 5a: Uninstall filters first.
  760. //
  761. if (fModifyFilterDevices)
  762. {
  763. g_pDiagCtx->Printf(ttidBeDiag, "Step 5a: Remove filter devices:\n");
  764. // Order is of utmost importance here. Remove must be called first
  765. // because it initializes some state internal to FilterDevices. Start
  766. // must come after Write and Write obviously has to come after all
  767. // new filter devices are installed.
  768. //
  769. FilterDevices.LoadAndRemoveFilterDevicesIfNeeded ();
  770. }
  771. //+-----------------------------------------------------------------------
  772. // Step 6: Uninstall removed components.
  773. //
  774. g_pDiagCtx->Printf (ttidBeDiag,
  775. "Step 6: Uninstall the following components:\n");
  776. for (iter = m_DirtyComponents.begin();
  777. iter != m_DirtyComponents.end();
  778. iter++)
  779. {
  780. pComponent = *iter;
  781. Assert (pComponent);
  782. // If the component is in the core, ignore it.
  783. // If it is not in the core, it means it has been removed and
  784. // we should therefore remove its bindings.
  785. //
  786. if (pNetConfig->Core.Components.FComponentInList (pComponent))
  787. {
  788. continue;
  789. }
  790. // If this is an enumerated component whose PnpId matches that of
  791. // a component in the current core, we've run into a special case.
  792. // This can happen when the external data (like the NetCfgInstanceId)
  793. // is corrupted and the class installer was told to update the
  794. // component. The class installer is really told to "install" the
  795. // component, but if it already exists as determined by the presence
  796. // of NetCfgInstanceId, the class installer translates it to "update".
  797. // Without the key, the class installer thinks its installing
  798. // a new one. We detect the duplicate PnpId and remove the "prior"
  799. // so we can install the "new". This "prior" instance is what we
  800. // are finalizing the remove of, but if we call HrCiRemoveComponent,
  801. // it just removes the same PnpId that the class installer told us
  802. // to install. By not calling HrCiRemoveComponent for this case,
  803. // the "prior" instance key gets reused implicitly by the "new"
  804. // instance.
  805. //
  806. if (FIsEnumerated (pComponent->Class()) &&
  807. pNetConfig->Core.Components.PFindComponentByPnpId (
  808. pComponent->m_pszPnpId))
  809. {
  810. g_pDiagCtx->Printf (ttidBeDiag,
  811. " Skip removal of %S because a duplicate was installed\n",
  812. pComponent->m_pszPnpId);
  813. continue;
  814. }
  815. g_pDiagCtx->Printf (ttidBeDiag,
  816. " %S\n", pComponent->PszGetPnpIdOrInfId());
  817. hr = HrCiRemoveComponent (pComponent, &pComponent->m_strRemoveSection);
  818. // We can ignore SPAPI_E_NO_SUCH_DEVINST because the class installer
  819. // may have already removed it and is just notifying us.
  820. //
  821. if ((S_OK != hr) && (SPAPI_E_NO_SUCH_DEVINST != hr))
  822. {
  823. m_fRebootRequired = TRUE;
  824. g_pDiagCtx->Printf (ttidBeDiag, " ^^^ needs a reboot (hr = 0x%08X)\n",
  825. hr);
  826. }
  827. }
  828. //+-----------------------------------------------------------------------
  829. // Step 6a: Modify filter devices.
  830. //
  831. if (fModifyFilterDevices)
  832. {
  833. g_pDiagCtx->Printf (ttidBeDiag, "Step 6a: Modify filter devices:\n");
  834. FilterDevices.InstallFilterDevicesIfNeeded ();
  835. (VOID)m_RegBindCtx.HrWriteBindingsForFilterDevices (&FilterDevices);
  836. PruneNdisWanBindPathsIfActiveRasConnections (
  837. &FilterDevices.m_BindPathsToRebind,
  838. &fRebootNeeded);
  839. if (fRebootNeeded)
  840. {
  841. m_fRebootRecommended = TRUE;
  842. }
  843. m_RegBindCtx.PnpBindOrUnbindBindPaths (UNBIND,
  844. &FilterDevices.m_BindPathsToRebind,
  845. &fRebootNeeded);
  846. if (fRebootNeeded)
  847. {
  848. m_fRebootRecommended = TRUE;
  849. }
  850. g_pDiagCtx->Printf (ttidBeDiag, "Step 6b: Starting filter devices:\n");
  851. FilterDevices.StartFilterDevices ();
  852. FilterDevices.Free ();
  853. }
  854. //+-----------------------------------------------------------------------
  855. // Step 7: Start services for added components.
  856. //
  857. Assert (0 == ServiceNames.Count());
  858. g_pDiagCtx->Printf (ttidBeDiag,
  859. "Step 7: Start the following drivers/services:\n");
  860. for (iter = m_DirtyComponents.begin();
  861. iter != m_DirtyComponents.end();
  862. iter++)
  863. {
  864. pComponent = *iter;
  865. Assert (pComponent);
  866. // If the component is in the core we started with, ignore it.
  867. // If it is not in the core we started with, it means it is newly
  868. // installed we should therefore start its services.
  869. //
  870. if (m_CoreStartedWith.Components.FComponentInList (pComponent))
  871. {
  872. continue;
  873. }
  874. // If we've added a network client, we'll need to signal the
  875. // network provider loaded event after we've started its service.
  876. //
  877. if (NC_NETCLIENT == pComponent->Class())
  878. {
  879. fSignalNetworkProviderLoaded = TRUE;
  880. }
  881. if (FIsEnumerated (pComponent->Class()))
  882. {
  883. g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pComponent->m_pszPnpId);
  884. hr = pComponent->HrStartOrStopEnumeratedComponent (DICS_START);
  885. if (S_OK != hr)
  886. {
  887. m_fRebootRecommended = TRUE;
  888. g_pDiagCtx->Printf (ttidBeDiag, " ^^^ needs a reboot (hr = 0x%08X)\n",
  889. hr);
  890. }
  891. if (FIsPhysicalNetAdapter (pComponent->Class(),
  892. pComponent->m_dwCharacter) && FInSystemSetup())
  893. {
  894. ProcessAdapterAnswerFileIfExists (pComponent);
  895. }
  896. }
  897. else if (pComponent->Ext.PszCoServices())
  898. {
  899. for (pszService = pComponent->Ext.PszCoServices();
  900. *pszService;
  901. pszService += wcslen(pszService) + 1)
  902. {
  903. (VOID)ServiceNames.HrAddPointer (pszService);
  904. g_pDiagCtx->Printf (ttidBeDiag, " %S", pszService);
  905. }
  906. g_pDiagCtx->Printf (ttidBeDiag, "\n");
  907. // If we're in system setup, then exclude whatever services
  908. // the component has marked as such.
  909. //
  910. if (FInSystemSetup())
  911. {
  912. ExcludeMarkedServicesForSetup (pComponent, &ServiceNames);
  913. }
  914. }
  915. }
  916. if ((ServiceNames.Count() > 0) &&
  917. !(g_pDiagCtx->Flags() & DF_DONT_START_SERVICES))
  918. {
  919. static const CSFLAGS CsStartFlags =
  920. {
  921. TRUE, // TRUE means start
  922. 0,
  923. 20000, // wait up to 20 seconds...
  924. SERVICE_RUNNING, // ... for service to reach this state
  925. TRUE, // ignore demand-start and disabled
  926. };
  927. hr = ServiceManager.HrControlServicesAndWait (
  928. ServiceNames.Count(),
  929. ServiceNames.begin(),
  930. &CsStartFlags);
  931. if (S_OK != hr)
  932. {
  933. m_fRebootRecommended = TRUE;
  934. g_pDiagCtx->Printf (ttidBeDiag, " some service failed to start (hr = 0x%08X)\n",
  935. hr);
  936. }
  937. }
  938. //+-----------------------------------------------------------------------
  939. // Step 8: Bind added bindpaths.
  940. //
  941. g_pDiagCtx->Printf (ttidBeDiag,
  942. "Step 8: Bind the following added bindings:\n");
  943. if (fModifyFilterDevices)
  944. {
  945. hr = m_AddedBindPaths.HrAppendBindingSet (
  946. &FilterDevices.m_BindPathsToRebind);
  947. if (S_OK != hr)
  948. {
  949. // Well, that's not good, but there is nothing we can do about
  950. // it now. (Most likely we ran out of memory.)
  951. }
  952. }
  953. if (!m_AddedBindPaths.FIsEmpty())
  954. {
  955. CBindPath* pBindPath;
  956. // We don't need to send BIND notifications for bindpaths that
  957. // involve adapters that have been newly installed. They will be
  958. // bound automatically when the adapter is started.
  959. //
  960. // Update to the above comment: We THOUGHT that was correct, but it
  961. // turns out it isn't. TDI isn't PNP (guess they must have missed
  962. // THAT memo) and they are not re-reading the new bind strings
  963. // from the registry when lower notifications bubble up. So, we
  964. // have to send these BINDS for added adapters too.
  965. //
  966. // We should remove bindpaths that involve components that have
  967. // been removed. These can end up in added bindpaths because way
  968. // up in step 0, we added bindpaths that were disabled in the
  969. // core we started with and that are no longer disabled in the
  970. // current core. Well, when the component is removed, its disabled
  971. // bindings are removed, so this case would have caused us to add
  972. // the bindpath to this binding set.
  973. //
  974. for (iter = m_DirtyComponents.begin();
  975. iter != m_DirtyComponents.end();
  976. iter++)
  977. {
  978. pComponent = *iter;
  979. Assert (pComponent);
  980. // If its been removed, remove any bindpaths that reference it.
  981. //
  982. if (!pNetConfig->Core.Components.FComponentInList (pComponent))
  983. {
  984. m_AddedBindPaths.RemoveBindPathsWithComponent (pComponent);
  985. }
  986. }
  987. // To prevent TDI from sending duplicate BINDs to its clients, we
  988. // have to do a little more work. We need to not send the TDI
  989. // BINDs to components that are newly installed. This is because
  990. // TDI sent them the BINDs when we started the driver above.
  991. // So, for each added bindpath, if it's going to the TDI layer, and
  992. // the owner (topmost) component of the bindpath is newly installed,
  993. // remove it from the added binding so we won't send a notification
  994. // for it below.
  995. //
  996. pBindPath = m_AddedBindPaths.begin();
  997. while (pBindPath != m_AddedBindPaths.end())
  998. {
  999. UINT unLayer = GetPnpLayerForBindPath (pBindPath);
  1000. if ((TDI == unLayer) &&
  1001. !m_CoreStartedWith.Components.FComponentInList (
  1002. pBindPath->POwner()))
  1003. {
  1004. m_AddedBindPaths.erase (pBindPath);
  1005. }
  1006. else
  1007. {
  1008. pBindPath++;
  1009. }
  1010. }
  1011. m_AddedBindPaths.SortForPnpBind ();
  1012. m_RegBindCtx.PnpBindOrUnbindBindPaths (BIND,
  1013. &m_AddedBindPaths,
  1014. &fRebootNeeded);
  1015. if (fRebootNeeded)
  1016. {
  1017. // If BINDs fail, we should recommend a reboot, but one is
  1018. // not required for subsequent installs or removes.
  1019. //
  1020. m_fRebootRecommended = TRUE;
  1021. }
  1022. }
  1023. // Signal the network provider loaded event if needed.
  1024. // Probably best to do this after we've indiciated the PnP bindings
  1025. // (above) to the new clients.
  1026. //
  1027. if (fSignalNetworkProviderLoaded)
  1028. {
  1029. SignalNetworkProviderLoaded ();
  1030. }
  1031. //+-----------------------------------------------------------------------
  1032. // Step 9: Allow notify objects to apply PnP changes
  1033. //
  1034. g_pDiagCtx->Printf (ttidBeDiag,
  1035. "Step 9: Notify: apply PnP changes\n");
  1036. for (iter = m_DirtyComponents.begin();
  1037. iter != m_DirtyComponents.end();
  1038. iter++)
  1039. {
  1040. pComponent = *iter;
  1041. Assert (pComponent);
  1042. pComponent->Notify.ApplyPnpChanges (
  1043. pNetConfig->Notify.PINetCfg(),
  1044. &fRebootNeeded);
  1045. if (fRebootNeeded)
  1046. {
  1047. g_pDiagCtx->Printf (ttidBeDiag,
  1048. " %S notify object wants a reboot\n",
  1049. pComponent->m_pszInfId);
  1050. // If the component has been removed, treat the reboot
  1051. // as mandatory. (The reason being that we cannot risk a
  1052. // failed re-install.) We put the component into lockdown
  1053. // in this situation.
  1054. //
  1055. if (!pNetConfig->Core.Components.FComponentInList (pComponent))
  1056. {
  1057. m_fRebootRequired = TRUE;
  1058. LockdownComponentUntilNextReboot (pComponent->m_pszInfId);
  1059. }
  1060. else
  1061. {
  1062. m_fRebootRecommended = TRUE;
  1063. }
  1064. }
  1065. }
  1066. //+-----------------------------------------------------------------------
  1067. // Step 10: Release notify objects for removed components and
  1068. // process any DelFiles in the remove section of their INF.
  1069. //
  1070. g_pDiagCtx->Printf (ttidBeDiag,
  1071. "Step 10: Release notify objects for removed components:\n");
  1072. for (iter = m_DirtyComponents.begin();
  1073. iter != m_DirtyComponents.end();
  1074. iter++)
  1075. {
  1076. pComponent = *iter;
  1077. Assert (pComponent);
  1078. // Skip enumerated components (they don't have notify objects), and
  1079. // Skip components that were not removed.
  1080. // Skip components that don't have their INF open (like unsupported
  1081. // components that get removed during GUI setup.)
  1082. //
  1083. if (FIsEnumerated (pComponent->Class()) ||
  1084. pNetConfig->Core.Components.FComponentInList (pComponent) ||
  1085. !pComponent->GetCachedInfFile())
  1086. {
  1087. continue;
  1088. }
  1089. pComponent->Notify.ReleaseNotifyObject(NULL, FALSE);
  1090. fCallCoFreeUnusedLibraries = TRUE;
  1091. }
  1092. if (fCallCoFreeUnusedLibraries)
  1093. {
  1094. g_pDiagCtx->Printf (ttidBeDiag,
  1095. " calling CoFreeUnusedLibraries before running remove sections\n");
  1096. // Now ask COM to unload any DLLs hosting COM objects that are no longer
  1097. // in use. (This is a bit heavy-handed as it affects the entire process,
  1098. // but there is currently no other way to safely unload the DLLs hosting
  1099. // the notify objects of the removed components.)
  1100. //
  1101. CoFreeUnusedLibrariesEx(0, 0);
  1102. for (iter = m_DirtyComponents.begin();
  1103. iter != m_DirtyComponents.end();
  1104. iter++)
  1105. {
  1106. pComponent = *iter;
  1107. Assert (pComponent);
  1108. // Skip enumerated components (they don't have notify objects), and
  1109. // Skip components that were not removed.
  1110. // Skip components that don't have their INF open (like unsupported
  1111. // components that get removed during GUI setup.)
  1112. //
  1113. if (FIsEnumerated (pComponent->Class()) ||
  1114. pNetConfig->Core.Components.FComponentInList (pComponent) ||
  1115. !pComponent->GetCachedInfFile())
  1116. {
  1117. continue;
  1118. }
  1119. g_pDiagCtx->Printf (ttidBeDiag,
  1120. " %S [%S]\n", pComponent->PszGetPnpIdOrInfId(),
  1121. pComponent->m_strRemoveSection.c_str());
  1122. (VOID) HrCiInstallFromInfSection(
  1123. pComponent->GetCachedInfFile(),
  1124. pComponent->m_strRemoveSection.c_str(),
  1125. NULL, NULL, SPINST_FILES);
  1126. }
  1127. }
  1128. /*
  1129. //+-----------------------------------------------------------------------
  1130. // Step 11: Reconfigure moved bindings
  1131. //
  1132. // If we changed binding order, Send PnP RECONFIGURE for all dirty
  1133. // components that are neither installed nor removed so we
  1134. // pickup these order changes.
  1135. //
  1136. for (iter = m_DirtyComponents.begin();
  1137. iter != m_DirtyComponents.end();
  1138. iter++)
  1139. {
  1140. pComponent = *iter;
  1141. Assert (pComponent);
  1142. // Skip components that have been newly installed or removed.
  1143. //
  1144. if (!pNetConfig->Core.Components.FComponentInList (pComponent) ||
  1145. !m_CoreStartedWith.Components.FComponentInList (pComponent))
  1146. {
  1147. continue;
  1148. }
  1149. // Note: send RECONFIGURE
  1150. }
  1151. */
  1152. }
  1153. HRESULT
  1154. CModifyContext::HrEnableOrDisableBindPath (
  1155. IN DWORD dwChangeFlag,
  1156. IN CBindPath* pBindPath,
  1157. IN INetCfgBindingPath* pIPath OPTIONAL)
  1158. {
  1159. TraceFileFunc(ttidNetcfgBase);
  1160. HRESULT hr;
  1161. CNetConfig* pNetConfig;
  1162. UINT CountBefore;
  1163. Assert (this);
  1164. Assert (S_OK == m_hr);
  1165. Assert (m_fPrepared);
  1166. Assert ((dwChangeFlag == NCN_ENABLE) || (dwChangeFlag == NCN_DISABLE));
  1167. Assert (pBindPath);
  1168. hr = S_OK;
  1169. pNetConfig = PNetConfig();
  1170. // Get the count of bindpaths currently disabled. If it changes
  1171. // after we enable/disable this one, we'll inform notify objects
  1172. // about it. If the count does not change, it means the state
  1173. // of the bindpath has not changed.
  1174. //
  1175. CountBefore = pNetConfig->Core.DisabledBindings.CountBindPaths();
  1176. if (NCN_ENABLE == dwChangeFlag)
  1177. {
  1178. pNetConfig->Core.EnableBindPath (pBindPath);
  1179. Assert (S_OK == hr);
  1180. }
  1181. else
  1182. {
  1183. hr = pNetConfig->Core.HrDisableBindPath (pBindPath);
  1184. }
  1185. if ((S_OK == hr) &&
  1186. (pNetConfig->Core.DisabledBindings.CountBindPaths() != CountBefore))
  1187. {
  1188. // Note: Need to protect against bad notify objects that
  1189. // switch the state of a bindpath we are notifying for.
  1190. // This could cause an infinite loop. Solve by adding a
  1191. // recursion count and bindset to the modify context dedicated
  1192. // to bindpath enabling/disabling. When the count is zero,
  1193. // we clear the bindingset, add the bindpath we are about to
  1194. // notify for, increment the recursion count and call
  1195. // NotifyBindPath. When the call returns, we decrement the
  1196. // recursion count, remove the bindpath from the binding set,
  1197. // and return. Before we call NotifyBindPath when the recursion
  1198. // count is non-zero, if the bindpath is already in the
  1199. // bindingset, we don't call.
  1200. //
  1201. pNetConfig->Notify.NotifyBindPath (dwChangeFlag, pBindPath, pIPath);
  1202. }
  1203. TraceHr (ttidError, FAL, hr, FALSE,
  1204. "CModifyContext::HrEnableOrDisableBindPath");
  1205. return hr;
  1206. }
  1207. VOID
  1208. CModifyContext::InstallOrRemoveRequiredComponents (
  1209. IN CComponent* pComponent,
  1210. IN IOR_ACTION Action)
  1211. {
  1212. TraceFileFunc(ttidNetcfgBase);
  1213. HRESULT hr;
  1214. HKEY hkeyInstance;
  1215. PWSTR pszRequiredList;
  1216. const WCHAR szDelims[] = L", ";
  1217. Assert (this);
  1218. Assert (S_OK == m_hr);
  1219. Assert (m_fPrepared);
  1220. Assert (pComponent);
  1221. Assert ((IOR_INSTALL == Action) || (IOR_REMOVE == Action));
  1222. pszRequiredList = NULL;
  1223. // Open the instance key of the component and read the RequireAll value.
  1224. // This value may not exist, which is okay, it means we have nothing
  1225. // to do.
  1226. //
  1227. hr = pComponent->HrOpenInstanceKey (KEY_READ, &hkeyInstance, NULL, NULL);
  1228. if (S_OK == hr)
  1229. {
  1230. HKEY hkeyNdi;
  1231. hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
  1232. if (S_OK == hr)
  1233. {
  1234. hr = HrRegQuerySzWithAlloc (hkeyNdi, L"RequiredAll",
  1235. &pszRequiredList);
  1236. RegCloseKey (hkeyNdi);
  1237. }
  1238. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1239. {
  1240. hr = S_OK;
  1241. Assert (!pszRequiredList);
  1242. }
  1243. RegCloseKey (hkeyInstance);
  1244. }
  1245. // If we have a list of required components, install or remove them.
  1246. //
  1247. if ((S_OK == hr) && pszRequiredList)
  1248. {
  1249. CNetConfig* pNetConfig;
  1250. INetCfgComponent* pIComp;
  1251. pNetConfig = PNetConfig();
  1252. hr = pComponent->HrGetINetCfgComponentInterface (
  1253. pNetConfig->Notify.PINetCfg(),
  1254. &pIComp);
  1255. if (S_OK == hr)
  1256. {
  1257. PCWSTR pszInfId;
  1258. PWSTR pszNextInfId;
  1259. OBO_TOKEN OboToken;
  1260. CComponent* pComponentToRemove;
  1261. WCHAR szInfFile [_MAX_PATH];
  1262. ZeroMemory (&OboToken, sizeof(OboToken));
  1263. OboToken.Type = OBO_COMPONENT;
  1264. OboToken.pncc = pIComp;
  1265. // For each INF ID in the comma separate list of required
  1266. // components...
  1267. //
  1268. for (pszInfId = GetNextStringToken (pszRequiredList, szDelims, &pszNextInfId);
  1269. pszInfId && *pszInfId;
  1270. pszInfId = GetNextStringToken (NULL, szDelims, &pszNextInfId))
  1271. {
  1272. if (IOR_INSTALL == Action)
  1273. {
  1274. NETWORK_INSTALL_PARAMS nip;
  1275. COMPONENT_INSTALL_PARAMS Params;
  1276. ZeroMemory (&Params, sizeof(Params));
  1277. // Get the Class corresponding to the INF ID.
  1278. //
  1279. m_hr = HrCiGetClassAndInfFileOfInfId (
  1280. pszInfId, &Params.Class, szInfFile);
  1281. if (S_OK != m_hr)
  1282. {
  1283. break;
  1284. }
  1285. //$REVIEW:Should we stick the filename in the
  1286. // COMPONENT_INSTALL_PARAMS so that we don't grovel
  1287. // the INF directory to find it again?
  1288. // If so, store the filename buffer in the modify
  1289. // context so we don't take up stack space or heap space.
  1290. // Just need to be sure that we use it to install the
  1291. // component before we recurse and overwrite it.
  1292. // Pack the network install parameters and call the common
  1293. // function.
  1294. //
  1295. //$REVIEW: we probably need dwSetupFlags and dwUpgradeFromBuildNo
  1296. // in the modify context saved when it was called at
  1297. // recursion depth 0. Otherwise, things installed here
  1298. // during GUI setup will have wrong parameters.
  1299. //
  1300. nip.dwSetupFlags = 0;
  1301. nip.dwUpgradeFromBuildNo = 0;
  1302. nip.pszAnswerFile = NULL;
  1303. nip.pszAnswerSection = NULL;
  1304. // Setup the component install parameters.
  1305. //
  1306. Params.pszInfId = pszInfId;
  1307. Params.pszInfFile = szInfFile;
  1308. Params.pOboToken = FIsEnumerated (Params.Class)
  1309. ? NULL : &OboToken;
  1310. Params.pnip = &nip;
  1311. //
  1312. // THIS MAY CAUSE RECURSION
  1313. //
  1314. // (just using pComponentToRemove as a placeholder
  1315. // for a required parameter.)
  1316. //
  1317. HrInstallNewOrReferenceExistingComponent (
  1318. Params, &pComponentToRemove);
  1319. if (S_OK != m_hr)
  1320. {
  1321. break;
  1322. }
  1323. }
  1324. else
  1325. {
  1326. Assert (IOR_REMOVE == Action);
  1327. // Search for the component to remove using its INF ID.
  1328. //
  1329. pComponentToRemove = pNetConfig->Core.Components.
  1330. PFindComponentByInfId (pszInfId, NULL);
  1331. if (pComponentToRemove)
  1332. {
  1333. //
  1334. // THIS MAY CAUSE RECURSION
  1335. //
  1336. HrRemoveComponentIfNotReferenced (
  1337. pComponentToRemove,
  1338. FIsEnumerated (pComponentToRemove->Class())
  1339. ? NULL
  1340. : &OboToken,
  1341. NULL);
  1342. if (S_OK != m_hr)
  1343. {
  1344. break;
  1345. }
  1346. }
  1347. }
  1348. }
  1349. ReleaseObj (pIComp);
  1350. }
  1351. MemFree (pszRequiredList);
  1352. }
  1353. }
  1354. //----------------------------------------------------------------------------
  1355. // Update a component. Do this by generating the bindings which involve
  1356. // the component and noting them as 'OldBindPaths'. The stack entries which
  1357. // involve the component are removed and re-generated and the bindings which
  1358. // involve the component are again noted as 'NewBindPaths'. The old bindings
  1359. // are compared to the new bindings and the differences are notified to
  1360. // notify objects as either being removed or added. For any removed bindings,
  1361. // we also remove them from the core's disabled set if they happen to exist
  1362. // there too.
  1363. //
  1364. // Assumptions:
  1365. // The INF for pComponent has already been re-run so that the potentially
  1366. // new values for UpperRange, LowerRange, etc. are present in the registry.
  1367. //
  1368. // pComponent has had its external data loaded already.
  1369. //
  1370. HRESULT
  1371. CModifyContext::HrUpdateComponent (
  1372. IN CComponent* pComponent,
  1373. IN DWORD dwSetupFlags,
  1374. IN DWORD dwUpgradeFromBuildNo)
  1375. {
  1376. TraceFileFunc(ttidNetcfgBase);
  1377. HRESULT hr;
  1378. CNetConfig* pNetConfig;
  1379. CBindingSet OldBindPaths;
  1380. CBindingSet NewBindPaths;
  1381. CBindPath* pScan;
  1382. Assert (this);
  1383. Assert (S_OK == m_hr);
  1384. Assert (m_fPrepared);
  1385. Assert (pComponent);
  1386. pNetConfig = PNetConfig();
  1387. // Now that we actually are going to modify something, push a new
  1388. // recursion depth.
  1389. //
  1390. PushRecursionDepth();
  1391. Assert (S_OK == m_hr);
  1392. // Generate the "old" bindings by noting those which involve the
  1393. // component.
  1394. //
  1395. hr = pNetConfig->Core.HrGetBindingsInvolvingComponent (
  1396. pComponent,
  1397. GBF_ONLY_WHICH_CONTAIN_COMPONENT,
  1398. &OldBindPaths);
  1399. if (S_OK != hr)
  1400. {
  1401. goto finished;
  1402. }
  1403. // Reload the external data so we pickup what the possibly updated
  1404. // INF has changed.
  1405. //
  1406. hr = pComponent->Ext.HrReloadExternalData ();
  1407. if (S_OK != hr)
  1408. {
  1409. goto finished;
  1410. }
  1411. // Update the stack table entries for the component.
  1412. //
  1413. hr = pNetConfig->Core.StackTable.HrUpdateEntriesForComponent (
  1414. pComponent,
  1415. &pNetConfig->Core.Components,
  1416. INS_SORTED);
  1417. if (S_OK != hr)
  1418. {
  1419. // This is not good. We ripped out the stack entries and failed
  1420. // putting them back in. The stack table now has no entries for
  1421. // this component. Prevent this from being applied by setting the
  1422. // modify context's HRESULT to the error.
  1423. //
  1424. m_hr = hr;
  1425. goto finished;
  1426. }
  1427. // Generate the "new" bindings by noting those which involve the
  1428. // component.
  1429. //
  1430. hr = pNetConfig->Core.HrGetBindingsInvolvingComponent (
  1431. pComponent,
  1432. GBF_ONLY_WHICH_CONTAIN_COMPONENT,
  1433. &NewBindPaths);
  1434. if (S_OK != hr)
  1435. {
  1436. // Probably out of memory. Prevent apply by setting the modify
  1437. // context's HRESULT to the error.
  1438. //
  1439. m_hr = hr;
  1440. goto finished;
  1441. }
  1442. // Notify any bindpaths which have been removed.
  1443. //
  1444. for (pScan = OldBindPaths.begin();
  1445. pScan != OldBindPaths.end();
  1446. pScan++)
  1447. {
  1448. if (NewBindPaths.FContainsBindPath (pScan))
  1449. {
  1450. continue;
  1451. }
  1452. m_DeletedBindPaths.HrAddBindPath (pScan, INS_IGNORE_IF_DUP | INS_APPEND);
  1453. pNetConfig->Core.DisabledBindings.RemoveBindPath (pScan);
  1454. pNetConfig->Notify.NotifyBindPath (NCN_REMOVE, pScan, NULL);
  1455. }
  1456. // Notify any bindpaths which have been added.
  1457. //
  1458. for (pScan = NewBindPaths.begin();
  1459. pScan != NewBindPaths.end();
  1460. pScan++)
  1461. {
  1462. if (OldBindPaths.FContainsBindPath (pScan))
  1463. {
  1464. continue;
  1465. }
  1466. m_AddedBindPaths.HrAddBindPath (pScan, INS_IGNORE_IF_DUP | INS_APPEND);
  1467. pNetConfig->Notify.NotifyBindPath (NCN_ADD | NCN_ENABLE, pScan, NULL);
  1468. }
  1469. // Notify that the component has been updated.
  1470. //
  1471. pNetConfig->Notify.ComponentUpdated (pComponent,
  1472. dwSetupFlags,
  1473. dwUpgradeFromBuildNo);
  1474. finished:
  1475. hr = HrPopRecursionDepth();
  1476. TraceHr (ttidError, FAL, hr, FALSE,
  1477. "CModifyContext::HrUpdateComponent (%S)",
  1478. pComponent->PszGetPnpIdOrInfId());
  1479. return hr;
  1480. }