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.

2612 lines
81 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N E T O C . C P P
  7. //
  8. // Contents: Functions for handling installation and removal of optional
  9. // networking components.
  10. //
  11. // Notes:
  12. //
  13. // Author: danielwe 28 Apr 1997
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #include "lancmn.h"
  19. #include "ncacs.h"
  20. #include "ncatlui.h"
  21. #include "ncbeac.h"
  22. #include "nccm.h"
  23. #include "ncdhcps.h"
  24. #include "ncias.h"
  25. #include "ncmisc.h"
  26. #include "ncmsz.h"
  27. #include "ncnetcfg.h"
  28. #include "ncnetcon.h"
  29. #include "ncoc.h"
  30. #include "ncperms.h"
  31. #include "ncreg.h"
  32. #include "ncsetup.h"
  33. #include "ncsfm.h"
  34. #include "ncstring.h"
  35. #include "ncsvc.h"
  36. #include "ncxbase.h"
  37. #include "netcfgn.h"
  38. #include "netcon.h"
  39. #include "netoc.h"
  40. #include "netocp.h"
  41. #include "netocx.h"
  42. #include "resource.h"
  43. //
  44. // External component install functions.
  45. // Add an entry in this table for each component that requires additional,
  46. // non-common installation support.
  47. //
  48. // NOTE: The component name should match the section name in the INF.
  49. //
  50. #pragma BEGIN_CONST_SECTION
  51. static const OCEXTPROCS c_aocepMap[] =
  52. {
  53. { L"MacSrv", HrOcExtSFM },
  54. { L"DHCPServer", HrOcExtDHCPServer },
  55. { L"NetCM", HrOcExtCM },
  56. { L"WINS", HrOcExtWINS },
  57. { L"DNS", HrOcExtDNS },
  58. { L"ACS", HrOcExtACS },
  59. { L"SNMP", HrOcExtSNMP },
  60. { L"IAS", HrOcExtIAS },
  61. { L"BEACON", HrOcExtBEACON },
  62. };
  63. #pragma END_CONST_SECTION
  64. static const INT c_cocepMap = celems(c_aocepMap);
  65. // generic strings
  66. static const WCHAR c_szUninstall[] = L"Uninstall";
  67. static const WCHAR c_szServices[] = L"StartServices";
  68. static const WCHAR c_szDependOnComp[] = L"DependOnComponents";
  69. static const WCHAR c_szVersionSection[] = L"Version";
  70. static const WCHAR c_szProvider[] = L"Provider";
  71. static const WCHAR c_szDefManu[] = L"Unknown";
  72. static const WCHAR c_szInfRef[] = L"SubCompInf";
  73. static const WCHAR c_szDesc[] = L"OptionDesc";
  74. static const WCHAR c_szNoDepends[] = L"NoDepends";
  75. // static-IP verification
  76. static const WCHAR c_szTcpipInterfacesPath[] =
  77. L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
  78. static const WCHAR c_szEnableDHCP[] = L"EnableDHCP";
  79. extern const WCHAR c_szOcMainSection[];
  80. static const DWORD c_dwUpgradeMask = SETUPOP_WIN31UPGRADE |
  81. SETUPOP_WIN95UPGRADE |
  82. SETUPOP_NTUPGRADE;
  83. OCM_DATA g_ocmData;
  84. typedef list<NETOCDATA*> ListOcData;
  85. ListOcData g_listOcData;
  86. //+---------------------------------------------------------------------------
  87. //
  88. // Function: PnocdFindComponent
  89. //
  90. // Purpose: Looks for the given component name in the list of known
  91. // components.
  92. //
  93. // Arguments:
  94. // pszComponent [in] Name of component to lookup.
  95. //
  96. // Returns: Pointer to component's data.
  97. //
  98. // Author: danielwe 23 Feb 1998
  99. //
  100. // Notes:
  101. //
  102. NETOCDATA *PnocdFindComponent(PCWSTR pszComponent)
  103. {
  104. ListOcData::iterator iterList;
  105. for (iterList = g_listOcData.begin();
  106. iterList != g_listOcData.end();
  107. iterList++)
  108. {
  109. NETOCDATA * pnocd;
  110. pnocd = *iterList;
  111. if (!lstrcmpiW(pnocd->pszComponentId, pszComponent))
  112. {
  113. return pnocd;
  114. }
  115. }
  116. return NULL;
  117. }
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Function: DeleteAllComponents
  121. //
  122. // Purpose: Removes all components from our list and frees all associated
  123. // data.
  124. //
  125. // Arguments:
  126. // (none)
  127. //
  128. // Returns: Nothing.
  129. //
  130. // Author: danielwe 23 Feb 1998
  131. //
  132. // Notes:
  133. //
  134. VOID DeleteAllComponents()
  135. {
  136. ListOcData::iterator iterList;
  137. for (iterList = g_listOcData.begin();
  138. iterList != g_listOcData.end();
  139. iterList++)
  140. {
  141. NETOCDATA * pnocd;
  142. pnocd = (*iterList);
  143. if (pnocd->hinfFile)
  144. {
  145. SetupCloseInfFile(pnocd->hinfFile);
  146. }
  147. delete pnocd;
  148. }
  149. g_listOcData.erase(g_listOcData.begin(), g_listOcData.end());
  150. }
  151. //+---------------------------------------------------------------------------
  152. //
  153. // Function: AddComponent
  154. //
  155. // Purpose: Adds a component to our list.
  156. //
  157. // Arguments:
  158. // pszComponent [in] Name of component to add.
  159. // pnocd [in] Data to associate with component.
  160. //
  161. // Returns: Nothing.
  162. //
  163. // Author: danielwe 23 Feb 1998
  164. //
  165. // Notes:
  166. //
  167. VOID AddComponent(PCWSTR pszComponent, NETOCDATA *pnocd)
  168. {
  169. Assert(pszComponent);
  170. Assert(pnocd);
  171. pnocd->pszComponentId = SzDupSz(pszComponent);
  172. g_listOcData.push_back(pnocd);
  173. }
  174. //+---------------------------------------------------------------------------
  175. //
  176. // Function: NetOcSetupProcHelper
  177. //
  178. // Purpose: Main entry point for optional component installs
  179. //
  180. // Arguments:
  181. // pvComponentId [in] Component Id (string)
  182. // pvSubcomponentId [in] Sub component Id (string)
  183. // uFunction [in] Function being performed
  184. // uParam1 [in] First param to function
  185. // pvParam2 [in, out] Second param to function
  186. //
  187. // Returns: Win32 error if failure
  188. //
  189. // Author: danielwe 17 Dec 1997
  190. //
  191. // Notes:
  192. //
  193. DWORD NetOcSetupProcHelper(LPCVOID pvComponentId, LPCVOID pvSubcomponentId,
  194. UINT uFunction, UINT uParam1, LPVOID pvParam2)
  195. {
  196. TraceFileFunc(ttidNetOc);
  197. HRESULT hr = S_OK;
  198. switch (uFunction)
  199. {
  200. case OC_PREINITIALIZE:
  201. return OCFLAG_UNICODE;
  202. case OC_QUERY_CHANGE_SEL_STATE:
  203. TraceTag(ttidNetOc, "OC_QUERY_CHANGE_SEL_STATE: %S, %ld, 0x%08X.",
  204. pvSubcomponentId ? pvSubcomponentId : L"null", uParam1,
  205. pvParam2);
  206. if (FHasPermission(NCPERM_AddRemoveComponents))
  207. {
  208. hr = HrOnQueryChangeSelState(reinterpret_cast<PCWSTR>(pvSubcomponentId),
  209. uParam1, reinterpret_cast<UINT_PTR>(pvParam2));
  210. if (S_OK == hr)
  211. {
  212. return TRUE;
  213. }
  214. }
  215. else
  216. {
  217. NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_NO_PERMS,
  218. MB_ICONSTOP | MB_OK);
  219. }
  220. return FALSE;
  221. case OC_QUERY_SKIP_PAGE:
  222. TraceTag(ttidNetOc, "OC_QUERY_SKIP_PAGE: %ld", uParam1);
  223. return FOnQuerySkipPage(static_cast<OcManagerPage>(uParam1));
  224. case OC_WIZARD_CREATED:
  225. TraceTag(ttidNetOc, "OC_WIZARD_CREATED: 0x%08X", pvParam2);
  226. OnWizardCreated(reinterpret_cast<HWND>(pvParam2));
  227. break;
  228. case OC_INIT_COMPONENT:
  229. TraceTag(ttidNetOc, "OC_INIT_COMPONENT: %S", pvSubcomponentId ?
  230. pvSubcomponentId : L"null");
  231. hr = HrOnInitComponent(reinterpret_cast<PSETUP_INIT_COMPONENT>(pvParam2));
  232. break;
  233. case OC_ABOUT_TO_COMMIT_QUEUE:
  234. TraceTag(ttidNetOc, "OC_ABOUT_TO_COMMIT_QUEUE: %S", pvSubcomponentId ?
  235. pvSubcomponentId : L"null");
  236. hr = HrOnPreCommitFileQueue(reinterpret_cast<PCWSTR>(pvSubcomponentId));
  237. break;
  238. case OC_CALC_DISK_SPACE:
  239. // Ignore return value for now. This is not fatal anyway.
  240. (VOID) HrOnCalcDiskSpace(reinterpret_cast<PCWSTR>(pvSubcomponentId),
  241. uParam1, reinterpret_cast<HDSKSPC>(pvParam2));
  242. break;
  243. case OC_QUERY_STATE:
  244. return DwOnQueryState(reinterpret_cast<PCWSTR>(pvSubcomponentId),
  245. uParam1 == OCSELSTATETYPE_FINAL);
  246. case OC_QUEUE_FILE_OPS:
  247. TraceTag(ttidNetOc, "OC_QUEUE_FILE_OPS: %S, 0x%08X", pvSubcomponentId ?
  248. pvSubcomponentId : L"null",
  249. pvParam2);
  250. hr = HrOnQueueFileOps(reinterpret_cast<PCWSTR>(pvSubcomponentId),
  251. reinterpret_cast<HSPFILEQ>(pvParam2));
  252. break;
  253. case OC_COMPLETE_INSTALLATION:
  254. TraceTag(ttidNetOc, "OC_COMPLETE_INSTALLATION: %S, %S", pvComponentId ?
  255. pvComponentId : L"null",
  256. pvSubcomponentId ? pvSubcomponentId : L"null");
  257. hr = HrOnCompleteInstallation(reinterpret_cast<PCWSTR>(pvComponentId),
  258. reinterpret_cast<PCWSTR>(pvSubcomponentId));
  259. break;
  260. case OC_QUERY_STEP_COUNT:
  261. return DwOnQueryStepCount(reinterpret_cast<PCWSTR>(pvSubcomponentId));
  262. case OC_CLEANUP:
  263. OnCleanup();
  264. break;
  265. default:
  266. break;
  267. }
  268. if (g_ocmData.sic.HelperRoutines.SetReboot && (NETCFG_S_REBOOT == hr))
  269. {
  270. // Request a reboot. Note we don't return the warning as the OCM call
  271. // below handles it. Fall through and return NO_ERROR.
  272. //
  273. g_ocmData.sic.HelperRoutines.SetReboot(
  274. g_ocmData.sic.HelperRoutines.OcManagerContext,
  275. FALSE);
  276. }
  277. else if (FAILED(hr))
  278. {
  279. if (!g_ocmData.fErrorReported)
  280. {
  281. PCWSTR pszSubComponentId = reinterpret_cast<PCWSTR>(pvSubcomponentId);
  282. TraceError("NetOcSetupProcHelper", hr);
  283. if (pszSubComponentId)
  284. {
  285. NETOCDATA * pnocd;
  286. pnocd = PnocdFindComponent(pszSubComponentId);
  287. Assert(pnocd);
  288. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
  289. {
  290. ReportErrorHr(hr, UiOcErrorFromHr(hr), g_ocmData.hwnd,
  291. pnocd->strDesc.c_str());
  292. }
  293. }
  294. }
  295. TraceError("NetOcSetupProcHelper", hr);
  296. return DwWin32ErrorFromHr(hr);
  297. }
  298. return NO_ERROR;
  299. }
  300. //+---------------------------------------------------------------------------
  301. //
  302. // Function: HrOnInitComponent
  303. //
  304. // Purpose: Handles the OC_INIT_COMPONENT function message.
  305. //
  306. // Arguments:
  307. // psic [in] Setup data. (see OCManager spec)
  308. //
  309. // Returns: S_OK if success, Win32 error otherwise
  310. //
  311. // Author: danielwe 23 Feb 1998
  312. //
  313. // Notes:
  314. //
  315. HRESULT HrOnInitComponent (PSETUP_INIT_COMPONENT psic)
  316. {
  317. HRESULT hr = S_OK;
  318. if (OCMANAGER_VERSION <= psic->OCManagerVersion)
  319. {
  320. psic->ComponentVersion = OCMANAGER_VERSION;
  321. CopyMemory(&g_ocmData.sic, (LPVOID)psic, sizeof(SETUP_INIT_COMPONENT));
  322. }
  323. else
  324. {
  325. hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
  326. }
  327. return hr;
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Function: OnWizardCreated
  332. //
  333. // Purpose: Handles the OC_WIZARD_CREATED function message.
  334. //
  335. // Arguments:
  336. // hwnd [in] HWND of wizard (may not be NULL)
  337. //
  338. // Returns: Nothing.
  339. //
  340. // Author: danielwe 23 Feb 1998
  341. //
  342. // Notes:
  343. //
  344. VOID OnWizardCreated(HWND hwnd)
  345. {
  346. g_ocmData.hwnd = hwnd;
  347. AssertSz(g_ocmData.hwnd, "Parent HWND is NULL!");
  348. }
  349. //+---------------------------------------------------------------------------
  350. //
  351. // Function: HrOnCalcDiskSpace
  352. //
  353. // Purpose: Handles the OC_CALC_DISK_SPACE function message.
  354. //
  355. // Arguments:
  356. // pszSubComponentId [in] Name of component.
  357. // fAdd [in] TRUE if disk space should be added to total
  358. // FALSE if removed from total.
  359. // hdskspc [in] Handle to diskspace struct.
  360. //
  361. // Returns: S_OK if success, Win32 error otherwise
  362. //
  363. // Author: danielwe 23 Feb 1998
  364. //
  365. // Notes:
  366. //
  367. HRESULT HrOnCalcDiskSpace(PCWSTR pszSubComponentId, BOOL fAdd,
  368. HDSKSPC hdskspc)
  369. {
  370. HRESULT hr = S_OK;
  371. DWORD dwErr;
  372. NETOCDATA * pnocd;
  373. pnocd = PnocdFindComponent(pszSubComponentId);
  374. Assert(pnocd);
  375. TraceTag(ttidNetOc, "Calculating disk space for %S...",
  376. pszSubComponentId);
  377. hr = HrEnsureInfFileIsOpen(pszSubComponentId, *pnocd);
  378. if (SUCCEEDED(hr))
  379. {
  380. if (fAdd)
  381. {
  382. dwErr = SetupAddInstallSectionToDiskSpaceList(hdskspc,
  383. pnocd->hinfFile,
  384. NULL,
  385. pszSubComponentId,
  386. 0, 0);
  387. }
  388. else
  389. {
  390. dwErr = SetupRemoveInstallSectionFromDiskSpaceList(hdskspc,
  391. pnocd->hinfFile,
  392. NULL,
  393. pszSubComponentId,
  394. 0, 0);
  395. }
  396. if (!dwErr)
  397. {
  398. hr = HrFromLastWin32Error();
  399. }
  400. }
  401. TraceError("HrOnCalcDiskSpace", hr);
  402. return hr;
  403. }
  404. //+---------------------------------------------------------------------------
  405. //
  406. // Function: DwOnQueryState
  407. //
  408. // Purpose: Handles the OC_QUERY_STATE function message.
  409. //
  410. // Arguments:
  411. // pszSubComponentId [in] Name of component.
  412. // fFinal [in] TRUE if this is the final state query, FALSE
  413. // if not
  414. //
  415. // Returns: SubcompOn - component should be checked "on"
  416. // SubcompUseOcManagerDefault - use whatever OCManage thinks is
  417. // the default
  418. //
  419. // Author: danielwe 23 Feb 1998
  420. //
  421. // Notes:
  422. //
  423. DWORD DwOnQueryState(PCWSTR pszSubComponentId, BOOL fFinal)
  424. {
  425. HRESULT hr = S_OK;
  426. if (pszSubComponentId)
  427. {
  428. NETOCDATA * pnocd;
  429. EINSTALL_TYPE eit;
  430. pnocd = PnocdFindComponent(pszSubComponentId);
  431. if (!pnocd)
  432. {
  433. pnocd = new NETOCDATA;
  434. if(pnocd)
  435. {
  436. AddComponent(pszSubComponentId, pnocd);
  437. }
  438. }
  439. if(pnocd)
  440. {
  441. if (fFinal)
  442. {
  443. if (pnocd->fFailedToInstall)
  444. {
  445. TraceTag(ttidNetOc, "OC_QUERY_STATE: %S failed to install so "
  446. "we are turning it off", pszSubComponentId);
  447. return SubcompOff;
  448. }
  449. }
  450. else
  451. {
  452. hr = HrGetInstallType(pszSubComponentId, *pnocd, &eit);
  453. if (SUCCEEDED(hr))
  454. {
  455. pnocd->eit = eit;
  456. if ((eit == IT_INSTALL) || (eit == IT_UPGRADE))
  457. {
  458. TraceTag(ttidNetOc, "OC_QUERY_STATE: %S is ON",
  459. pszSubComponentId);
  460. return SubcompOn;
  461. }
  462. else if (eit == IT_REMOVE)
  463. {
  464. TraceTag(ttidNetOc, "OC_QUERY_STATE: %S is OFF",
  465. pszSubComponentId);
  466. return SubcompOff;
  467. }
  468. }
  469. }
  470. }
  471. }
  472. TraceTag(ttidNetOc, "OC_QUERY_STATE: %S is using default",
  473. pszSubComponentId);
  474. return SubcompUseOcManagerDefault;
  475. }
  476. //+---------------------------------------------------------------------------
  477. //
  478. // Function: HrEnsureInfFileIsOpen
  479. //
  480. // Purpose: Ensures that the INF file for the given component is open.
  481. //
  482. // Arguments:
  483. // pszSubComponentId [in] Name of component.
  484. // nocd [in, ref] Data associated with component.
  485. //
  486. // Returns: S_OK if success, Win32 error otherwise
  487. //
  488. // Author: danielwe 23 Feb 1998
  489. //
  490. // Notes:
  491. //
  492. HRESULT HrEnsureInfFileIsOpen(PCWSTR pszSubComponentId, NETOCDATA &nocd)
  493. {
  494. HRESULT hr = S_OK;
  495. tstring strInf;
  496. if (!nocd.hinfFile)
  497. {
  498. // Get component INF file name
  499. hr = HrSetupGetFirstString(g_ocmData.sic.ComponentInfHandle,
  500. pszSubComponentId, c_szInfRef,
  501. &strInf);
  502. if (SUCCEEDED(hr))
  503. {
  504. TraceTag(ttidNetOc, "Opening INF file %S...", strInf.c_str());
  505. hr = HrSetupOpenInfFile(strInf.c_str(), NULL,
  506. INF_STYLE_WIN4, NULL, &nocd.hinfFile);
  507. if (SUCCEEDED(hr))
  508. {
  509. // Append in the layout.inf file
  510. (VOID) SetupOpenAppendInfFile(NULL, nocd.hinfFile, NULL);
  511. }
  512. }
  513. // This is a good time to cache away the component description as
  514. // well.
  515. (VOID) HrSetupGetFirstString(g_ocmData.sic.ComponentInfHandle,
  516. pszSubComponentId, c_szDesc,
  517. &nocd.strDesc);
  518. }
  519. return hr;
  520. }
  521. //+---------------------------------------------------------------------------
  522. //
  523. // Function: HrOnPreCommitFileQueue
  524. //
  525. // Purpose: Handles the OC_ABOUT_TO_COMMIT_QUEUE function message.
  526. //
  527. // Arguments:
  528. // pszSubComponentId [in] Name of component.
  529. //
  530. // Returns: S_OK if success, Win32 error otherwise
  531. //
  532. // Author: danielwe 9 Dec 1998
  533. //
  534. // Notes:
  535. //
  536. HRESULT HrOnPreCommitFileQueue(PCWSTR pszSubComponentId)
  537. {
  538. HRESULT hr = S_OK;
  539. NETOCDATA * pnocd;
  540. if (pszSubComponentId)
  541. {
  542. EINSTALL_TYPE eit;
  543. pnocd = PnocdFindComponent(pszSubComponentId);
  544. hr = HrGetInstallType(pszSubComponentId, *pnocd, &eit);
  545. if (SUCCEEDED(hr))
  546. {
  547. pnocd->eit = eit;
  548. if (pnocd->eit == IT_REMOVE)
  549. {
  550. // Always use main install section
  551. hr = HrStartOrStopAnyServices(pnocd->hinfFile,
  552. pszSubComponentId, FALSE);
  553. if (FAILED(hr))
  554. {
  555. // Don't report errors for non-existent services
  556. if (HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) != hr)
  557. {
  558. // Don't bail removal if services couldn't be stopped.
  559. if (!g_ocmData.fErrorReported)
  560. {
  561. // Report an error and continue the removal.
  562. ReportErrorHr(hr,
  563. IDS_OC_STOP_SERVICE_FAILURE,
  564. g_ocmData.hwnd,
  565. pnocd->strDesc.c_str());
  566. }
  567. }
  568. hr = S_OK;
  569. }
  570. // We need to unregister DLLs before they get commited to the
  571. // queue, otherwise we try to unregister a non-existent DLL.
  572. if (SUCCEEDED(hr))
  573. {
  574. tstring strUninstall;
  575. // Get the name of the uninstall section first
  576. hr = HrSetupGetFirstString(pnocd->hinfFile,
  577. pszSubComponentId,
  578. c_szUninstall, &strUninstall);
  579. if (SUCCEEDED(hr))
  580. {
  581. PCWSTR pszInstallSection;
  582. pszInstallSection = strUninstall.c_str();
  583. // Run the INF but only call the unregister function
  584. //
  585. hr = HrSetupInstallFromInfSection(g_ocmData.hwnd,
  586. pnocd->hinfFile,
  587. pszInstallSection,
  588. SPINST_UNREGSVR,
  589. NULL, NULL, 0, NULL,
  590. NULL, NULL, NULL);
  591. }
  592. else
  593. {
  594. // Uninstall may not be present
  595. hr = S_OK;
  596. }
  597. }
  598. }
  599. }
  600. }
  601. TraceError("HrOnPreCommitFileQueue", hr);
  602. return hr;
  603. }
  604. //+---------------------------------------------------------------------------
  605. //
  606. // Function: HrOnQueueFileOps
  607. //
  608. // Purpose: Handles the OC_QUEUE_FILE_OPS function message.
  609. //
  610. // Arguments:
  611. // pszSubComponentId [in] Name of component.
  612. // hfq [in] Handle to file queue struct.
  613. //
  614. // Returns: S_OK if success, Win32 error otherwise
  615. //
  616. // Author: danielwe 23 Feb 1998
  617. //
  618. // Notes:
  619. //
  620. HRESULT HrOnQueueFileOps(PCWSTR pszSubComponentId, HSPFILEQ hfq)
  621. {
  622. HRESULT hr = S_OK;
  623. NETOCDATA * pnocd;
  624. if (pszSubComponentId)
  625. {
  626. EINSTALL_TYPE eit;
  627. pnocd = PnocdFindComponent(pszSubComponentId);
  628. hr = HrGetInstallType(pszSubComponentId, *pnocd, &eit);
  629. if (SUCCEEDED(hr))
  630. {
  631. pnocd->eit = eit;
  632. if ((pnocd->eit == IT_INSTALL) || (pnocd->eit == IT_UPGRADE) ||
  633. (pnocd->eit == IT_REMOVE))
  634. {
  635. BOOL fSuccess = TRUE;
  636. PCWSTR pszInstallSection;
  637. tstring strUninstall;
  638. AssertSz(hfq, "No file queue?");
  639. hr = HrEnsureInfFileIsOpen(pszSubComponentId, *pnocd);
  640. if (SUCCEEDED(hr))
  641. {
  642. if (pnocd->eit == IT_REMOVE)
  643. {
  644. // Get the name of the uninstall section first
  645. hr = HrSetupGetFirstString(pnocd->hinfFile,
  646. pszSubComponentId,
  647. c_szUninstall,
  648. &strUninstall);
  649. if (SUCCEEDED(hr))
  650. {
  651. pszInstallSection = strUninstall.c_str();
  652. }
  653. else
  654. {
  655. if (hr == HRESULT_FROM_SETUPAPI(ERROR_LINE_NOT_FOUND))
  656. {
  657. // Uninstall section is not required.
  658. hr = S_OK;
  659. fSuccess = FALSE;
  660. }
  661. }
  662. }
  663. else
  664. {
  665. pszInstallSection = pszSubComponentId;
  666. }
  667. }
  668. if (SUCCEEDED(hr) && fSuccess)
  669. {
  670. hr = HrCallExternalProc(pnocd, NETOCM_QUEUE_FILES,
  671. (WPARAM)hfq, 0);
  672. }
  673. if (SUCCEEDED(hr))
  674. {
  675. TraceTag(ttidNetOc, "Queueing files for %S...",
  676. pszSubComponentId);
  677. hr = HrSetupInstallFilesFromInfSection(pnocd->hinfFile,
  678. NULL, hfq,
  679. pszInstallSection,
  680. NULL, 0);
  681. }
  682. }
  683. }
  684. }
  685. TraceError("HrOnQueueFileOps", hr);
  686. return hr;
  687. }
  688. //+---------------------------------------------------------------------------
  689. //
  690. // Function: HrOnCompleteInstallation
  691. //
  692. // Purpose: Handles the OC_COMPLETE_INSTALLATION function message.
  693. //
  694. // Arguments:
  695. // pszComponentId [in] Top-level component name (will always be
  696. // "NetOC" or NULL.
  697. // pszSubComponentId [in] Name of component.
  698. //
  699. // Returns: S_OK if success, Win32 error otherwise
  700. //
  701. // Author: danielwe 23 Feb 1998
  702. // omiller 28 March 2000 Added code to move the progress
  703. // bar one tick for every component
  704. // installed or removed.
  705. //
  706. // Notes:
  707. //
  708. HRESULT HrOnCompleteInstallation(PCWSTR pszComponentId,
  709. PCWSTR pszSubComponentId)
  710. {
  711. HRESULT hr = S_OK;
  712. // Make sure they're different. If not, it's the top level item and
  713. // we don't want to do anything
  714. if (pszSubComponentId && lstrcmpiW(pszSubComponentId, pszComponentId))
  715. {
  716. NETOCDATA * pnocd;
  717. pnocd = PnocdFindComponent(pszSubComponentId);
  718. Assert(pnocd);
  719. pnocd->fCleanup = FALSE;
  720. if (pnocd->eit == IT_INSTALL || pnocd->eit == IT_REMOVE ||
  721. pnocd->eit == IT_UPGRADE)
  722. {
  723. pnocd->pszSection = pszSubComponentId;
  724. // Get component description
  725. #if DBG
  726. if (pnocd->eit == IT_INSTALL)
  727. {
  728. TraceTag(ttidNetOc, "Installing network OC %S...",
  729. pszSubComponentId);
  730. }
  731. else if (pnocd->eit == IT_UPGRADE)
  732. {
  733. TraceTag(ttidNetOc, "Upgrading network OC %S...",
  734. pszSubComponentId);
  735. }
  736. else if (pnocd->eit == IT_REMOVE)
  737. {
  738. TraceTag(ttidNetOc, "Removing network OC %S...",
  739. pszSubComponentId);
  740. }
  741. #endif
  742. hr = HrDoOCInstallOrUninstall(pnocd);
  743. if (FAILED(hr) && pnocd->eit == IT_INSTALL)
  744. {
  745. // A failure during install means we have to clean up by doing
  746. // an uninstall now. Report the appropriate error and do the
  747. // remove. Note - Don't report the error if it's ERROR_CANCELLED,
  748. // because they KNOW that they cancelled, and it's not really
  749. // an error.
  750. //
  751. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
  752. {
  753. // Don't report the error a second time if the component
  754. // has already put up error UI (and set this flag)
  755. //
  756. if (!g_ocmData.fErrorReported)
  757. {
  758. ReportErrorHr(hr, UiOcErrorFromHr(hr),
  759. g_ocmData.hwnd,
  760. pnocd->strDesc.c_str());
  761. }
  762. }
  763. g_ocmData.fErrorReported = TRUE;
  764. // Now we're removing
  765. pnocd->eit = IT_REMOVE;
  766. pnocd->fCleanup = TRUE;
  767. pnocd->fFailedToInstall = TRUE;
  768. // eat the error. Haven't we troubled them enough? :(
  769. (VOID) HrDoOCInstallOrUninstall(pnocd);
  770. }
  771. else
  772. {
  773. // Every time a component is installed,upgraded or removed, the progress
  774. // bar is advanced by one tick. For every component that is being
  775. // installed/removed/upgraded the OC manager asked netoc for how many ticks
  776. // that component counts (OC_QUERY_STEP_COUNT). From this information
  777. // the OC manger knows the relationship between tick and progress bar
  778. // advancement.
  779. g_ocmData.sic.HelperRoutines.TickGauge(g_ocmData.sic.HelperRoutines.OcManagerContext);
  780. }
  781. }
  782. }
  783. TraceError("HrOnCompleteInstallation", hr);
  784. return hr;
  785. }
  786. //+---------------------------------------------------------------------------
  787. //
  788. // Function: DwOnQueryStepCount
  789. //
  790. // Purpose: Handles the OC_QUERY_STEP_COUNT message.
  791. // The OC manager is asking us how many ticks a component is worth.
  792. // The number of ticks determines the distance the progress bar gets
  793. // moved. For netoc all components installed/removed are one tick and
  794. // all components that are unchanged are 0 ticks.
  795. //
  796. // Arguments:
  797. // pszSubComponentId [in] Name of component.
  798. //
  799. // Returns: Number of ticks for progress bar to move
  800. //
  801. // Author: omiller 28 March 2000
  802. //
  803. //
  804. DWORD DwOnQueryStepCount(PCWSTR pvSubcomponentId)
  805. {
  806. NETOCDATA * pnocd;
  807. // Get the component
  808. pnocd = PnocdFindComponent(reinterpret_cast<PCWSTR>(pvSubcomponentId));
  809. if( pnocd )
  810. {
  811. // Check if the status of the component has changed.
  812. if (pnocd->eit == IT_INSTALL || pnocd->eit == IT_REMOVE ||
  813. pnocd->eit == IT_UPGRADE)
  814. {
  815. // Status of component has changed. For this component the OC manager
  816. // will move the status bar by one tick.
  817. return 1;
  818. }
  819. }
  820. // The component has not changed. The progress bar will not move for this component.
  821. return 0;
  822. }
  823. //+---------------------------------------------------------------------------
  824. //
  825. // Function: HrOnQueryChangeSelState
  826. //
  827. // Purpose: Handles the OC_QUERY_CHANGE_SEL_STATE function message.
  828. // Enables and disables the next button. If no changes has
  829. // been made to the selections the next button is disabled.
  830. //
  831. // Arguments:
  832. // pszSubComponentId [in] Name of component.
  833. // fSelected [in] TRUE if component was checked "on", FALSE if
  834. // checked "off"
  835. // uiFlags [in] Flags defined in ocmgr.doc
  836. //
  837. // Returns: S_OK if success, Win32 error otherwise
  838. //
  839. // Author: danielwe 23 Feb 1998
  840. //
  841. // Notes:
  842. //
  843. HRESULT HrOnQueryChangeSelState(PCWSTR pszSubComponentId, BOOL fSelected,
  844. UINT uiFlags)
  845. {
  846. HRESULT hr = S_OK;
  847. static int nItemsChanged=0;
  848. NETOCDATA * pnocd;
  849. if (fSelected && pszSubComponentId)
  850. {
  851. pnocd = PnocdFindComponent(pszSubComponentId);
  852. if (pnocd)
  853. {
  854. // "NetOc" may be a subcomponent and we don't want to call this
  855. // for it.
  856. hr = HrCallExternalProc(pnocd, NETOCM_QUERY_CHANGE_SEL_STATE,
  857. (WPARAM)(!!(uiFlags & OCQ_ACTUAL_SELECTION)),
  858. 0);
  859. }
  860. }
  861. TraceError("HrOnQueryChangeSelState", hr);
  862. return hr;
  863. }
  864. //+---------------------------------------------------------------------------
  865. //
  866. // Function: FOnQuerySkipPage
  867. //
  868. // Purpose: Handles the OC_QUERY_SKIP_PAGE function message.
  869. //
  870. // Arguments:
  871. // ocmPage [in] Which page we are asked to possibly skip.
  872. //
  873. // Returns: TRUE if component list page should be skipped, FALSE if not.
  874. //
  875. // Author: danielwe 23 Feb 1998
  876. //
  877. // Notes:
  878. //
  879. BOOL FOnQuerySkipPage(OcManagerPage ocmPage)
  880. {
  881. BOOL fUnattended;
  882. BOOL fGuiSetup;
  883. BOOL fWorkstation;
  884. fUnattended = !!(g_ocmData.sic.SetupData.OperationFlags & SETUPOP_BATCH);
  885. fGuiSetup = !(g_ocmData.sic.SetupData.OperationFlags & SETUPOP_STANDALONE);
  886. fWorkstation = g_ocmData.sic.SetupData.ProductType == PRODUCT_WORKSTATION;
  887. if ((fUnattended || fWorkstation) && fGuiSetup)
  888. {
  889. // We're in GUI mode setup and... we're unattended -OR- this is
  890. // a workstation install
  891. if (ocmPage == OcPageComponentHierarchy)
  892. {
  893. TraceTag(ttidNetOc, "NETOC: Skipping component list page "
  894. "during GUI mode setup...");
  895. TraceTag(ttidNetOc, "fUnattended = %s, fGuiSetup = %s, "
  896. "fWorkstation = %s",
  897. fUnattended ? "yes" : "no",
  898. fGuiSetup ? "yes" : "no",
  899. fWorkstation ? "yes" : "no");
  900. // Make sure we never show the component list page during setup
  901. return TRUE;
  902. }
  903. }
  904. TraceTag(ttidNetOc, "Using component list page.");
  905. TraceTag(ttidNetOc, "fUnattended = %s, fGuiSetup = %s, "
  906. "fWorkstation = %s",
  907. fUnattended ? "yes" : "no",
  908. fGuiSetup ? "yes" : "no",
  909. fWorkstation ? "yes" : "no");
  910. return FALSE;
  911. }
  912. //+---------------------------------------------------------------------------
  913. //
  914. // Function: OnCleanup
  915. //
  916. // Purpose: Handles the OC_CLEANUP function message.
  917. //
  918. // Arguments:
  919. // (none)
  920. //
  921. // Returns: Nothing
  922. //
  923. // Author: danielwe 23 Feb 1998
  924. //
  925. // Notes:
  926. //
  927. VOID OnCleanup()
  928. {
  929. TraceTag(ttidNetOc, "Cleaning up");
  930. if (g_ocmData.hinfAnswerFile)
  931. {
  932. SetupCloseInfFile(g_ocmData.hinfAnswerFile);
  933. TraceTag(ttidNetOc, "Closed answer file");
  934. }
  935. DeleteAllComponents();
  936. }
  937. //+---------------------------------------------------------------------------
  938. //
  939. // Function: HrGetSelectionState
  940. //
  941. // Purpose:
  942. //
  943. // Arguments:
  944. // pszSubComponentId [in] Name of subcomponent
  945. // uStateType [in] In OCManager doc.
  946. //
  947. // Returns: S_OK if component is selected, S_FALSE if not, or Win32 error
  948. // otheriwse
  949. //
  950. // Author: danielwe 17 Dec 1997
  951. //
  952. // Notes:
  953. //
  954. HRESULT HrGetSelectionState(PCWSTR pszSubComponentId, UINT uStateType)
  955. {
  956. HRESULT hr = S_OK;
  957. BOOL fInstall;
  958. fInstall = g_ocmData.sic.HelperRoutines.
  959. QuerySelectionState(g_ocmData.sic.HelperRoutines.OcManagerContext,
  960. pszSubComponentId, uStateType);
  961. if (!fInstall)
  962. {
  963. // Still not sure of the state
  964. hr = HrFromLastWin32Error();
  965. if (SUCCEEDED(hr))
  966. {
  967. // Ok now we know
  968. hr = S_FALSE;
  969. }
  970. }
  971. else
  972. {
  973. hr = S_OK;
  974. }
  975. TraceError("HrGetSelectionState", (S_FALSE == hr) ? S_OK : hr);
  976. return hr;
  977. }
  978. //+---------------------------------------------------------------------------
  979. //
  980. // Function: HrGetInstallType
  981. //
  982. // Purpose: Determines whether the given component is being installed or
  983. // removed and stores the result in the given structure.
  984. //
  985. // Arguments:
  986. // pszSubComponentId [in] Component being queried
  987. // nocd [in, ref] Net OC Data.
  988. // peit [out] Returns the install type
  989. //
  990. // Returns: S_OK if success, Win32 error otherwise
  991. //
  992. // Author: danielwe 16 Dec 1997
  993. //
  994. // Notes: If the function fails, the eit member is unreliable
  995. //
  996. HRESULT HrGetInstallType(PCWSTR pszSubComponentId, NETOCDATA &nocd,
  997. EINSTALL_TYPE *peit)
  998. {
  999. HRESULT hr = S_OK;
  1000. Assert(peit);
  1001. Assert(pszSubComponentId);
  1002. *peit = IT_UNKNOWN;
  1003. if (g_ocmData.sic.SetupData.OperationFlags & SETUPOP_BATCH)
  1004. {
  1005. // In batch mode (upgrade or unattended install), install flag is
  1006. // determined from answer file not from selection state.
  1007. // assume no change
  1008. *peit = IT_NO_CHANGE;
  1009. if (!g_ocmData.hinfAnswerFile)
  1010. {
  1011. // Open the answer file
  1012. hr = HrSetupOpenInfFile(g_ocmData.sic.SetupData.UnattendFile, NULL,
  1013. INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL,
  1014. &g_ocmData.hinfAnswerFile);
  1015. }
  1016. if (SUCCEEDED(hr))
  1017. {
  1018. DWORD dwValue = 0;
  1019. // First query for a special value called "NoDepends" which, if
  1020. // present, means that the DependOnComponents line will be IGNORED
  1021. // for ALL network optional components for this install. This is
  1022. // because NetCfg may invoke the OC Manager to install an optional
  1023. // component and if that component has DependOnComponents, it will
  1024. // turn around and try to instantiate another INetCfg and that
  1025. // will fail because one instance is already running. This case
  1026. // is rare, though.
  1027. //
  1028. hr = HrSetupGetFirstDword(g_ocmData.hinfAnswerFile,
  1029. c_szOcMainSection, c_szNoDepends,
  1030. &dwValue);
  1031. if (SUCCEEDED(hr) && dwValue)
  1032. {
  1033. TraceTag(ttidNetOc, "Found the special 'NoDepends'"
  1034. " keyword in the answer file. DependOnComponents "
  1035. "will be ignored from now on");
  1036. g_ocmData.fNoDepends = TRUE;
  1037. }
  1038. else
  1039. {
  1040. TraceTag(ttidNetOc, "Didn't find the special 'NoDepends'"
  1041. " keyword in the answer file");
  1042. hr = S_OK;
  1043. }
  1044. hr = HrSetupGetFirstDword(g_ocmData.hinfAnswerFile,
  1045. c_szOcMainSection, pszSubComponentId,
  1046. &dwValue);
  1047. if (SUCCEEDED(hr))
  1048. {
  1049. // This component was installed before, so we should
  1050. // return that this component should be checked on
  1051. if (dwValue)
  1052. {
  1053. TraceTag(ttidNetOc, "Optional component %S was "
  1054. "previously installed or is being added thru"
  1055. " unattended install.", pszSubComponentId);
  1056. if (g_ocmData.sic.SetupData.OperationFlags & SETUPOP_NTUPGRADE)
  1057. {
  1058. // If we're upgrading NT, then this optional component
  1059. // does exist but it needs to be upgraded
  1060. *peit = IT_UPGRADE;
  1061. }
  1062. else
  1063. {
  1064. // Otherwise (even if Win3.1 or Win95 upgrade) it's like
  1065. // we're fresh installing the optional component
  1066. *peit = IT_INSTALL;
  1067. }
  1068. }
  1069. else
  1070. {
  1071. // Answer file contains something like WINS=0
  1072. hr = HrGetSelectionState(pszSubComponentId,
  1073. OCSELSTATETYPE_ORIGINAL);
  1074. if (S_OK == hr)
  1075. {
  1076. // Only set state to remove if the component was
  1077. // previously installed.
  1078. //
  1079. *peit = IT_REMOVE;
  1080. }
  1081. }
  1082. }
  1083. }
  1084. hr = S_OK;
  1085. // If the answer file was opened successfully and if the
  1086. // a section was found for the pszSubComponentId, *peit
  1087. // will be either IT_INSTALL, IT_UPGRADE or IT_REMOVE.
  1088. // Nothing needs to be done for any of these *peit values.
  1089. // However, if the answerfile could not be opened or if
  1090. // no section existed in the answer file for the pszSubComponentId
  1091. // *peit will have the value IT_NO_CHANGE. For this scenario,
  1092. // if the corresponding subComponent is currently installed,
  1093. // we should upgrade it. The following if addresses this scenario.
  1094. if (*peit == IT_NO_CHANGE)
  1095. {
  1096. // Still not going to install, because this is an upgrade
  1097. hr = HrGetSelectionState(pszSubComponentId,
  1098. OCSELSTATETYPE_ORIGINAL);
  1099. if (S_OK == hr)
  1100. {
  1101. // If originally selected and not in answer file, this is an
  1102. // upgrade of this component
  1103. *peit = IT_UPGRADE;
  1104. }
  1105. }
  1106. }
  1107. else // This is standalone (post-setup) mode
  1108. {
  1109. hr = HrGetSelectionState(pszSubComponentId, OCSELSTATETYPE_ORIGINAL);
  1110. if (SUCCEEDED(hr))
  1111. {
  1112. HRESULT hrT;
  1113. hrT = HrGetSelectionState(pszSubComponentId,
  1114. OCSELSTATETYPE_CURRENT);
  1115. if (SUCCEEDED(hrT))
  1116. {
  1117. if (hrT != hr)
  1118. {
  1119. // wasn't originally installed so...
  1120. *peit = (hrT == S_OK) ? IT_INSTALL : IT_REMOVE;
  1121. }
  1122. else
  1123. {
  1124. // was originally checked
  1125. *peit = IT_NO_CHANGE;
  1126. }
  1127. }
  1128. else
  1129. {
  1130. hr = hrT;
  1131. }
  1132. }
  1133. }
  1134. AssertSz(FImplies(SUCCEEDED(hr), *peit != IT_UNKNOWN), "Succeeded "
  1135. "but we never found out the install type!");
  1136. if (SUCCEEDED(hr))
  1137. {
  1138. hr = S_OK;
  1139. #if DBG
  1140. const CHAR *szInstallType;
  1141. switch (*peit)
  1142. {
  1143. case IT_NO_CHANGE:
  1144. szInstallType = "no change";
  1145. break;
  1146. case IT_INSTALL:
  1147. szInstallType = "install";
  1148. break;
  1149. case IT_UPGRADE:
  1150. szInstallType = "upgrade";
  1151. break;
  1152. case IT_REMOVE:
  1153. szInstallType = "remove";
  1154. break;
  1155. default:
  1156. AssertSz(FALSE, "Unknown install type!");
  1157. break;
  1158. }
  1159. TraceTag(ttidNetOc, "Install type of %S is %s.", pszSubComponentId,
  1160. szInstallType);
  1161. #endif
  1162. }
  1163. TraceError("HrGetInstallType", hr);
  1164. return hr;
  1165. }
  1166. #if DBG
  1167. PCWSTR SzFromOcUmsg(UINT uMsg)
  1168. {
  1169. switch (uMsg)
  1170. {
  1171. case NETOCM_PRE_INF:
  1172. return L"NETOCM_PRE_INF";
  1173. case NETOCM_POST_INSTALL:
  1174. return L"NETOCM_POST_INSTALL";
  1175. case NETOCM_QUERY_CHANGE_SEL_STATE:
  1176. return L"NETOCM_QUERY_CHANGE_SEL_STATE";
  1177. case NETOCM_QUEUE_FILES:
  1178. return L"NETOCM_QUEUE_FILES";
  1179. default:
  1180. return L"**unknown**";
  1181. }
  1182. }
  1183. #else
  1184. #define SzFromOcUmsg(x) (VOID)0
  1185. #endif
  1186. //+---------------------------------------------------------------------------
  1187. //
  1188. // Function: HrCallExternalProc
  1189. //
  1190. // Purpose: Calls a component's external function as defined by
  1191. // the table at the top of this file. This enables a component
  1192. // to perform additional installation tasks that are not common
  1193. // to other components.
  1194. //
  1195. // Arguments:
  1196. // pnocd [in] Pointer to Net OC Data
  1197. //
  1198. // Returns: S_OK if successful, Win32 error code otherwise.
  1199. //
  1200. // Author: danielwe 5 May 1997
  1201. //
  1202. // Notes:
  1203. //
  1204. HRESULT HrCallExternalProc(PNETOCDATA pnocd, UINT uMsg, WPARAM wParam,
  1205. LPARAM lParam)
  1206. {
  1207. HRESULT hr = S_OK;
  1208. INT iaocep;
  1209. AssertSz(pnocd, "Bad pnocd in HrCallExternalProc");
  1210. for (iaocep = 0; iaocep < c_cocepMap; iaocep++)
  1211. {
  1212. if (!lstrcmpiW(c_aocepMap[iaocep].pszComponentName,
  1213. pnocd->pszComponentId))
  1214. {
  1215. TraceTag(ttidNetOc, "Calling external procedure for %S. uMsg = %S"
  1216. " wParam = %08X,"
  1217. " lParam = %08X", c_aocepMap[iaocep].pszComponentName,
  1218. SzFromOcUmsg(uMsg), wParam, lParam);
  1219. // This component has an external proc. Call it now.
  1220. hr = c_aocepMap[iaocep].pfnHrOcExtProc(pnocd, uMsg,
  1221. wParam, lParam);
  1222. // Don't try to call any other functions
  1223. break;
  1224. }
  1225. }
  1226. TraceError("HrCallExternalProc", hr);
  1227. return hr;
  1228. }
  1229. //+---------------------------------------------------------------------------
  1230. //
  1231. // Function: HrInstallOrRemoveNetCfgComponent
  1232. //
  1233. // Purpose: Utility function for use by optional components that wish to
  1234. // install a NetCfg component from within their own install.
  1235. //
  1236. // Arguments:
  1237. // pnocd [in] Pointer to NETOC data
  1238. // pszComponentId [in] Component ID of NetCfg component to install.
  1239. // This can be found in the netinfid.cpp file.
  1240. // pszManufacturer [in] Manufacturer name of component doing the
  1241. // installing (*this* component). Should always
  1242. // be "Microsoft".
  1243. // pszProduct [in] Short name of product for this component.
  1244. // Should be something like "MacSrv".
  1245. // pszDisplayName [in] Display name of this product. Should be
  1246. // something like "Services For Macintosh".
  1247. // rguid [in] class GUID of the component being installed
  1248. //
  1249. // Returns: S_OK if successful, Win32 error code otherwise.
  1250. //
  1251. // Author: danielwe 6 May 1997
  1252. //
  1253. // Notes:
  1254. //
  1255. HRESULT HrInstallOrRemoveNetCfgComponent(PNETOCDATA pnocd,
  1256. PCWSTR pszComponentId,
  1257. PCWSTR pszManufacturer,
  1258. PCWSTR pszProduct,
  1259. PCWSTR pszDisplayName,
  1260. const GUID& rguid)
  1261. {
  1262. HRESULT hr = S_OK;
  1263. INetCfg * pnc;
  1264. NETWORK_INSTALL_PARAMS nip = {0};
  1265. BOOL fReboot = FALSE;
  1266. nip.dwSetupFlags = FInSystemSetup() ? NSF_PRIMARYINSTALL :
  1267. NSF_POSTSYSINSTALL;
  1268. hr = HrOcGetINetCfg(pnocd, TRUE, &pnc);
  1269. if (SUCCEEDED(hr))
  1270. {
  1271. if (pnocd->eit == IT_INSTALL || pnocd->eit == IT_UPGRADE)
  1272. {
  1273. if (*pszComponentId == L'*')
  1274. {
  1275. // Advance past the *
  1276. pszComponentId++;
  1277. // Install OBO user instead
  1278. TraceTag(ttidNetOc, "Installing %S on behalf of the user",
  1279. pszComponentId);
  1280. hr = HrInstallComponentOboUser(pnc, &nip, rguid,
  1281. pszComponentId, NULL);
  1282. }
  1283. else
  1284. {
  1285. TraceTag(ttidNetOc, "Installing %S on behalf of %S",
  1286. pszComponentId, pnocd->pszSection);
  1287. hr = HrInstallComponentOboSoftware(pnc, &nip,
  1288. rguid,
  1289. pszComponentId,
  1290. pszManufacturer,
  1291. pszProduct,
  1292. pszDisplayName,
  1293. NULL);
  1294. }
  1295. }
  1296. else
  1297. {
  1298. AssertSz(pnocd->eit == IT_REMOVE, "Invalid install action!");
  1299. TraceTag(ttidNetOc, "Removing %S on behalf of %S",
  1300. pszComponentId, pnocd->pszSection);
  1301. hr = HrRemoveComponentOboSoftware(pnc,
  1302. rguid,
  1303. pszComponentId,
  1304. pszManufacturer,
  1305. pszProduct,
  1306. pszDisplayName);
  1307. if (NETCFG_S_REBOOT == hr)
  1308. {
  1309. // Save off the fact that we need to reboot
  1310. fReboot = TRUE;
  1311. }
  1312. // Don't care about the return value here. If we can't remove a
  1313. // dependent component, we can't do anything about it so we should
  1314. // still continue the removal of the OC.
  1315. //
  1316. else if (FAILED(hr))
  1317. {
  1318. TraceTag(ttidError, "Failed to remove %S on behalf of %S!! "
  1319. "Error is 0x%08X",
  1320. pszComponentId, pnocd->pszSection, hr);
  1321. hr = S_OK;
  1322. }
  1323. }
  1324. if (SUCCEEDED(hr))
  1325. {
  1326. hr = pnc->Apply();
  1327. }
  1328. (VOID) HrUninitializeAndReleaseINetCfg(TRUE, pnc, TRUE);
  1329. }
  1330. if (SUCCEEDED(hr) && fReboot)
  1331. {
  1332. // If all went well and we needed to reboot, set hr back.
  1333. hr = NETCFG_S_REBOOT;
  1334. }
  1335. TraceError("HrInstallOrRemoveNetCfgComponent", hr);
  1336. return hr;
  1337. }
  1338. //+---------------------------------------------------------------------------
  1339. //
  1340. // Function: HrInstallOrRemoveServices
  1341. //
  1342. // Purpose: Given an install section, installs (or removes) NT services
  1343. // from the section.
  1344. //
  1345. // Arguments:
  1346. // hinf [in] Handle to INF file.
  1347. // pszSectionName [in] Name of section to use.
  1348. //
  1349. // Returns: S_OK if successful, WIN32 HRESULT if not.
  1350. //
  1351. // Author: danielwe 23 Apr 1997
  1352. //
  1353. // Notes:
  1354. //
  1355. HRESULT HrInstallOrRemoveServices(HINF hinf, PCWSTR pszSectionName)
  1356. {
  1357. static const WCHAR c_szDotServices[] = L"."INFSTR_SUBKEY_SERVICES;
  1358. HRESULT hr = S_OK;
  1359. PWSTR pszServicesSection;
  1360. const DWORD c_cchServices = celems(c_szDotServices);
  1361. DWORD cchName;
  1362. // Look for <szSectionName>.Services to install any NT
  1363. // services if they exist.
  1364. cchName = c_cchServices + lstrlenW(pszSectionName);
  1365. pszServicesSection = new WCHAR [cchName];
  1366. if(pszServicesSection)
  1367. {
  1368. lstrcpyW(pszServicesSection, pszSectionName);
  1369. lstrcatW(pszServicesSection, c_szDotServices);
  1370. if (!SetupInstallServicesFromInfSection(hinf, pszServicesSection, 0))
  1371. {
  1372. hr = HrFromLastWin32Error();
  1373. if (hr == HRESULT_FROM_SETUPAPI(ERROR_SECTION_NOT_FOUND))
  1374. {
  1375. // No problem if section was not found
  1376. hr = S_OK;
  1377. }
  1378. }
  1379. delete [] pszServicesSection;
  1380. }
  1381. else
  1382. {
  1383. hr = E_OUTOFMEMORY;
  1384. }
  1385. TraceError("HrInstallOrRemoveServices", hr);
  1386. return hr;
  1387. }
  1388. //+---------------------------------------------------------------------------
  1389. //
  1390. // Function: HrHandleOCExtensions
  1391. //
  1392. // Purpose: Handles support for all optional component extensions to the
  1393. // INF file format.
  1394. //
  1395. // Arguments:
  1396. // hinfFile [in] handle to INF to process
  1397. // pszInstallSection [in] Install section to process
  1398. //
  1399. // Returns: S_OK if success, setup API HRESULT otherwise
  1400. //
  1401. // Author: danielwe 28 Apr 1997
  1402. //
  1403. // Notes:
  1404. //
  1405. HRESULT HrHandleOCExtensions(HINF hinfFile, PCWSTR pszInstallSection)
  1406. {
  1407. HRESULT hr = S_OK;
  1408. // There's now common code to do this, so simply make a call to that code.
  1409. //
  1410. hr = HrProcessAllINFExtensions(hinfFile, pszInstallSection);
  1411. TraceError("HrHandleOCExtensions", hr);
  1412. return hr;
  1413. }
  1414. //+---------------------------------------------------------------------------
  1415. //
  1416. // Function: HrInstallOrRemoveDependOnComponents
  1417. //
  1418. // Purpose: Handles installation or removal of any NetCfg components that
  1419. // the optional component being installed is dependent upon.
  1420. //
  1421. // Arguments:
  1422. // pnocd [in] Pointer to NETOC data
  1423. // hinf [in] Handle to INF file to process.
  1424. // pszInstallSection [in] Section name to install from.
  1425. // pszDisplayName [in] Display name of component being installed.
  1426. //
  1427. // Returns: S_OK if success, setup API HRESULT otherwise
  1428. //
  1429. // Author: danielwe 17 Jun 1997
  1430. //
  1431. // Notes:
  1432. //
  1433. HRESULT HrInstallOrRemoveDependOnComponents(PNETOCDATA pnocd,
  1434. HINF hinf,
  1435. PCWSTR pszInstallSection,
  1436. PCWSTR pszDisplayName)
  1437. {
  1438. HRESULT hr = S_OK;
  1439. PWSTR mszDepends;
  1440. tstring strManufacturer;
  1441. PCWSTR pszManufacturer;
  1442. Assert(pnocd);
  1443. hr = HrSetupGetFirstString(hinf, c_szVersionSection, c_szProvider,
  1444. &strManufacturer);
  1445. if (S_OK == hr)
  1446. {
  1447. pszManufacturer = strManufacturer.c_str();
  1448. }
  1449. else
  1450. {
  1451. // No provider found, use default
  1452. hr = S_OK;
  1453. pszManufacturer = c_szDefManu;
  1454. }
  1455. hr = HrSetupGetFirstMultiSzFieldWithAlloc(hinf, pszInstallSection,
  1456. c_szDependOnComp,
  1457. &mszDepends);
  1458. if (S_OK == hr)
  1459. {
  1460. PCWSTR pszComponent;
  1461. pszComponent = mszDepends;
  1462. while (SUCCEEDED(hr) && *pszComponent)
  1463. {
  1464. const GUID * pguidClass;
  1465. PCWSTR pszComponentActual = pszComponent;
  1466. if (*pszComponent == L'*')
  1467. {
  1468. pszComponentActual = pszComponent + 1;
  1469. }
  1470. if (FClassGuidFromComponentId(pszComponentActual, &pguidClass))
  1471. {
  1472. hr = HrInstallOrRemoveNetCfgComponent(pnocd,
  1473. pszComponent,
  1474. pszManufacturer,
  1475. pszInstallSection,
  1476. pszDisplayName,
  1477. *pguidClass);
  1478. }
  1479. #ifdef DBG
  1480. else
  1481. {
  1482. TraceTag(ttidNetOc, "Error in INF, Component %S not found!",
  1483. pszComponent);
  1484. }
  1485. #endif
  1486. pszComponent += lstrlenW(pszComponent) + 1;
  1487. }
  1488. delete mszDepends;
  1489. }
  1490. else if (hr == HRESULT_FROM_SETUPAPI(ERROR_LINE_NOT_FOUND))
  1491. {
  1492. // Section is not required.
  1493. hr = S_OK;
  1494. }
  1495. TraceError("HrInstallOrRemoveDependOnComponents", hr);
  1496. return hr;
  1497. }
  1498. //+---------------------------------------------------------------------------
  1499. //
  1500. // Function: HrRunInfSection
  1501. //
  1502. // Purpose: Runs the given INF section, but doesn't copy files
  1503. //
  1504. // Arguments:
  1505. // hinf [in] Handle to INF to run
  1506. // pnocd [in] NetOC Data
  1507. // pszInstallSection [in] Install section to run
  1508. // dwFlags [in] Install flags (SPINST_*)
  1509. //
  1510. // Returns: S_OK if success, SetupAPI or Win32 error otherwise
  1511. //
  1512. // Author: danielwe 16 Dec 1997
  1513. //
  1514. // Notes:
  1515. //
  1516. HRESULT HrRunInfSection(HINF hinf, PNETOCDATA pnocd,
  1517. PCWSTR pszInstallSection, DWORD dwFlags)
  1518. {
  1519. HRESULT hr;
  1520. // Now we run all sections but CopyFiles and UnregisterDlls because we
  1521. // did that earlier
  1522. //
  1523. hr = HrSetupInstallFromInfSection(g_ocmData.hwnd, hinf,
  1524. pszInstallSection,
  1525. dwFlags & ~SPINST_FILES & ~SPINST_UNREGSVR,
  1526. NULL, NULL, 0, NULL,
  1527. NULL, NULL, NULL);
  1528. TraceError("HrRunInfSection", hr);
  1529. return hr;
  1530. }
  1531. //+---------------------------------------------------------------------------
  1532. //
  1533. // Function: HrStartOrStopAnyServices
  1534. //
  1535. // Purpose: Starts or stops any services the INF has requested via the
  1536. // Services value in the main install section.
  1537. //
  1538. // Arguments:
  1539. // hinf [in] handle to INF to process
  1540. // pszSection [in] Install section to process
  1541. // fStart [in] TRUE to start, FALSE to stop.
  1542. //
  1543. // Returns: S_OK or Win32 error code.
  1544. //
  1545. // Author: danielwe 17 Jun 1997
  1546. //
  1547. // Notes: Services are stopped in the same order they are started.
  1548. //
  1549. HRESULT HrStartOrStopAnyServices(HINF hinf, PCWSTR pszSection, BOOL fStart)
  1550. {
  1551. HRESULT hr;
  1552. PWSTR mszServices;
  1553. hr = HrSetupGetFirstMultiSzFieldWithAlloc(hinf, pszSection,
  1554. c_szServices, &mszServices);
  1555. if (SUCCEEDED(hr))
  1556. {
  1557. // Build an array of pointers to strings that point at the
  1558. // strings of the multi-sz. This is needed because the API to
  1559. // stop and start services takes an array of pointers to strings.
  1560. //
  1561. UINT cServices;
  1562. PCWSTR* apszServices;
  1563. hr = HrCreateArrayOfStringPointersIntoMultiSz(
  1564. mszServices,
  1565. &cServices,
  1566. &apszServices);
  1567. if (SUCCEEDED(hr))
  1568. {
  1569. CServiceManager scm;
  1570. if (fStart)
  1571. {
  1572. hr = scm.HrStartServicesAndWait(cServices, apszServices);
  1573. }
  1574. else
  1575. {
  1576. hr = scm.HrStopServicesAndWait(cServices, apszServices);
  1577. }
  1578. MemFree (apszServices);
  1579. }
  1580. delete mszServices;
  1581. }
  1582. else if (hr == HRESULT_FROM_SETUPAPI(ERROR_LINE_NOT_FOUND))
  1583. {
  1584. // this is a totally optional thing
  1585. hr = S_OK;
  1586. }
  1587. TraceError("HrStartOrStopAnyServices", hr);
  1588. return hr;
  1589. }
  1590. //+---------------------------------------------------------------------------
  1591. //
  1592. // Function: HrDoActualInstallOrUninstall
  1593. //
  1594. // Purpose: Handles main portion of install or uninstall for an optional
  1595. // network component.
  1596. //
  1597. // Arguments:
  1598. // hinf [in] handle to INF to process
  1599. // pnocd [in] Pointer to NETOC data (hwnd, poc)
  1600. // pszInstallSection [in] Install section to process
  1601. //
  1602. // Returns: S_OK if success, setup API HRESULT otherwise
  1603. //
  1604. // Author: danielwe 17 Jun 1997
  1605. //
  1606. // Notes:
  1607. //
  1608. HRESULT HrDoActualInstallOrUninstall(HINF hinf,
  1609. PNETOCDATA pnocd,
  1610. PCWSTR pszInstallSection)
  1611. {
  1612. HRESULT hr = S_OK;
  1613. BOOL fReboot = FALSE;
  1614. AssertSz(pszInstallSection, "Install section is NULL!");
  1615. AssertSz(pnocd, "Bad pnocd in HrDoActualInstallOrUninstall");
  1616. //AssertSz(g_ocmData.hwnd, "Bad g_ocmData.hwnd in HrDoActualInstallOrUninstall");
  1617. if (pnocd->eit == IT_REMOVE)
  1618. {
  1619. hr = HrCallExternalProc(pnocd, NETOCM_PRE_INF, 0, 0);
  1620. if (SUCCEEDED(hr))
  1621. {
  1622. // Now process the component's INF file
  1623. //
  1624. TraceTag(ttidNetOc, "Running INF section %S", pszInstallSection);
  1625. hr = HrRunInfSection(hinf, pnocd, pszInstallSection, SPINST_ALL);
  1626. }
  1627. }
  1628. else
  1629. {
  1630. hr = HrCallExternalProc(pnocd, NETOCM_PRE_INF, 0, 0);
  1631. if (SUCCEEDED(hr))
  1632. {
  1633. // Process the component's INF file
  1634. //
  1635. TraceTag(ttidNetOc, "Running INF section %S", pszInstallSection);
  1636. hr = HrRunInfSection(hinf, pnocd, pszInstallSection,
  1637. SPINST_ALL & ~SPINST_REGSVR);
  1638. }
  1639. }
  1640. if (SUCCEEDED(hr))
  1641. {
  1642. // Must install or remove services first
  1643. TraceTag(ttidNetOc, "Running HrInstallOrRemoveServices for %S",
  1644. pszInstallSection);
  1645. hr = HrInstallOrRemoveServices(hinf, pszInstallSection);
  1646. if (SUCCEEDED(hr))
  1647. {
  1648. // Bug #383239: Wait till services are installed before
  1649. // running the RegisterDlls section
  1650. //
  1651. hr = HrRunInfSection(hinf, pnocd, pszInstallSection,
  1652. SPINST_REGSVR);
  1653. }
  1654. if (SUCCEEDED(hr))
  1655. {
  1656. TraceTag(ttidNetOc, "Running HrHandleOCExtensions for %S",
  1657. pszInstallSection);
  1658. hr = HrHandleOCExtensions(hinf, pszInstallSection);
  1659. if (SUCCEEDED(hr))
  1660. {
  1661. if (!g_ocmData.fNoDepends)
  1662. {
  1663. // Now install or remove any NetCfg components that this
  1664. // component requires
  1665. TraceTag(ttidNetOc, "Running "
  1666. "HrInstallOrRemoveDependOnComponents for %S",
  1667. pnocd->pszSection);
  1668. hr = HrInstallOrRemoveDependOnComponents(pnocd,
  1669. hinf,
  1670. pnocd->pszSection,
  1671. pnocd->strDesc.c_str());
  1672. if (NETCFG_S_REBOOT == hr)
  1673. {
  1674. fReboot = TRUE;
  1675. }
  1676. }
  1677. else
  1678. {
  1679. AssertSz(g_ocmData.sic.SetupData.OperationFlags &
  1680. SETUPOP_BATCH, "How can NoDepends be set??");
  1681. TraceTag(ttidNetOc, "NOT Running "
  1682. "HrInstallOrRemoveDependOnComponents for %S "
  1683. "because NoDepends was set in the answer file.",
  1684. pnocd->pszSection);
  1685. }
  1686. if (SUCCEEDED(hr))
  1687. {
  1688. // Now call any external installation support...
  1689. hr = HrCallExternalProc(pnocd, NETOCM_POST_INSTALL,
  1690. 0, 0);
  1691. if (SUCCEEDED(hr))
  1692. {
  1693. if (pnocd->eit == IT_INSTALL && !FInSystemSetup())
  1694. {
  1695. // ... and finally, start any services they've
  1696. // requested
  1697. hr = HrStartOrStopAnyServices(hinf,
  1698. pszInstallSection, TRUE);
  1699. {
  1700. if (FAILED(hr))
  1701. {
  1702. UINT ids = IDS_OC_START_SERVICE_FAILURE;
  1703. if (HRESULT_FROM_WIN32(ERROR_TIMEOUT) == hr)
  1704. {
  1705. ids = IDS_OC_START_TOOK_TOO_LONG;
  1706. }
  1707. // Don't bail installation if service
  1708. // couldn't be started. Report an error
  1709. // and continue the install.
  1710. ReportErrorHr(hr, ids, g_ocmData.hwnd,
  1711. pnocd->strDesc.c_str());
  1712. hr = S_OK;
  1713. }
  1714. }
  1715. }
  1716. }
  1717. }
  1718. }
  1719. }
  1720. }
  1721. if ((S_OK == hr) && (fReboot))
  1722. {
  1723. hr = NETCFG_S_REBOOT;
  1724. }
  1725. TraceError("HrDoActualInstallOrUninstall", hr);
  1726. return hr;
  1727. }
  1728. //+---------------------------------------------------------------------------
  1729. //
  1730. // Function: HrOCInstallOrUninstallFromINF
  1731. //
  1732. // Purpose: Handles installation of an Optional Component from its INF
  1733. // file.
  1734. //
  1735. // Arguments:
  1736. // pnocd [in] Pointer to NETOC data.
  1737. //
  1738. // Returns: S_OK if success, setup API HRESULT otherwise
  1739. //
  1740. // Author: danielwe 6 May 1997
  1741. //
  1742. // Notes:
  1743. //
  1744. HRESULT HrOCInstallOrUninstallFromINF(PNETOCDATA pnocd)
  1745. {
  1746. HRESULT hr = S_OK;
  1747. tstring strUninstall;
  1748. PCWSTR pszInstallSection = NULL;
  1749. BOOL fSuccess = TRUE;
  1750. Assert(pnocd);
  1751. if (pnocd->eit == IT_REMOVE)
  1752. {
  1753. // Get the name of the uninstall section first
  1754. hr = HrSetupGetFirstString(pnocd->hinfFile, pnocd->pszSection,
  1755. c_szUninstall, &strUninstall);
  1756. if (SUCCEEDED(hr))
  1757. {
  1758. pszInstallSection = strUninstall.c_str();
  1759. }
  1760. else
  1761. {
  1762. if (hr == HRESULT_FROM_SETUPAPI(ERROR_LINE_NOT_FOUND))
  1763. {
  1764. // Uninstall section is not required.
  1765. hr = S_OK;
  1766. fSuccess = FALSE;
  1767. }
  1768. }
  1769. }
  1770. else
  1771. {
  1772. pszInstallSection = pnocd->pszSection;
  1773. }
  1774. if (fSuccess)
  1775. {
  1776. hr = HrDoActualInstallOrUninstall(pnocd->hinfFile,
  1777. pnocd,
  1778. pszInstallSection);
  1779. }
  1780. TraceError("HrOCInstallOrUninstallFromINF", hr);
  1781. return hr;
  1782. }
  1783. //+---------------------------------------------------------------------------
  1784. //
  1785. // Function: HrDoOCInstallOrUninstall
  1786. //
  1787. // Purpose: Installs or removes an optional networking component.
  1788. //
  1789. // Arguments:
  1790. // pnocd [in] Pointer to NETOC data
  1791. //
  1792. // Returns: S_OK for success, SetupAPI HRESULT error code otherwise.
  1793. //
  1794. // Author: danielwe 6 May 1997
  1795. //
  1796. // Notes:
  1797. //
  1798. HRESULT HrDoOCInstallOrUninstall(PNETOCDATA pnocd)
  1799. {
  1800. HRESULT hr = S_OK;
  1801. hr = HrOCInstallOrUninstallFromINF(pnocd);
  1802. TraceError("HrDoOCInstallOrUninstall", hr);
  1803. return hr;
  1804. }
  1805. //+---------------------------------------------------------------------------
  1806. //
  1807. // Function: UiOcErrorFromHr
  1808. //
  1809. // Purpose: Maps a Win32 error code into an understandable error string.
  1810. //
  1811. // Arguments:
  1812. // hr [in] HRESULT to convert
  1813. //
  1814. // Returns: The resource ID of the string.
  1815. //
  1816. // Author: danielwe 9 Feb 1998
  1817. //
  1818. // Notes:
  1819. //
  1820. UINT UiOcErrorFromHr(HRESULT hr)
  1821. {
  1822. UINT uid;
  1823. AssertSz(FAILED(hr), "Don't call UiOcErrorFromHr if Hr didn't fail!");
  1824. switch (hr)
  1825. {
  1826. case HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND):
  1827. case HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND):
  1828. uid = IDS_OC_REGISTER_PROBLEM;
  1829. break;
  1830. case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
  1831. uid = IDS_OC_FILE_PROBLEM;
  1832. break;
  1833. case NETCFG_E_NEED_REBOOT:
  1834. case HRESULT_FROM_WIN32(ERROR_SERVICE_MARKED_FOR_DELETE):
  1835. uid = IDS_OC_NEEDS_REBOOT;
  1836. break;
  1837. case HRESULT_FROM_WIN32(ERROR_CANCELLED):
  1838. uid = IDS_OC_USER_CANCELLED;
  1839. break;
  1840. case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
  1841. uid = IDS_OC_NO_PERMISSION;
  1842. break;
  1843. default:
  1844. uid = IDS_OC_ERROR;
  1845. break;
  1846. }
  1847. return uid;
  1848. }
  1849. //+---------------------------------------------------------------------------
  1850. //
  1851. // Function: SzErrorToString
  1852. //
  1853. // Purpose: Converts an HRESULT into a displayable string.
  1854. //
  1855. // Arguments:
  1856. // hr [in] HRESULT value to convert.
  1857. //
  1858. // Returns: LPWSTR a dynamically allocated string to be freed with LocalFree
  1859. //
  1860. // Author: mbend 3 Apr 2000
  1861. //
  1862. // Notes: Attempts to use FormatMessage to convert the HRESULT to a string.
  1863. // If that fails, just convert the HRESULT to a hex string.
  1864. //
  1865. LPWSTR SzErrorToString(HRESULT hr)
  1866. {
  1867. LPWSTR pszErrorText = NULL;
  1868. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1869. FORMAT_MESSAGE_FROM_SYSTEM,
  1870. NULL, hr,
  1871. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  1872. (WCHAR*)&pszErrorText, 0, NULL);
  1873. if (pszErrorText)
  1874. {
  1875. // Strip off newline characters.
  1876. //
  1877. LPWSTR pchText = pszErrorText;
  1878. while (*pchText && (*pchText != L'\r') && (*pchText != L'\n'))
  1879. {
  1880. pchText++;
  1881. }
  1882. *pchText = 0;
  1883. return pszErrorText;
  1884. }
  1885. // We did't find anything so format the hex value
  1886. WCHAR szBuf[128];
  1887. wsprintfW(szBuf, L"0x%08x", hr);
  1888. WCHAR * szRet = reinterpret_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, lstrlenW(szBuf) * sizeof(WCHAR)));
  1889. if(szRet)
  1890. {
  1891. lstrcpyW(szRet, szBuf);
  1892. }
  1893. return szRet;
  1894. }
  1895. //+---------------------------------------------------------------------------
  1896. //
  1897. // Function: ReportErrorHr
  1898. //
  1899. // Purpose: Pops up a message box related to error passed in.
  1900. //
  1901. // Arguments:
  1902. // hr [in] HRESULT value to report.
  1903. // ids [in] Resource ID of string to display.
  1904. // hwnd [in] HWND of parent window.
  1905. // pszDesc [in] Description of component involved.
  1906. //
  1907. // Returns: Nothing.
  1908. //
  1909. // Author: danielwe 28 Apr 1997
  1910. //
  1911. // Notes: The string resource in ids must contain a %1 and %2 where %1
  1912. // is the name of the component, and %2 is the error code.
  1913. //
  1914. VOID ReportErrorHr(HRESULT hr, INT ids, HWND hwnd, PCWSTR pszDesc)
  1915. {
  1916. BOOL bCleanup = TRUE;
  1917. WCHAR * szText = SzErrorToString(hr);
  1918. if(!szText)
  1919. {
  1920. szText = L"Out of memory!";
  1921. bCleanup = FALSE;
  1922. }
  1923. NcMsgBox(hwnd, IDS_OC_CAPTION, ids, MB_ICONSTOP | MB_OK, pszDesc, szText);
  1924. if(bCleanup)
  1925. {
  1926. LocalFree(szText);
  1927. }
  1928. }
  1929. //+---------------------------------------------------------------------------
  1930. //
  1931. // Function: HrVerifyStaticIPPresent
  1932. //
  1933. // Purpose: Verify that at least one adapter has a static IP address.
  1934. // Both DHCP Server and WINS need to know this, as they need
  1935. // to bring up UI if this isn't the case. This function is, of
  1936. // course, a complete hack until we can get a properties
  1937. // interface hanging off of the components.
  1938. //
  1939. // Arguments:
  1940. // pnc [in] INetCfg interface to use
  1941. //
  1942. // Returns: S_OK, or valid Win32 error code.
  1943. //
  1944. // Author: jeffspr 19 Jun 1997
  1945. //
  1946. // Notes:
  1947. //
  1948. HRESULT HrVerifyStaticIPPresent(INetCfg *pnc)
  1949. {
  1950. HRESULT hr = S_OK;
  1951. HKEY hkeyInterfaces = NULL;
  1952. HKEY hkeyEnum = NULL;
  1953. INetCfgComponent* pncc = NULL;
  1954. HKEY hkeyTcpipAdapter = NULL;
  1955. PWSTR pszBindName = NULL;
  1956. Assert(pnc);
  1957. // Iterate the adapters in the system looking for non-virtual adapters
  1958. //
  1959. CIterNetCfgComponent nccIter(pnc, &GUID_DEVCLASS_NET);
  1960. while (S_OK == (hr = nccIter.HrNext(&pncc)))
  1961. {
  1962. DWORD dwFlags = 0;
  1963. // Get the adapter characteristics
  1964. //
  1965. hr = pncc->GetCharacteristics(&dwFlags);
  1966. if (SUCCEEDED(hr))
  1967. {
  1968. DWORD dwEnableValue = 0;
  1969. // If we're NOT a virtual adapter, THEN test for
  1970. // tcp/ip static IP
  1971. if (!(dwFlags & NCF_VIRTUAL))
  1972. {
  1973. WCHAR szRegPath[MAX_PATH+1];
  1974. // Get the component bind name
  1975. //
  1976. hr = pncc->GetBindName(&pszBindName);
  1977. if (FAILED(hr))
  1978. {
  1979. TraceTag(ttidError,
  1980. "Error getting bind name from component "
  1981. "in HrVerifyStaticIPPresent()");
  1982. goto Exit;
  1983. }
  1984. // Build the path to the TCP/IP instance key for his adapter
  1985. //
  1986. wsprintfW(szRegPath, L"%s\\%s",
  1987. c_szTcpipInterfacesPath, pszBindName);
  1988. // Open the key for this adapter.
  1989. //
  1990. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1991. szRegPath,
  1992. KEY_READ, &hkeyTcpipAdapter);
  1993. if (SUCCEEDED(hr))
  1994. {
  1995. // Read the EnableDHCP value.
  1996. //
  1997. hr = HrRegQueryDword(hkeyTcpipAdapter, c_szEnableDHCP,
  1998. &dwEnableValue);
  1999. if (FAILED(hr))
  2000. {
  2001. TraceTag(ttidError,
  2002. "Error reading the EnableDHCP value from "
  2003. "the enumerated key in "
  2004. "HrVerifyStaticIPPresent()");
  2005. goto Exit;
  2006. }
  2007. // If we've found a non-DHCP-enabled adapter.
  2008. //
  2009. if (0 == dwEnableValue)
  2010. {
  2011. // We have our man. Take a hike, and return S_OK,
  2012. // meaning that we had at least one good adapter.
  2013. // The enumerated key will get cleaned up at exit.
  2014. hr = S_OK;
  2015. goto Exit;
  2016. }
  2017. RegSafeCloseKey(hkeyTcpipAdapter);
  2018. hkeyTcpipAdapter = NULL;
  2019. }
  2020. else
  2021. {
  2022. // If the key wasn't found, we just don't have a
  2023. // binding to TCP/IP. This is fine, but we don't need
  2024. // to continue plodding down this path.
  2025. //
  2026. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  2027. {
  2028. hr = S_OK;
  2029. }
  2030. else
  2031. {
  2032. TraceTag(ttidError,
  2033. "Error opening adapter key in "
  2034. "HrVerifyStaticIPPresent()");
  2035. goto Exit;
  2036. }
  2037. }
  2038. }
  2039. }
  2040. if (pszBindName)
  2041. {
  2042. CoTaskMemFree(pszBindName);
  2043. pszBindName = NULL;
  2044. }
  2045. ReleaseObj (pncc);
  2046. pncc = NULL;
  2047. }
  2048. // If we haven't found an adapter, we'll have an S_FALSE returned from
  2049. // the HrNext. This is fine, because if we haven't found an adapter
  2050. // with a static IP address, this is exactly what we want to return.
  2051. // If we'd found one, we'd have set hr = S_OK, and dropped out of the
  2052. // loop.
  2053. Exit:
  2054. RegSafeCloseKey(hkeyTcpipAdapter);
  2055. if (pszBindName)
  2056. {
  2057. CoTaskMemFree(pszBindName);
  2058. pszBindName = NULL;
  2059. }
  2060. ReleaseObj(pncc);
  2061. TraceError("HrVerifyStaticIPPresent()", (hr == S_FALSE) ? S_OK : hr);
  2062. return hr;
  2063. }
  2064. //+---------------------------------------------------------------------------
  2065. //
  2066. // Function: HrCountConnections
  2067. //
  2068. // Purpose: Determines the number of LAN connections present and returns
  2069. // a pointer to an INetConnection object if only one connection
  2070. // is present.
  2071. //
  2072. // Arguments:
  2073. // ppconn [out] If only one connection is present, this returns it
  2074. //
  2075. // Returns: S_OK if no errors were found and at least one connection
  2076. // exists, S_FALSE if no connections exist, or a Win32 or OLE
  2077. // error code otherwise
  2078. //
  2079. // Author: danielwe 28 Jul 1998
  2080. //
  2081. // Notes:
  2082. //
  2083. HRESULT HrCountConnections(INetConnection **ppconn)
  2084. {
  2085. HRESULT hr = S_OK;
  2086. INetConnectionManager * pconMan;
  2087. Assert(ppconn);
  2088. *ppconn = NULL;
  2089. // Iterate all LAN connections
  2090. //
  2091. hr = HrCreateInstance(
  2092. CLSID_LanConnectionManager,
  2093. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  2094. &pconMan);
  2095. TraceHr(ttidError, FAL, hr, FALSE, "HrCreateInstance");
  2096. if (SUCCEEDED(hr))
  2097. {
  2098. CIterNetCon ncIter(pconMan, NCME_DEFAULT);
  2099. INetConnection * pconn = NULL;
  2100. INetConnection * pconnCur = NULL;
  2101. INT cconn = 0;
  2102. while (SUCCEEDED(hr) && (S_OK == (ncIter.HrNext(&pconn))))
  2103. {
  2104. ReleaseObj(pconnCur);
  2105. cconn++;
  2106. AddRefObj(pconnCur = pconn);
  2107. ReleaseObj(pconn);
  2108. }
  2109. if (cconn > 1)
  2110. {
  2111. // if more than one connection found, release last one we had
  2112. ReleaseObj(pconnCur);
  2113. hr = S_OK;
  2114. }
  2115. else if (cconn == 0)
  2116. {
  2117. ReleaseObj(pconnCur);
  2118. hr = S_FALSE;
  2119. }
  2120. else // conn == 1
  2121. {
  2122. *ppconn = pconnCur;
  2123. hr = S_OK;
  2124. }
  2125. ReleaseObj(pconMan);
  2126. }
  2127. TraceError("HrCountConnections", (hr == S_FALSE) ? S_OK : hr);
  2128. return hr;
  2129. }
  2130. //+---------------------------------------------------------------------------
  2131. //
  2132. // Function: HrHandleStaticIpDependency
  2133. //
  2134. // Purpose: Handles the need that some components have that requires
  2135. // at least one adapter using a static IP address before they
  2136. // can be installed properly.
  2137. //
  2138. // Arguments:
  2139. // pnocd [in] Pointer to NETOC data
  2140. //
  2141. // Returns: S_OK if success, Win32 HRESULT error code otherwise.
  2142. //
  2143. // Author: danielwe 19 Jun 1997
  2144. //
  2145. // Notes:
  2146. //
  2147. HRESULT HrHandleStaticIpDependency(PNETOCDATA pnocd)
  2148. {
  2149. HRESULT hr = S_OK;
  2150. static BOOL fFirstInvocation = TRUE;
  2151. // bug 25841. This function is called during installation of DNS, DHCP,
  2152. // and WINS. If all three are being installed togetther then this ends
  2153. // up showing the same error message thrice when one would suffice.
  2154. if( fFirstInvocation )
  2155. {
  2156. fFirstInvocation = FALSE;
  2157. }
  2158. else
  2159. {
  2160. return hr;
  2161. }
  2162. // Can't do anything about this if not in "attended" setup mode
  2163. if (!(g_ocmData.sic.SetupData.OperationFlags & SETUPOP_BATCH))
  2164. {
  2165. BOOL fChangesApplied = FALSE;
  2166. INetCfg * pnc = NULL;
  2167. Assert(pnocd);
  2168. //Assert(g_ocmData.hwnd);
  2169. hr = HrOcGetINetCfg(pnocd, FALSE, &pnc);
  2170. if (SUCCEEDED(hr))
  2171. {
  2172. hr = HrVerifyStaticIPPresent(pnc);
  2173. if (hr == S_FALSE)
  2174. {
  2175. INetConnectionCommonUi * pcommUi;
  2176. INetConnection * pconn = NULL;
  2177. hr = HrCountConnections(&pconn);
  2178. if (S_OK == hr)
  2179. {
  2180. // One or more connections found
  2181. // Display message to user indicating that she has to
  2182. // configure at least one adapter with a static IP address
  2183. // before we can continue.
  2184. NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION,
  2185. IDS_OC_NEED_STATIC_IP,
  2186. MB_ICONINFORMATION | MB_OK,
  2187. pnocd->strDesc.c_str());
  2188. hr = CoCreateInstance(CLSID_ConnectionCommonUi, NULL,
  2189. CLSCTX_INPROC | CLSCTX_NO_CODE_DOWNLOAD,
  2190. IID_INetConnectionCommonUi,
  2191. reinterpret_cast<LPVOID *>(&pcommUi));
  2192. TraceHr(ttidError, FAL, hr, FALSE, "CoCreateInstance");
  2193. if (SUCCEEDED(hr))
  2194. {
  2195. if (pconn)
  2196. {
  2197. // Exactly one connection found
  2198. hr = pcommUi->ShowConnectionProperties(g_ocmData.hwnd,
  2199. pconn);
  2200. if (S_OK == hr)
  2201. {
  2202. fChangesApplied = TRUE;
  2203. }
  2204. else if (FAILED(hr))
  2205. {
  2206. // Eat the error since we can't do anything about it
  2207. // anyway.
  2208. TraceError("HrHandleStaticIpDependency - "
  2209. "ShowConnectionProperties", hr);
  2210. hr = S_OK;
  2211. }
  2212. }
  2213. else
  2214. {
  2215. // More than one connection found
  2216. if (SUCCEEDED(hr))
  2217. {
  2218. NETCON_CHOOSECONN chooseCon = {0};
  2219. chooseCon.lStructSize = sizeof(NETCON_CHOOSECONN);
  2220. chooseCon.hwndParent = g_ocmData.hwnd;
  2221. chooseCon.dwTypeMask = NCCHT_LAN;
  2222. chooseCon.dwFlags = NCCHF_DISABLENEW;
  2223. hr = pcommUi->ChooseConnection(&chooseCon, NULL);
  2224. if (SUCCEEDED(hr))
  2225. {
  2226. fChangesApplied = TRUE;
  2227. }
  2228. else
  2229. {
  2230. // Eat the error since we can't do anything about it
  2231. // anyway.
  2232. TraceError("HrHandleStaticIpDependency - "
  2233. "ChooseConnection", hr);
  2234. hr = S_OK;
  2235. }
  2236. }
  2237. }
  2238. ReleaseObj(pcommUi);
  2239. }
  2240. ReleaseObj(pconn);
  2241. if (SUCCEEDED(hr))
  2242. {
  2243. // Don't bother checking again if they never
  2244. // made any changes
  2245. if (!fChangesApplied ||
  2246. (S_FALSE == (hr = HrVerifyStaticIPPresent(pnc))))
  2247. {
  2248. // Geez, still no static IP address available.
  2249. // Put up another message box scolding the user for
  2250. // not following directions.
  2251. NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION,
  2252. IDS_OC_STILL_NO_STATIC_IP,
  2253. MB_ICONSTOP | MB_OK,
  2254. pnocd->strDesc.c_str());
  2255. hr = S_OK;
  2256. }
  2257. }
  2258. }
  2259. }
  2260. hr = HrUninitializeAndReleaseINetCfg(TRUE, pnc, FALSE);
  2261. }
  2262. }
  2263. else
  2264. {
  2265. TraceTag(ttidNetOc, "Not handling static IP dependency for %S "
  2266. "because we're in unattended mode", pnocd->strDesc.c_str());
  2267. }
  2268. TraceError("HrHandleStaticIpDependency", hr);
  2269. return hr;
  2270. }
  2271. //+---------------------------------------------------------------------------
  2272. //
  2273. // Function: HrOcGetINetCfg
  2274. //
  2275. // Purpose: Obtains an INetCfg to work with
  2276. //
  2277. // Arguments:
  2278. // pnocd [in] OC Data
  2279. // fWriteLock [in] TRUE if write lock should be acquired, FALSE if
  2280. // not.
  2281. // ppnc [out] Returns INetCfg pointer
  2282. //
  2283. // Returns: S_OK if success, OLE or Win32 error if failed. ERROR_CANCELLED
  2284. // is returned if INetCfg is locked and the users cancels.
  2285. //
  2286. // Author: danielwe 18 Dec 1997
  2287. //
  2288. // Notes:
  2289. //
  2290. HRESULT HrOcGetINetCfg(PNETOCDATA pnocd, BOOL fWriteLock, INetCfg **ppnc)
  2291. {
  2292. HRESULT hr = S_OK;
  2293. PWSTR pszDesc;
  2294. BOOL fInitCom = TRUE;
  2295. Assert(ppnc);
  2296. *ppnc = NULL;
  2297. top:
  2298. AssertSz(!*ppnc, "Can't have valid INetCfg here!");
  2299. hr = HrCreateAndInitializeINetCfg(&fInitCom, ppnc, fWriteLock, 0,
  2300. SzLoadIds(IDS_OC_CAPTION), &pszDesc);
  2301. if ((hr == NETCFG_E_NO_WRITE_LOCK) && !pnocd->fCleanup)
  2302. {
  2303. int nRet;
  2304. nRet = NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_CANT_GET_LOCK,
  2305. MB_RETRYCANCEL | MB_DEFBUTTON1 | MB_ICONWARNING,
  2306. pnocd->strDesc.c_str(),
  2307. pszDesc ? pszDesc : SzLoadIds(IDS_OC_GENERIC_COMP));
  2308. CoTaskMemFree(pszDesc);
  2309. if (IDRETRY == nRet)
  2310. {
  2311. goto top;
  2312. }
  2313. else
  2314. {
  2315. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2316. }
  2317. }
  2318. TraceError("HrOcGetINetCfg", hr);
  2319. return hr;
  2320. }