Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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