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.

2636 lines
77 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include <ndisguid.h>
  4. #include "afilexp.h"
  5. #include "edc.h"
  6. #include "lm.h"
  7. #include "nceh.h"
  8. #include "ncerror.h"
  9. #include "ncmisc.h"
  10. #include "ncnetcfg.h"
  11. #include "ncreg.h"
  12. #include "ncsvc.h"
  13. #include "ncsetup.h"
  14. #include "ncatlui.h"
  15. #include "netcfgn.h"
  16. #include "netsetup.h"
  17. #include "nslog.h"
  18. #include "nsres.h"
  19. #include "resource.h"
  20. #include "upgrade.h"
  21. #include "windns.h"
  22. #include "winstall.h"
  23. #include <hnetcfg.h>
  24. extern const WCHAR c_szInfId_MS_Server[];
  25. extern const WCHAR c_szInfId_MS_NwSapAgent[];
  26. extern const WCHAR c_szInfId_MS_DHCPServer[];
  27. extern const WCHAR c_szInfId_MS_NWClient[];
  28. extern const WCHAR c_szAfSectionNetworking[]; // L"Networking";
  29. extern const WCHAR c_szAfBuildNumber[]; // L"BuildNumber";
  30. extern const WCHAR c_szSvcWorkstation[]; // L"LanmanWorkstation";
  31. extern const WCHAR c_szInfId_MS_NetBIOS[];
  32. extern const WCHAR c_szInfId_MS_MSClient[]; // L"ms_msclient";
  33. const WCHAR PSZ_SPOOLER[] = L"Spooler";
  34. const WCHAR c_szSamEventName[] = L"\\SAM_SERVICE_STARTED";
  35. const WCHAR c_szLsaEventName[] = L"\\INSTALLATION_SECURITY_HOLD";
  36. const WCHAR c_szActiveComputerNameKey[] = L"SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName";
  37. const WCHAR c_szComputerNameKey[] = L"SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
  38. const WCHAR c_szComputerNameValue[] = L"ComputerName";
  39. const WCHAR c_szOCMKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\SubComponents";
  40. const WCHAR c_szDHCPServer[] = L"dhcpserver";
  41. const WCHAR c_szSapAgent[] = L"nwsapagent";
  42. // Unattended Mode related strings
  43. //
  44. const WCHAR c_szUnattendSection[] = L"Unattended";
  45. const WCHAR c_szUnattendMode[] = L"UnattendMode";
  46. const WCHAR c_szUMDefaultHide[] = L"DefaultHide";
  47. const WCHAR c_szUMGuiAttended[] = L"GuiAttended";
  48. const WCHAR c_szUMProvideDefault[] = L"ProvideDefault";
  49. const WCHAR c_szUMReadOnly[] = L"ReadOnly";
  50. const WCHAR c_szUMFullUnattended[] = L"FullUnattended";
  51. // Sysprep registry strings
  52. const WCHAR c_szSystemSetupKey[] = L"SYSTEM\\Setup";
  53. const WCHAR c_szMiniSetupInProgress[] = L"MiniSetupInProgress";
  54. const DWORD c_cmsWaitForINetCfgWrite = 120000;
  55. const UINT PWM_PROCEED = WM_USER+1202;
  56. const UINT PWM_EXIT = WM_USER+1203;
  57. const UINT c_uiUpgradeRefreshID = 7719;
  58. const UINT c_uiUpgradeRefreshRate = 5000; // Refresh rate in milliseconds
  59. EXTERN_C DWORD InstallUpgradeWorkThrd(InitThreadParam* pitp);
  60. // Setup Wizard Global - Only used during setup.
  61. extern CWizard * g_pSetupWizard;
  62. WNDPROC OldProgressProc;
  63. BOOL
  64. NewProgessProc(
  65. IN HWND hdlg,
  66. IN UINT msg,
  67. IN WPARAM wParam,
  68. IN LPARAM lParam
  69. )
  70. {
  71. switch (msg)
  72. {
  73. case PBM_DELTAPOS:
  74. case PBM_SETRANGE:
  75. case PBM_SETRANGE32:
  76. case PBM_STEPIT:
  77. case PBM_SETPOS:
  78. case PBM_SETSTEP:
  79. // Forward to the billboard progress.
  80. g_pSetupWizard->PSetupData()->BillboardProgressCallback(msg, wParam, lParam);
  81. break;
  82. }
  83. // Always call the progress on the wizard page.
  84. return (BOOL)CallWindowProc(OldProgressProc,hdlg,msg,wParam,lParam);
  85. }
  86. //
  87. // Function: SignalLsa
  88. //
  89. // Purpose: During initial setup, the winlogon creates a special event
  90. // (unsignalled) before it starts up Lsa. During initialization
  91. // lsa waits on this event. After Gui setup is done with setting
  92. // the AccountDomain sid it can signal the event. Lsa will then
  93. // continue initialization.
  94. //
  95. // Parameters: none
  96. //
  97. // Returns: nothing
  98. //
  99. BOOL SignalLsa(VOID)
  100. {
  101. TraceFileFunc(ttidGuiModeSetup);
  102. UNICODE_STRING UnicodeString;
  103. OBJECT_ATTRIBUTES Attributes;
  104. NTSTATUS Status;
  105. HANDLE Event;
  106. BOOL b;
  107. //
  108. // If the following event exists, it is an indication that
  109. // LSA is blocked at installation time and that we need to
  110. // signal this event.
  111. //
  112. // Unfortunately we have to use the NT APIs to do this, because
  113. // all events created/accessed via the Win32 APIs will be in the
  114. // BaseNamedObjects directory, and LSA doesn't know to look there.
  115. //
  116. RtlInitUnicodeString(&UnicodeString,c_szLsaEventName);
  117. InitializeObjectAttributes(&Attributes,&UnicodeString,0,0,NULL);
  118. Status = NtOpenEvent(&Event,EVENT_MODIFY_STATE,&Attributes);
  119. if(NT_SUCCESS(Status))
  120. {
  121. Status = NtSetEvent(Event,NULL);
  122. if(NT_SUCCESS(Status))
  123. {
  124. b = TRUE;
  125. }
  126. else
  127. {
  128. b = FALSE;
  129. }
  130. CloseHandle(Event);
  131. } else {
  132. b = FALSE;
  133. }
  134. return(b);
  135. }
  136. //
  137. // Function: CreateSamEvent
  138. //
  139. // Purpose: Create an event that SAM will use to tell us when it's finished
  140. // initializing.
  141. //
  142. // Parameters: phSamEvent [OUT] - Handle to the event object created
  143. //
  144. // Returns: BOOL, TRUE on success
  145. //
  146. BOOL CreateSamEvent(HANDLE * phSamEvent)
  147. {
  148. TraceFileFunc(ttidGuiModeSetup);
  149. UNICODE_STRING UnicodeString;
  150. OBJECT_ATTRIBUTES Attributes;
  151. NTSTATUS Status;
  152. //
  153. // Unfortunately we have to use the NT APIs to do this, because
  154. // all events created/accessed via the Win32 APIs will be in the
  155. // BaseNamedObjects directory, and SAM doesn't know to look there.
  156. //
  157. RtlInitUnicodeString(&UnicodeString,c_szSamEventName);
  158. InitializeObjectAttributes(&Attributes,&UnicodeString,0,0,NULL);
  159. Status = NtCreateEvent(phSamEvent,SYNCHRONIZE,&Attributes,NotificationEvent,FALSE);
  160. if(!NT_SUCCESS(Status)) {
  161. *phSamEvent = NULL;
  162. }
  163. return(NT_SUCCESS(Status));
  164. }
  165. //
  166. // Function: WaitForSam
  167. //
  168. // Purpose: Wait for SAM to finish initializing. We can tell when it's done
  169. // because an event we created earlier (see CreateSamEvent()) will
  170. // become signalled.
  171. //
  172. // Parameters: hSamEvent - HANDLE to wait for
  173. //
  174. // Returns: BOOL, TRUE on success
  175. //
  176. BOOL WaitForSam(HANDLE hSamEvent)
  177. {
  178. DWORD d;
  179. BOOL b = false;
  180. if (hSamEvent)
  181. {
  182. b = TRUE;
  183. d = WaitForSingleObject(hSamEvent,INFINITE);
  184. if(d != WAIT_OBJECT_0) {
  185. b = FALSE;
  186. TraceError("WaitForSam",E_UNEXPECTED);
  187. }
  188. }
  189. return(b);
  190. }
  191. //
  192. // Function: SyncSAM
  193. //
  194. // Purpose: Sychronize the SAM database and Lsa
  195. //
  196. // Parameters: pWizard [IN] - Ptr to a Wizard Instance
  197. //
  198. // Returns: nothing
  199. //
  200. VOID SyncSAM(CWizard *pWizard)
  201. {
  202. TraceFileFunc(ttidGuiModeSetup);
  203. HANDLE hSamEvent = NULL;
  204. Assert(!IsPostInstall(pWizard));
  205. TraceTag(ttidWizard,"Beginning SAM/Lsa Sync");
  206. // Sync the SAM DB
  207. CreateSamEvent(&hSamEvent);
  208. SignalLsa();
  209. if (hSamEvent)
  210. {
  211. WaitForSam(hSamEvent);
  212. CloseHandle(hSamEvent);
  213. }
  214. TraceTag(ttidWizard,"Completed SAM/Lsa Sync");
  215. }
  216. //
  217. // Function: HrSetActiveComputerName
  218. //
  219. // Purpose: To make sure the active and intended computer names are the same
  220. //
  221. // Parameters: pszNewName [IN] - the new computer name
  222. //
  223. // Returns: HRESULT, S_OK on success
  224. //
  225. HRESULT
  226. HrSetActiveComputerName (
  227. IN PCWSTR pszNewName )
  228. {
  229. TraceFileFunc(ttidGuiModeSetup);
  230. HRESULT hr;
  231. HKEY hkeyActive = NULL;
  232. HKEY hkeyIntended = NULL;
  233. tstring str;
  234. TraceTag(ttidWizard,"Setting the active computer name");
  235. // open the keys we need
  236. hr = HrRegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szActiveComputerNameKey,
  237. KEY_WRITE, &hkeyActive );
  238. if (FAILED(hr))
  239. goto Error;
  240. hr = HrRegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szComputerNameKey,
  241. KEY_READ_WRITE, &hkeyIntended );
  242. if (FAILED(hr))
  243. goto Error;
  244. if (pszNewName == NULL)
  245. {
  246. hr = HrRegQueryString(hkeyIntended, c_szComputerNameValue, &str);
  247. pszNewName = str.c_str();
  248. }
  249. else
  250. {
  251. // set the intended computer name
  252. hr = HrRegSetSz(hkeyIntended, c_szComputerNameValue, pszNewName);
  253. }
  254. if (FAILED(hr))
  255. goto Error;
  256. // set the active computer name
  257. hr = HrRegSetSz(hkeyActive, c_szComputerNameValue, pszNewName);
  258. Error:
  259. // close it all up
  260. RegSafeCloseKey( hkeyActive );
  261. RegSafeCloseKey( hkeyIntended );
  262. TraceHr(ttidWizard, FAL, hr, FALSE, "HrSetActiveComputerName");
  263. return hr;
  264. }
  265. //
  266. // Function: HrInitAndGetINetCfg
  267. //
  268. // Purpose: To initialize an INetCfg instance and to do some preliminary
  269. // answerfile work (if an answer file is being used).
  270. //
  271. // Parameters: pWizard [IN] - Ptr to a wizard instance
  272. //
  273. // Returns: HRESULT, S_OK on success
  274. //
  275. HRESULT HrInitAndGetINetCfg(CWizard *pWizard)
  276. {
  277. TraceFileFunc(ttidGuiModeSetup);
  278. HRESULT hr = S_OK;
  279. Assert(NULL != pWizard);
  280. if (SUCCEEDED(hr))
  281. {
  282. PWSTR pszClientDesc = NULL;
  283. INetCfg* pNetCfg = NULL;
  284. BOOL fInitCom = !pWizard->FCoUninit();
  285. hr = HrCreateAndInitializeINetCfg(&fInitCom, &pNetCfg, TRUE,
  286. c_cmsWaitForINetCfgWrite,
  287. SzLoadIds(IDS_WIZARD_CAPTION),
  288. &pszClientDesc);
  289. if (SUCCEEDED(hr))
  290. {
  291. // Retain our success in initializing COM only if we asked to
  292. // initialize COM in the first place.
  293. if (!pWizard->FCoUninit())
  294. {
  295. pWizard->SetCoUninit(fInitCom);
  296. }
  297. pWizard->SetNetCfg(pNetCfg);
  298. CoTaskMemFree(pszClientDesc);
  299. }
  300. }
  301. TraceHr(ttidWizard, FAL, hr, FALSE, "HrInitAndGetINetCfg");
  302. return hr;
  303. }
  304. //
  305. // Function: OnUpgradeUpdateProgress
  306. //
  307. // Purpose: Update the progress control during setup
  308. //
  309. // Parameters: Standard timer callback parameters
  310. //
  311. // Returns: nothing
  312. //
  313. VOID OnUpgradeUpdateProgress(HWND hwndDlg)
  314. {
  315. TraceFileFunc(ttidGuiModeSetup);
  316. CWizard * pWizard = reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  317. Assert(NULL != pWizard);
  318. LPARAM lParam = pWizard->GetPageData(IDD_Upgrade);
  319. Assert(lParam);
  320. UpgradeData * pData = reinterpret_cast<UpgradeData *>(lParam);
  321. if(pData)
  322. {
  323. // Get current position
  324. //
  325. HWND hwndProgress = GetDlgItem(hwndDlg, IDC_UPGRADE_PROGRESS);
  326. Assert(hwndProgress);
  327. UINT nCurPos = SendMessage(hwndProgress, PBM_GETPOS, 0, 0);
  328. // If the current position is less then the cap, advance
  329. //
  330. if (nCurPos < pData->nCurrentCap)
  331. {
  332. SendMessage(hwndProgress, PBM_SETPOS, ++nCurPos, 0);
  333. }
  334. }
  335. }
  336. //
  337. // Function: UpgradeSetProgressCap
  338. //
  339. // Purpose: Update the current cap for the progress control
  340. //
  341. // Parameters: hwndDlg - Handle to the current dialog
  342. // pWizard - Ptr to the wizard data
  343. // nNewCap - The new maximum progress cap
  344. //
  345. // Returns: nothing
  346. //
  347. VOID
  348. OnUpgradeUpdateProgressCap (
  349. HWND hwndDlg,
  350. CWizard* pWizard,
  351. UINT nNewCap)
  352. {
  353. TraceFileFunc(ttidGuiModeSetup);
  354. LPARAM lParam = pWizard->GetPageData(IDD_Upgrade);
  355. Assert(lParam);
  356. UpgradeData * pData = reinterpret_cast<UpgradeData *>(lParam);
  357. if(pData)
  358. {
  359. // Since we're increasing the progress cap, we need to advance the
  360. // progress indicator to the old cap.
  361. //
  362. SendMessage(GetDlgItem(hwndDlg, IDC_UPGRADE_PROGRESS), PBM_SETPOS,
  363. pData->nCurrentCap, 0);
  364. // Retain the new cap
  365. //
  366. pData->nCurrentCap = nNewCap;
  367. }
  368. }
  369. //
  370. // Function:
  371. //
  372. // Purpose:
  373. //
  374. // Parameters:
  375. //
  376. // Returns:
  377. //
  378. VOID ReadAnswerFileSetupOptions(CWizard * pWizard)
  379. {
  380. TraceFileFunc(ttidGuiModeSetup);
  381. if (IsUnattended(pWizard))
  382. {
  383. // Get the unattended flags
  384. //
  385. CSetupInfFile csif;
  386. Assert(pWizard->PSetupData());
  387. Assert(pWizard->PSetupData()->UnattendFile);
  388. // Open the answser file
  389. //
  390. if (SUCCEEDED(csif.HrOpen(pWizard->PSetupData()->UnattendFile, NULL,
  391. INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL)))
  392. {
  393. tstring str;
  394. // Confirm no one has over written the default
  395. //
  396. Assert(UM_DEFAULTHIDE == pWizard->GetUnattendedMode());
  397. // Locate the UnattendMode string, if it exists
  398. //
  399. if (SUCCEEDED(csif.HrGetString(c_szUnattendSection,
  400. c_szUnattendMode, &str)))
  401. {
  402. struct
  403. {
  404. PCWSTR pszMode;
  405. UM_MODE UMMode;
  406. } UMModeMap[] = {{c_szUMDefaultHide,UM_DEFAULTHIDE},
  407. {c_szUMGuiAttended,UM_GUIATTENDED},
  408. {c_szUMProvideDefault,UM_PROVIDEDEFAULT},
  409. {c_szUMReadOnly,UM_READONLY},
  410. {c_szUMFullUnattended,UM_FULLUNATTENDED}};
  411. // Search the map for the unattended flag, note that if
  412. // we don't find it the default is UM_DEFAULTHIDE
  413. //
  414. for (UINT nIdx = 0; nIdx < celems(UMModeMap); nIdx++)
  415. {
  416. if (0 == _wcsicmp(str.c_str(),UMModeMap[nIdx].pszMode))
  417. {
  418. pWizard->SetUnattendedMode(UMModeMap[nIdx].UMMode);
  419. break;
  420. }
  421. }
  422. }
  423. }
  424. }
  425. }
  426. //
  427. // Function: StartSpooler
  428. //
  429. // Purpose: Start the spooler process before the components are applied
  430. // as some of the components want to install print monitors, and
  431. // the spooler needs to be running for this to succeed.
  432. //
  433. // Parameters: none
  434. //
  435. // Returns: nothing
  436. //
  437. VOID StartSpooler()
  438. {
  439. TraceFileFunc(ttidGuiModeSetup);
  440. CServiceManager csm;
  441. TraceTag(ttidWizard, "Attempting to start spooler");
  442. HRESULT hr = csm.HrStartServiceNoWait(PSZ_SPOOLER);
  443. TraceHr(ttidWizard, FAL, hr, FALSE,
  444. "*** StartSpooler - The spooler failed to start, you probably "
  445. "won't have networking ***");
  446. }
  447. //
  448. // Function: HrCommitINetCfgChanges
  449. //
  450. // Purpose: Validate and Commit changes to the INetCfg object
  451. //
  452. // Parameters: hwnd [IN] - Handle of the current window
  453. // pWizard [IN] - Ptr to a wizard instance
  454. //
  455. // Returns: HRESULT, S_OK on success
  456. //
  457. HRESULT HrCommitINetCfgChanges(HWND hwnd, CWizard * pWizard)
  458. {
  459. TraceFileFunc(ttidGuiModeSetup);
  460. INetCfg * pNetCfg = pWizard->PNetCfg();
  461. Assert(NULL != pNetCfg);
  462. // Commit the changes
  463. TraceTag(ttidWizard,"HrCommitINetCfgChanges - Applying changes");
  464. HRESULT hr = pNetCfg->Apply();
  465. if (S_FALSE == hr)
  466. {
  467. hr = S_OK;
  468. }
  469. TraceHr(ttidWizard, FAL, hr, FALSE, "HrCommitINetCfgChanges");
  470. return hr;
  471. }
  472. //
  473. // Function: IsSBS
  474. //
  475. // Purpose: Determine if it is SBS version.
  476. //
  477. // Parameters: None
  478. //
  479. // Returns: BOOL, TRUE if it is Microsoft Small Business Server
  480. //
  481. BOOL IsSBS (VOID)
  482. {
  483. TraceFileFunc(ttidGuiModeSetup);
  484. OSVERSIONINFOEX ose;
  485. BOOL bVersionRet;
  486. ZeroMemory(&ose, sizeof(ose));
  487. ose.dwOSVersionInfoSize = sizeof(ose);
  488. bVersionRet = GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&ose));
  489. return (bVersionRet && (ose.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED));
  490. }
  491. //
  492. // Function: IsMSClientInstalled
  493. //
  494. // Purpose: Determine if MSClient is installed.
  495. //
  496. // Parameters: hwnd [IN] - Handle of the current window
  497. // pWizard [IN] - Ptr to a wizard instance
  498. //
  499. // Returns: BOOL, TRUE if MS Client is installed, otherwise
  500. //
  501. BOOL IsMSClientInstalled(HWND hwnd, CWizard * pWizard)
  502. {
  503. INetCfg *pNetCfg;
  504. INetCfgComponent *pncc;
  505. HRESULT hr;
  506. TraceFileFunc(ttidGuiModeSetup);
  507. Assert(NULL != pWizard);
  508. if ( !pWizard )
  509. {
  510. return FALSE;
  511. }
  512. pNetCfg = pWizard->PNetCfg();
  513. Assert(NULL != pNetCfg);
  514. if ( !pNetCfg )
  515. {
  516. return FALSE;
  517. }
  518. hr = pNetCfg->FindComponent(c_szInfId_MS_MSClient, &pncc);
  519. if ( hr == S_OK )
  520. {
  521. ReleaseObj(pncc);
  522. }
  523. TraceHr(ttidWizard, FAL, hr, FALSE, "IsMSClientInstalled");
  524. return hr == S_OK;
  525. }
  526. //
  527. // Function:
  528. //
  529. // Purpose:
  530. //
  531. // Parameters:
  532. //
  533. // Returns:
  534. //
  535. BOOL OnProcessPrevAdapterPagePrev(HWND hwndDlg, UINT idd)
  536. {
  537. TraceFileFunc(ttidGuiModeSetup);
  538. BOOL fRet = FALSE;
  539. CWizard * pWizard =
  540. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  541. Assert(NULL != pWizard);
  542. HPROPSHEETPAGE hPage;
  543. GUID * pguidAdapter = pWizard->PAdapterQueue()->PrevAdapter();
  544. if (NULL != pguidAdapter)
  545. {
  546. pWizard->SetCurrentProvider(0);
  547. CWizProvider * pWizProvider = pWizard->GetCurrentProvider();
  548. Assert(NULL != pWizProvider);
  549. Assert(pWizProvider->ULPageCount());
  550. // Reset the providers guard page to point forward
  551. LPARAM ulId = reinterpret_cast<LPARAM>(pWizProvider);
  552. pWizard->SetPageDirection(ulId, NWPD_FORWARD);
  553. // Push the adapter guid onto the provider
  554. HRESULT hr = pWizProvider->HrSpecifyAdapterGuid(pguidAdapter);
  555. if (SUCCEEDED(hr))
  556. {
  557. // Get the last page from the provider
  558. TraceTag(ttidWizard, "Jumping to LAN provider last page...");
  559. hPage = (pWizProvider->PHPropPages())[pWizProvider->ULPageCount() - 1];
  560. Assert(hPage);
  561. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
  562. PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0,
  563. (LPARAM)(HPROPSHEETPAGE)hPage);
  564. fRet = TRUE; // We jumped to a provider page
  565. }
  566. }
  567. else
  568. {
  569. if (idd)
  570. {
  571. hPage = pWizard->GetPageHandle(idd);
  572. Assert(hPage);
  573. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
  574. PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0,
  575. (LPARAM)(HPROPSHEETPAGE)hPage);
  576. }
  577. }
  578. return fRet;
  579. }
  580. //
  581. // Function: OBOUserAddRefSpecialCase
  582. //
  583. // Purpose: Handle a special case where when upgrading from NT351 or NT 4
  584. // with MS's "File and Print" and GSNW. In this case we need to
  585. // AddRef OBOUser F&P, so removal of GSNW does not remove F&P.
  586. //
  587. // Parameters: pWizard [IN] - Context information
  588. //
  589. // Returns: Nothing. (this is basically a do it if we can special case.)
  590. //
  591. VOID OBOUserAddRefSpecialCase(CWizard * pWizard)
  592. {
  593. TraceFileFunc(ttidGuiModeSetup);
  594. CSetupInfFile csif;
  595. HRESULT hr = S_OK;
  596. Assert(pWizard->PNetCfg());
  597. Assert(IsUnattended(pWizard));
  598. TraceTag(ttidWizard, "OBOUserAddRefSpecialCase - Start");
  599. // if we're upgrading from NT 3.51 or NT 4
  600. //
  601. if (pWizard->PSetupData()->UnattendFile)
  602. {
  603. /* DWORD dwBuild = 0;
  604. hr = csif.HrOpen(pWizard->PSetupData()->UnattendFile,
  605. NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
  606. if (SUCCEEDED(hr))
  607. {
  608. hr = csif.HrGetDword(c_szAfSectionNetworking, c_szAfBuildNumber, &dwBuild);
  609. }
  610. if (SUCCEEDED(hr) && (dwBuild <= wWinNT4BuildNumber))
  611. {*/
  612. PRODUCT_FLAVOR pf;
  613. // If this is an NT server (GSNW is server only)
  614. //
  615. GetProductFlavor(NULL, &pf);
  616. if (PF_WORKSTATION != pf)
  617. {
  618. const GUID * rgguidClass[2] = {&GUID_DEVCLASS_NETSERVICE,
  619. &GUID_DEVCLASS_NETCLIENT};
  620. const PCWSTR rgpszComponentId[2] = {c_szInfId_MS_Server,
  621. c_szInfId_MS_NWClient};
  622. INetCfgComponent* rgpncc[2] = {NULL, NULL};
  623. hr = HrFindComponents (pWizard->PNetCfg(), 2, rgguidClass,
  624. rgpszComponentId, rgpncc);
  625. if (SUCCEEDED(hr))
  626. {
  627. // Are both "GSNW" and "File and Print" installed?
  628. //
  629. if (rgpncc[0] && rgpncc[1])
  630. {
  631. NETWORK_INSTALL_PARAMS nip = {0};
  632. nip.dwSetupFlags = NSF_PRIMARYINSTALL;
  633. // re-install OBOUser "File and Print"
  634. //
  635. TraceTag(ttidWizard, " OBOUser Install of File and Print Services");
  636. TraceTag(ttidWizard, " On upgrade from NT 3.51 or NT 4");
  637. (void)HrInstallComponentsOboUser(pWizard->PNetCfg(), &nip, 1,
  638. &rgguidClass[0],
  639. &rgpszComponentId[0]);
  640. }
  641. ReleaseObj(rgpncc[0]);
  642. ReleaseObj(rgpncc[1]);
  643. }
  644. }
  645. /// }
  646. }
  647. TraceTag(ttidWizard, "OBOUserAddRefSpecialCase - End");
  648. TraceError("OBOUserAddRefSpecialCase",hr);
  649. }
  650. //
  651. // Function:
  652. //
  653. // Purpose:
  654. //
  655. // Parameters:
  656. //
  657. // Returns:
  658. //
  659. BOOL OnProcessNextAdapterPageNext(HWND hwndDlg, BOOL FOnActivate)
  660. {
  661. TraceFileFunc(ttidGuiModeSetup);
  662. // Retrieve the CWizard instance from the dialog
  663. CWizard * pWizard =
  664. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  665. Assert(NULL != pWizard);
  666. HRESULT hr = S_OK;
  667. BOOL fRet = FALSE;
  668. HPROPSHEETPAGE hPage;
  669. GUID * pguidAdapter;
  670. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
  671. // Refresh the contents of the adapter queue.
  672. // ATM adapters may have been added or removed
  673. if (pWizard->FProcessLanPages())
  674. {
  675. // Commit changes and look for any new adapters
  676. (VOID)HrCommitINetCfgChanges(GetParent(hwndDlg), pWizard);
  677. (VOID)pWizard->PAdapterQueue()->HrQueryUnboundAdapters(pWizard);
  678. }
  679. // If there are adapters left to process prime the pump
  680. pguidAdapter = pWizard->PAdapterQueue()->NextAdapter();
  681. if (NULL != pguidAdapter)
  682. {
  683. pWizard->SetCurrentProvider(0);
  684. CWizProvider * pWizProvider = pWizard->GetCurrentProvider();
  685. Assert(NULL != pWizProvider);
  686. Assert(pWizProvider->ULPageCount());
  687. // Push the adapter guid onto the provider
  688. hr = pWizProvider->HrSpecifyAdapterGuid(pguidAdapter);
  689. if (SUCCEEDED(hr))
  690. {
  691. #if DBG
  692. WCHAR szGuid[c_cchGuidWithTerm];
  693. Assert(pguidAdapter);
  694. if (SUCCEEDED(StringFromGUID2(*pguidAdapter, szGuid,
  695. c_cchGuidWithTerm)))
  696. {
  697. TraceTag(ttidWizard, " Calling LAN pages for Adapter Guid: %S", szGuid);
  698. }
  699. #endif
  700. // Reset the providers guard page to point forward
  701. LPARAM ulId = reinterpret_cast<LPARAM>(pWizProvider);
  702. pWizard->SetPageDirection(ulId, NWPD_FORWARD);
  703. // Get the first page from the provider
  704. hPage = (pWizProvider->PHPropPages())[0];
  705. Assert(hPage);
  706. PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0,
  707. (LPARAM)(HPROPSHEETPAGE)hPage);
  708. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
  709. TraceTag(ttidWizard, "Jumping to LAN provider first page...");
  710. fRet = TRUE; // We processed it
  711. }
  712. }
  713. // If there are no adapters left to process, or an error occurred
  714. if ((NULL == pguidAdapter) || FAILED(hr))
  715. {
  716. UINT idd = IDD_Exit;
  717. // Commit any changes to INetCfg.
  718. if (SUCCEEDED(hr) && pWizard->FProcessLanPages())
  719. {
  720. // Commit changes
  721. (VOID)HrCommitINetCfgChanges(GetParent(hwndDlg), pWizard);
  722. }
  723. if (!IsPostInstall(pWizard) && IsMSClientInstalled(GetParent(hwndDlg), pWizard))
  724. {
  725. idd = IDD_Join;
  726. TraceTag(ttidWizard, "Jumping to Join page...");
  727. }
  728. else
  729. {
  730. TraceTag(ttidWizard, "Jumping to Exit page...");
  731. }
  732. if (FOnActivate)
  733. {
  734. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, idd);
  735. }
  736. else
  737. {
  738. // else goto the appropriate page
  739. hPage = pWizard->GetPageHandle(idd);
  740. Assert(hPage);
  741. PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0, (LPARAM)hPage);
  742. }
  743. fRet = TRUE; // We processed it
  744. }
  745. Assert(TRUE == fRet);
  746. return fRet;
  747. }
  748. //
  749. // Function: FixupOldOcComponents
  750. //
  751. // Purpose: Convert SAP and DHCP optional components (if present) into
  752. // regular networking components.
  753. //
  754. // Parameters: pWizard
  755. //
  756. // Returns: nothing
  757. //
  758. void FixupOldOcComponents(CWizard * pWizard)
  759. {
  760. TraceFileFunc(ttidGuiModeSetup);
  761. HRESULT hr;
  762. static const GUID* c_apguidInstalledComponentClasses [] =
  763. {
  764. &GUID_DEVCLASS_NETSERVICE, // DHCP
  765. &GUID_DEVCLASS_NETSERVICE, // SAP Agent
  766. };
  767. static const PCWSTR c_apszInstalledComponentIds [] =
  768. {
  769. c_szInfId_MS_DHCPServer,
  770. c_szInfId_MS_NwSapAgent,
  771. };
  772. static const PCWSTR c_apszOcNames[] =
  773. {
  774. c_szDHCPServer,
  775. c_szSapAgent,
  776. };
  777. // If component was installed as an optional component
  778. //
  779. HKEY hkey;
  780. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szOCMKey, KEY_READ_WRITE, &hkey);
  781. if (SUCCEEDED(hr))
  782. {
  783. DWORD dw;
  784. for (UINT idx=0; idx<celems(c_apszOcNames); idx++)
  785. {
  786. // Remove the OC Manager reference
  787. //
  788. hr = HrRegQueryDword (hkey, c_apszOcNames[idx], &dw);
  789. if (SUCCEEDED(hr))
  790. {
  791. if (dw)
  792. {
  793. // Install OBO user the component
  794. //
  795. NETWORK_INSTALL_PARAMS nip = {0};
  796. // Note: Claiming it's a server upgrade is a bit bogus,
  797. // but is needed so dhcpsobj.cpp doesn't display
  798. // UI.
  799. //
  800. nip.dwSetupFlags |= NSF_WINNT_SVR_UPGRADE;
  801. nip.dwSetupFlags |= NSF_PRIMARYINSTALL;
  802. (void)HrInstallComponentsOboUser(pWizard->PNetCfg(), &nip, 1,
  803. &c_apguidInstalledComponentClasses[idx],
  804. &c_apszInstalledComponentIds[idx]);
  805. }
  806. // Delete the value
  807. //
  808. (VOID)HrRegDeleteValue(hkey, c_apszOcNames[idx]);
  809. }
  810. }
  811. RegCloseKey(hkey);
  812. }
  813. }
  814. struct NAME_DATA
  815. {
  816. PCWSTR pszComputerName;
  817. };
  818. //+---------------------------------------------------------------------------
  819. //
  820. // Function: DuplicateNameProc
  821. //
  822. // Purpose: Dialog procedure for the duplicate name dialog
  823. //
  824. // Arguments:
  825. // hwndDlg []
  826. // uMsg [] See MSDN
  827. // wParam []
  828. // lParam []
  829. //
  830. // Returns:
  831. //
  832. // Author: danielwe 16 Feb 1999
  833. //
  834. // Notes:
  835. //
  836. INT_PTR
  837. CALLBACK
  838. DuplicateNameProc(
  839. HWND hwndDlg,
  840. UINT uMsg,
  841. WPARAM wParam,
  842. LPARAM lParam)
  843. {
  844. TraceFileFunc(ttidGuiModeSetup);
  845. BOOL frt = FALSE;
  846. WCHAR szBuf[1024];
  847. WCHAR szText[1024];
  848. NAME_DATA * pData;
  849. switch (uMsg)
  850. {
  851. case WM_INITDIALOG:
  852. SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
  853. pData = (NAME_DATA *)lParam;
  854. Assert(pData->pszComputerName);
  855. GetDlgItemText(hwndDlg, TXT_Caption, szText, celems(szText));
  856. // add computer name to title
  857. wsprintfW(szBuf, szText, pData->pszComputerName);
  858. SetDlgItemText(hwndDlg, TXT_Caption, szBuf);
  859. // limit text in edit control
  860. SendDlgItemMessage(hwndDlg, EDT_New_Name, EM_LIMITTEXT,
  861. (WPARAM)MAX_COMPUTERNAME_LENGTH, 0);
  862. return TRUE;
  863. case WM_COMMAND:
  864. switch (HIWORD(wParam))
  865. {
  866. case BN_CLICKED:
  867. switch (LOWORD(wParam))
  868. {
  869. case IDOK:
  870. NET_API_STATUS nas;
  871. GetDlgItemText(hwndDlg, EDT_New_Name, szBuf, celems(szBuf));
  872. nas = NetValidateName(NULL, szBuf, NULL, NULL,
  873. NetSetupMachine);
  874. if (nas != NO_ERROR)
  875. {
  876. UINT ids;
  877. if (nas == ERROR_DUP_NAME)
  878. {
  879. ids = IDS_E_COMPUTER_NAME_DUPE;
  880. TraceTag(ttidWizard, "Computer name %S"
  881. " is a dupe.", szBuf);
  882. }
  883. else
  884. {
  885. ids = IDS_E_COMPUTER_NAME_INVALID;
  886. TraceTag(ttidWizard, "Computer name %S"
  887. " is invalid.", szBuf);
  888. }
  889. MessageBeep(MB_ICONSTOP);
  890. MessageBox(hwndDlg, SzLoadIds(ids),
  891. SzLoadIds(IDS_SETUP_CAPTION),
  892. MB_ICONSTOP | MB_OK);
  893. SetFocus(GetDlgItem(hwndDlg, EDT_New_Name));
  894. Edit_SetSel(GetDlgItem(hwndDlg, EDT_New_Name), 0, -1);
  895. }
  896. else
  897. {
  898. // 398325/406259 : trying to keep DNS names lowercased
  899. //
  900. LowerCaseComputerName(szBuf);
  901. if (!SetComputerNameEx(ComputerNamePhysicalDnsHostname,
  902. szBuf))
  903. {
  904. TraceLastWin32Error("SetComputerNameEx");
  905. }
  906. else
  907. {
  908. CServiceManager sm;
  909. (VOID)HrSetActiveComputerName(NULL);
  910. TraceTag(ttidWizard, "Setting new computer name "
  911. "%S.", szBuf);
  912. TraceTag(ttidWizard, "Restarting workstation service"
  913. "...");
  914. (VOID) sm.HrStartServiceAndWait(c_szSvcWorkstation);
  915. }
  916. EndDialog(hwndDlg, 0);
  917. }
  918. break;
  919. }
  920. break;
  921. }
  922. break;
  923. default:
  924. frt = FALSE;
  925. break;
  926. }
  927. return frt;
  928. }
  929. //+---------------------------------------------------------------------------
  930. //
  931. // Function: GenerateComputerNameBasedOnOrganizationName
  932. //
  933. // Purpose: Generate a random computer name based on the register user name
  934. // and organization name
  935. //
  936. // Arguments:
  937. // pszGeneratedStringOut Generated Computer Name - allocated by caller
  938. // dwDesiredStrLenIn Desired length of Computer Name
  939. //
  940. // Returns:
  941. //
  942. // Author: deonb 22 April 2000
  943. //
  944. // Notes:
  945. //
  946. VOID GenerateComputerNameBasedOnOrganizationName(
  947. LPWSTR pszGeneratedStringOut, // the generated computer name
  948. DWORD dwDesiredStrLenIn // desired length for the computer name
  949. )
  950. {
  951. TraceFileFunc(ttidGuiModeSetup);
  952. static DWORD dwSeed = 98725757;
  953. static LPCWSTR UsableChars = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  954. static LPCWSTR RegKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
  955. static LPCWSTR RegOwner = REGSTR_VAL_REGOWNER;
  956. static LPCWSTR RegOrganization = REGSTR_VAL_REGORGANIZATION;
  957. WCHAR pszNameOrgNameIn[MAX_PATH];
  958. WCHAR pszNameOrgOrgIn[MAX_PATH]; // organization the computer is registered to
  959. pszNameOrgNameIn[0] = NULL;
  960. pszNameOrgOrgIn[0] = NULL;
  961. HKEY hkResult = NULL;
  962. HRESULT hr;
  963. hr = HrRegOpenKeyBestAccess(HKEY_LOCAL_MACHINE, RegKey, &hkResult);
  964. if (SUCCEEDED(hr))
  965. {
  966. tstring pstr;
  967. hr = HrRegQueryString(hkResult, RegOwner, &pstr);
  968. if (SUCCEEDED(hr))
  969. wcsncpy(pszNameOrgNameIn, pstr.c_str(), MAX_PATH);
  970. hr = HrRegQueryString(hkResult, RegOrganization, &pstr);
  971. if (SUCCEEDED(hr))
  972. wcsncpy(pszNameOrgOrgIn, pstr.c_str(), MAX_PATH);
  973. RegCloseKey(hkResult);
  974. }
  975. //
  976. // How many characters will come from the org/name string.
  977. //
  978. DWORD BaseLength = 8;
  979. DWORD i,j;
  980. DWORD UsableCount;
  981. if( dwDesiredStrLenIn <= BaseLength )
  982. {
  983. BaseLength = dwDesiredStrLenIn - 1;
  984. }
  985. if( pszNameOrgOrgIn[0] )
  986. {
  987. wcscpy( pszGeneratedStringOut, pszNameOrgOrgIn );
  988. } else if( pszNameOrgNameIn[0] )
  989. {
  990. wcscpy( pszGeneratedStringOut, pszNameOrgNameIn );
  991. } else
  992. {
  993. wcscpy( pszGeneratedStringOut, L"X" );
  994. for( i = 1; i < BaseLength; i++ )
  995. {
  996. wcscat( pszGeneratedStringOut, L"X" );
  997. }
  998. }
  999. //
  1000. // Get him upper-case for our filter...
  1001. //
  1002. CharUpper( pszGeneratedStringOut );
  1003. //
  1004. // Now we want to put a '-' at the end
  1005. // of our pszGeneratedStringOut. We'd like it to
  1006. // be placed in the BASE_LENGTH character, but
  1007. // the string may be shorter than that, or may
  1008. // even have a ' ' in it. Figure out where to
  1009. // put the '-' now.
  1010. //
  1011. for( i = 0; i <= BaseLength; i++ )
  1012. {
  1013. //
  1014. // Check for a short string.
  1015. //
  1016. if( ( pszGeneratedStringOut[i] == 0 ) ||
  1017. ( pszGeneratedStringOut[i] == L' ' ) ||
  1018. ( ! wcschr(UsableChars, pszGeneratedStringOut[i] ) ) ||
  1019. ( i == BaseLength )
  1020. )
  1021. {
  1022. pszGeneratedStringOut[i] = L'-';
  1023. pszGeneratedStringOut[i+1] = 0;
  1024. break;
  1025. }
  1026. }
  1027. //
  1028. // Special case the scenario where we had no usable
  1029. // characters.
  1030. //
  1031. if( pszGeneratedStringOut[0] == L'-' )
  1032. {
  1033. pszGeneratedStringOut[0] = 0;
  1034. }
  1035. UsableCount = wcslen(UsableChars);
  1036. GUID gdRandom;
  1037. CoCreateGuid(&gdRandom);
  1038. LPBYTE lpGuid = reinterpret_cast<LPBYTE>(&gdRandom);
  1039. j = wcslen( pszGeneratedStringOut );
  1040. for( i = j; i < dwDesiredStrLenIn; i++ )
  1041. {
  1042. pszGeneratedStringOut[i] = UsableChars[lpGuid[i % sizeof(GUID)] % UsableCount];
  1043. }
  1044. pszGeneratedStringOut[i] = 0;
  1045. CharUpper(pszGeneratedStringOut);
  1046. }
  1047. //+---------------------------------------------------------------------------
  1048. //
  1049. // Function: EnsureUniqueComputerName
  1050. //
  1051. // Purpose: Ensures that the computer name entered in the first part of
  1052. // GUI mode setup (note: this UI is not owned by NetCfg) is
  1053. // unique. User is prompted to enter a new name if this is not
  1054. // the case.
  1055. //
  1056. // Arguments:
  1057. // hwndDlg [in] Parent window
  1058. // bIsUnattended Do not pop up dialog box to ask for computer name
  1059. // - rather generate a random unique name.
  1060. //
  1061. // Returns: Nothing
  1062. //
  1063. // Author: danielwe 16 Feb 1999
  1064. //
  1065. // Notes: Workstation service is stopped and restarted when new name is
  1066. // entered so the change can take effect and domain join can
  1067. // succeed.
  1068. //
  1069. VOID EnsureUniqueComputerName(HWND hwndDlg, BOOL bIsUnattended)
  1070. {
  1071. TraceFileFunc(ttidGuiModeSetup);
  1072. NET_API_STATUS nas;
  1073. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1074. DWORD cchName = celems(szComputerName);
  1075. NAME_DATA nd = {0};
  1076. if (GetComputerNameEx(ComputerNameNetBIOS,
  1077. reinterpret_cast<PWSTR>(&szComputerName),
  1078. &cchName))
  1079. {
  1080. CServiceManager sm;
  1081. CService service;
  1082. BOOL fRestart = FALSE;
  1083. DWORD dwState;
  1084. // Open the workstation service and figure out if it is running. If
  1085. // so we'll need to stop it and note that we need to restart it when
  1086. // we're done verifying the computer name.
  1087. //
  1088. if (SUCCEEDED(sm.HrOpenService(&service, c_szSvcWorkstation)))
  1089. {
  1090. if (SUCCEEDED(service.HrQueryState(&dwState)) &&
  1091. (dwState == SERVICE_RUNNING))
  1092. {
  1093. TraceTag(ttidWizard, "Stopping workstation service...");
  1094. (VOID) sm.HrStopServiceAndWait(c_szSvcWorkstation);
  1095. fRestart = TRUE;
  1096. }
  1097. }
  1098. // NetValidateName() should work without the workstation service
  1099. // being started. In fact, it *has* to work like this because otherwise
  1100. // the machine will find itself as a duplicate name.. Not good.
  1101. //
  1102. DWORD dwNumTries = 10;
  1103. do
  1104. {
  1105. nas = NetValidateName(NULL, szComputerName, NULL, NULL,
  1106. NetSetupMachine);
  1107. if (nas == ERROR_DUP_NAME)
  1108. {
  1109. INT irt;
  1110. TraceTag(ttidWizard, "Displaying UI to change duplicate computer "
  1111. "name %S.", szComputerName);
  1112. nd.pszComputerName = szComputerName;
  1113. if (!bIsUnattended)
  1114. {
  1115. irt = DialogBoxParam(_Module.GetResourceInstance(),
  1116. MAKEINTRESOURCE(IDD_Duplicate_Name),
  1117. hwndDlg,
  1118. (DLGPROC)DuplicateNameProc,
  1119. (LPARAM)&nd);
  1120. }
  1121. else
  1122. {
  1123. WCHAR szOldComputerName[MAX_COMPUTERNAME_LENGTH+1];
  1124. wcsncpy(szOldComputerName, szComputerName, MAX_COMPUTERNAME_LENGTH);
  1125. GenerateComputerNameBasedOnOrganizationName(szComputerName, MAX_COMPUTERNAME_LENGTH);
  1126. NetSetupLogStatusV( LogSevError,
  1127. SzLoadIds (IDS_E_UNATTENDED_COMPUTER_NAME_CHANGED),
  1128. szOldComputerName, szComputerName
  1129. );
  1130. LowerCaseComputerName(szComputerName);
  1131. if (!SetComputerNameEx(ComputerNamePhysicalDnsHostname, szComputerName))
  1132. {
  1133. TraceLastWin32Error("SetComputerNameEx");
  1134. }
  1135. else
  1136. {
  1137. (VOID)HrSetActiveComputerName(NULL);
  1138. TraceTag(ttidWizard, "Setting new computer name %S.", szComputerName);
  1139. }
  1140. }
  1141. }
  1142. else
  1143. {
  1144. TraceTag(ttidWizard, "Name is already unique.");
  1145. // Restart the workstation service if necessary.
  1146. //
  1147. if (fRestart)
  1148. {
  1149. TraceTag(ttidWizard, "Restarting Workstation service...");
  1150. (VOID) sm.HrStartServiceAndWait(c_szSvcWorkstation);
  1151. }
  1152. }
  1153. } while ( (ERROR_DUP_NAME == nas) && (dwNumTries--) && (bIsUnattended) );
  1154. }
  1155. else
  1156. {
  1157. TraceLastWin32Error("EnsureUniqueComputerName - GetComputerNameEx");
  1158. }
  1159. }
  1160. //+---------------------------------------------------------------------------
  1161. //
  1162. // Function: ValidateNetBiosName
  1163. //
  1164. // Purpose: Ensures that the computer name is a valid DNS name e.g. when
  1165. // upgrading from a previous O/S. If not it logs an error to the
  1166. // setuperr.log
  1167. //
  1168. // Arguments: nothing
  1169. //
  1170. // Returns: S_OK if valid
  1171. // S_FALSE if invalid
  1172. // E_FAIL if failed
  1173. //
  1174. // Author: deonb 2 May 2000
  1175. //
  1176. // Notes:
  1177. HRESULT ValidateNetBiosName()
  1178. {
  1179. TraceFileFunc(ttidGuiModeSetup);
  1180. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1181. DWORD cchName = celems(szComputerName);
  1182. if (GetComputerNameEx(ComputerNameNetBIOS,
  1183. reinterpret_cast<PWSTR>(&szComputerName),
  1184. &cchName))
  1185. {
  1186. DNS_STATUS dnsStatus = DnsValidateName(szComputerName, DnsNameHostnameLabel);
  1187. switch (dnsStatus)
  1188. {
  1189. case ERROR_SUCCESS:
  1190. return S_OK;
  1191. case ERROR_INVALID_NAME:
  1192. NetSetupLogStatusV( LogSevError,
  1193. SzLoadIds (IDS_E_UPGRADE_DNS_INVALID_NAME));
  1194. return S_FALSE;
  1195. case DNS_ERROR_INVALID_NAME_CHAR:
  1196. NetSetupLogStatusV( LogSevError,
  1197. SzLoadIds (IDS_E_UPGRADE_DNS_INVALID_NAME_CHAR));
  1198. return S_FALSE;
  1199. case DNS_ERROR_NON_RFC_NAME:
  1200. NetSetupLogStatusV( LogSevError,
  1201. SzLoadIds (IDS_E_UPGRADE_DNS_INVALID_NAME_NONRFC));
  1202. return S_FALSE;
  1203. default:
  1204. TraceError("ValidateComputerName - DnsValidateName", dnsStatus);
  1205. return E_FAIL;
  1206. }
  1207. }
  1208. else
  1209. {
  1210. TraceLastWin32Error("ValidateComputerName - GetComputerNameEx");
  1211. return E_FAIL;
  1212. }
  1213. }
  1214. //
  1215. // Function: HrSetupGetSourceInfo
  1216. //
  1217. // Purpose: Allocates, gets, and returns the required Setup info
  1218. //
  1219. // Parameters: hinf [IN] - setup hinf handle
  1220. // SrcId [IN] - source id obtained from setup
  1221. // InfoDesired [IN] - indicates what info is desired
  1222. // ppsz [OUT] - ptr to string to be filled and returned
  1223. //
  1224. // Returns: HRESULT
  1225. //
  1226. HRESULT
  1227. HrSetupGetSourceInfo(
  1228. IN HINF hinf,
  1229. IN UINT SrcId,
  1230. IN UINT InfoDesired,
  1231. OUT PWSTR * ppsz)
  1232. {
  1233. TraceFileFunc(ttidGuiModeSetup);
  1234. Assert(hinf);
  1235. Assert(SRCINFO_PATH == InfoDesired ||
  1236. SRCINFO_TAGFILE == InfoDesired ||
  1237. SRCINFO_DESCRIPTION == InfoDesired);
  1238. Assert(ppsz);
  1239. HRESULT hr = S_OK;
  1240. ULONG cch;
  1241. // first get the size of the string required
  1242. //
  1243. if (SetupGetSourceInfo(hinf, SrcId, InfoDesired, NULL, 0, &cch))
  1244. {
  1245. // now get the required info
  1246. //
  1247. *ppsz = (PWSTR) MemAlloc(cch * sizeof (WCHAR));
  1248. if (*ppsz)
  1249. {
  1250. if (!SetupGetSourceInfo(hinf, SrcId, InfoDesired, *ppsz, cch, NULL))
  1251. {
  1252. MemFree(*ppsz);
  1253. hr = HRESULT_FROM_WIN32(GetLastError());
  1254. }
  1255. }
  1256. else
  1257. {
  1258. hr = E_OUTOFMEMORY;
  1259. }
  1260. }
  1261. else
  1262. {
  1263. hr = HRESULT_FROM_WIN32(GetLastError());
  1264. }
  1265. return hr;
  1266. }
  1267. //
  1268. // Function: UpgradeEtcServicesFile
  1269. //
  1270. // Purpose: Performs upgrade of %windir%\system32\drivers\etc\services file
  1271. //
  1272. // Parameters: pWizard [IN] - wizard info
  1273. //
  1274. // Returns: void
  1275. //
  1276. VOID
  1277. UpgradeEtcServicesFile(CWizard * pWizard)
  1278. {
  1279. TraceFileFunc(ttidGuiModeSetup);
  1280. // find etc\services file, and get size and other data
  1281. // compare size/date etc and decide if we should upgrade it.
  1282. HRESULT hr = S_OK;
  1283. DWORD status;
  1284. BOOL fShouldUpgradeIt = FALSE;
  1285. WCHAR szWindowsDir[MAX_PATH+1];
  1286. tstring strServices;
  1287. static const WCHAR c_szServicesFile[] = L"\\system32\\drivers\\etc\\services";
  1288. static const WCHAR c_szServicesDirSuffix[] = L"\\system32\\drivers\\etc";
  1289. static const DWORD c_dwNT4ServicesFileSize = 6007;
  1290. DWORD cNumCharsReturned = GetSystemWindowsDirectory(szWindowsDir, MAX_PATH);
  1291. if (cNumCharsReturned)
  1292. {
  1293. HANDLE hFile;
  1294. strServices = szWindowsDir;
  1295. strServices += c_szServicesFile;
  1296. // see if file exists
  1297. hFile = CreateFile(strServices.c_str(),
  1298. GENERIC_READ,
  1299. 0,
  1300. NULL,
  1301. OPEN_EXISTING,
  1302. 0,
  1303. NULL);
  1304. if (hFile)
  1305. {
  1306. // get attributes
  1307. DWORD dwSize = GetFileSize(hFile, NULL);
  1308. if (c_dwNT4ServicesFileSize == dwSize)
  1309. {
  1310. fShouldUpgradeIt = TRUE;
  1311. }
  1312. CloseHandle(hFile);
  1313. }
  1314. else
  1315. {
  1316. TraceTag(ttidWizard, "services files doesn't exist");
  1317. }
  1318. }
  1319. else
  1320. {
  1321. hr = HrFromLastWin32Error();
  1322. }
  1323. static const WCHAR c_szServices[] = L"services";
  1324. //
  1325. // copy over new services file if required
  1326. //
  1327. if (S_OK == hr && fShouldUpgradeIt)
  1328. {
  1329. // copy the file
  1330. //
  1331. HSPFILEQ q = NULL;
  1332. HINF hinf = NULL;
  1333. UINT SrcId;
  1334. PWSTR pszTagInfo = NULL;
  1335. PWSTR pszDescription = NULL;
  1336. tstring strServicesDir = szWindowsDir;
  1337. PVOID pCtx = NULL;
  1338. q = SetupOpenFileQueue();
  1339. if (!q)
  1340. {
  1341. TraceTag(ttidWizard, "SetupOpenFileQueue failed");
  1342. goto cleanup;
  1343. }
  1344. // we need the location of services._ (the compressed file)
  1345. // first open layout.inf
  1346. //
  1347. hinf = SetupOpenMasterInf();
  1348. if (!hinf)
  1349. {
  1350. TraceTag(ttidWizard, "Failed to open layout.inf");
  1351. goto cleanup;
  1352. }
  1353. // get size of needed buffer
  1354. //
  1355. if (!SetupGetSourceFileLocation(hinf, NULL, c_szServices, &SrcId, NULL, 0, NULL))
  1356. {
  1357. TraceTag(ttidWizard, "SetupGetSourceFileLocation failed.");
  1358. goto cleanup;
  1359. }
  1360. // get TagInfo
  1361. //
  1362. if (S_OK != HrSetupGetSourceInfo(hinf, SrcId, SRCINFO_TAGFILE, &pszTagInfo))
  1363. {
  1364. TraceTag(ttidWizard, "Failed to get TagInfo for services file.");
  1365. goto cleanup;
  1366. }
  1367. // get Description
  1368. //
  1369. if (S_OK != HrSetupGetSourceInfo(hinf, SrcId, SRCINFO_DESCRIPTION, &pszDescription))
  1370. {
  1371. TraceTag(ttidWizard, "Failed to get Description for services file.");
  1372. goto cleanup;
  1373. }
  1374. // now copy the file using this info
  1375. //
  1376. strServicesDir += c_szServicesDirSuffix;
  1377. if (!SetupQueueCopy(q,
  1378. pWizard->PSetupData()->LegacySourcePath,
  1379. NULL, // don't need this since LegacySourcePath covers it
  1380. c_szServices,
  1381. pszDescription,
  1382. pszTagInfo,
  1383. strServicesDir.c_str(),
  1384. NULL,
  1385. SP_COPY_REPLACEONLY))
  1386. {
  1387. TraceTag(ttidWizard, "SetupQueueCopy failed");
  1388. goto cleanup;
  1389. }
  1390. pCtx = SetupInitDefaultQueueCallbackEx(NULL,
  1391. static_cast<HWND>(INVALID_HANDLE_VALUE),
  1392. 0, 0, NULL);
  1393. if (!pCtx)
  1394. {
  1395. TraceTag(ttidWizard, "SetupInitDefaultQueueCallbackEx failed.");
  1396. goto cleanup;
  1397. }
  1398. if (!SetupCommitFileQueue(NULL, q, &SetupDefaultQueueCallback, pCtx))
  1399. {
  1400. TraceTag(ttidWizard, "SetupCommitFileQueue failed, "
  1401. "did not copy over new services file");
  1402. goto cleanup;
  1403. }
  1404. // success!
  1405. TraceTag(ttidWizard, "Copied over new services file");
  1406. cleanup:
  1407. if (pCtx)
  1408. {
  1409. SetupTermDefaultQueueCallback(pCtx);
  1410. }
  1411. MemFree(pszDescription);
  1412. MemFree(pszTagInfo);
  1413. if (hinf)
  1414. {
  1415. SetupCloseInfFile(hinf);
  1416. }
  1417. if (q)
  1418. {
  1419. SetupCloseFileQueue(q);
  1420. }
  1421. }
  1422. }
  1423. void FixWmiServiceDependencies(
  1424. const WCHAR *ServiceName
  1425. );
  1426. extern BOOL WINAPI FNetSetupApplySysPrep();
  1427. //
  1428. // Function: InstallUpgradeWorkThrd
  1429. //
  1430. // Purpose: Perform an network install or upgrade as appropriate
  1431. //
  1432. // Parameters: pitp [IN] - Thread data
  1433. //
  1434. // Returns: DWORD, Zero always
  1435. //
  1436. EXTERN_C
  1437. DWORD
  1438. InstallUpgradeWorkThrd (
  1439. InitThreadParam* pitp)
  1440. {
  1441. TraceFileFunc(ttidGuiModeSetup);
  1442. BOOL fUninitCOM = FALSE;
  1443. BOOL fLockSCM = FALSE;
  1444. HRESULT hr = S_OK;
  1445. UINT uMsg = PWM_EXIT;
  1446. CServiceManager scm;
  1447. const WCHAR szISACTRL[] = L"ISACTRL";
  1448. TraceTag(ttidWizard, "Entering InstallUpgradeWorkThrd...");
  1449. Assert(!IsPostInstall(pitp->pWizard));
  1450. Assert(pitp->pWizard->PNetCfg());
  1451. #if DBG
  1452. if (FIsDebugFlagSet (dfidBreakOnStartOfUpgrade))
  1453. {
  1454. AssertSz(FALSE, "THIS IS NOT A BUG! The debug flag "
  1455. "\"BreakOnStartOfUpgrade\" has been set. Set your breakpoints now.");
  1456. }
  1457. #endif // DBG
  1458. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 10);
  1459. // If this is in Mini-Setup mode, we will try to restore adapter specific parameters
  1460. // saved for SysPrep operation. This has to be done before the normal Answer-File processing.
  1461. // There is nothing we can do with any error here, so any error is ignored.
  1462. if ( (pitp->pWizard->PSetupData())->OperationFlags & SETUPOPER_MINISETUP )
  1463. {
  1464. FNetSetupApplySysPrep();
  1465. }
  1466. TraceTag(ttidWizard, "Waiting on Service Controller");
  1467. // Wait until service controller can be locked
  1468. //
  1469. if (SUCCEEDED(scm.HrOpen()))
  1470. {
  1471. while (!fLockSCM)
  1472. {
  1473. if (SUCCEEDED(scm.HrLock()))
  1474. {
  1475. fLockSCM = TRUE;
  1476. scm.Unlock();
  1477. break;
  1478. }
  1479. Sleep( 500 );
  1480. }
  1481. }
  1482. //
  1483. // Fixup ISA service which has a dependency on the WMI
  1484. // extensions to WDM service that needs to be removed
  1485. //
  1486. FixWmiServiceDependencies(szISACTRL);
  1487. // Initialize COM on this thread
  1488. //
  1489. hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
  1490. if (FAILED(hr))
  1491. {
  1492. TraceTag(ttidWizard, "Failed to initialize COM upgrade work thread");
  1493. goto Done;
  1494. }
  1495. else
  1496. {
  1497. // Remember to uninitialize COM on thread exit
  1498. fUninitCOM = TRUE;
  1499. }
  1500. #if DBG
  1501. RtlValidateProcessHeaps ();
  1502. #endif
  1503. if (!IsUpgrade(pitp->pWizard))
  1504. {
  1505. // Make sure the computer name is the same for both intended and active
  1506. TraceTag(ttidWizard, "Setting Active Computer Name");
  1507. (VOID)HrSetActiveComputerName(NULL);
  1508. }
  1509. // Synchronize the SAM database
  1510. //
  1511. SyncSAM(pitp->pWizard);
  1512. // Retrieve NetDevice info for later use
  1513. //
  1514. NetDevRetrieveInfo(pitp->pWizard);
  1515. // Do answer file processing if it is unattended mode.
  1516. //
  1517. if (IsUnattended(pitp->pWizard))
  1518. {
  1519. hr = HrInitForUnattendedNetSetup(
  1520. pitp->pWizard->PNetCfg(),
  1521. pitp->pWizard->PSetupData());
  1522. }
  1523. else if ( IsUpgrade(pitp->pWizard) )
  1524. {
  1525. // Attended upgrade is really a repair mode.
  1526. hr = HrInitForRepair();
  1527. }
  1528. // Join the default workgroup if necessary
  1529. //
  1530. if (!IsUpgrade(pitp->pWizard))
  1531. {
  1532. // Join the default workgroup only fresh install
  1533. TraceTag(ttidWizard, "Joining Default Workgroup");
  1534. JoinDefaultWorkgroup(pitp->pWizard, pitp->hwndDlg);
  1535. }
  1536. // Now process any problems in loading netcfg
  1537. //
  1538. if (NETSETUP_E_ANS_FILE_ERROR == hr)
  1539. {
  1540. // $REVIEW - LogError ?
  1541. // Disable unattended for networking
  1542. //
  1543. pitp->pWizard->DisableUnattended();
  1544. TraceTag(ttidWizard, "Error In answer file, installing default networking");
  1545. goto InstallDefNetworking;
  1546. }
  1547. else if (NETSETUP_E_NO_ANSWERFILE == hr)
  1548. {
  1549. // $REVIEW(tongl, 4/6/99): Raid #310599, if we are in mini-setup, then
  1550. // do attended install if no networking section is specified
  1551. HKEY hkeySetup = NULL;
  1552. HRESULT hrReg = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1553. c_szSystemSetupKey,
  1554. KEY_READ,
  1555. &hkeySetup);
  1556. if (SUCCEEDED(hrReg))
  1557. {
  1558. DWORD dw;
  1559. hrReg = HrRegQueryDword(hkeySetup, c_szMiniSetupInProgress, &dw);
  1560. RegCloseKey(hkeySetup);
  1561. }
  1562. if (SUCCEEDED(hrReg))
  1563. {
  1564. pitp->pWizard->DisableUnattended();
  1565. TraceTag(ttidWizard, "Mini-setup with no networking section, do attended install");
  1566. goto InstallDefNetworking;
  1567. }
  1568. else
  1569. {
  1570. // Per Raid 199750 - Install default networking when no
  1571. // networking is present.
  1572. //
  1573. TraceTag(ttidWizard, "No network answer file section, minimal network component setup");
  1574. InstallDefaultComponents(pitp->pWizard, EDC_DEFAULT, pitp->hwndDlg);
  1575. goto SkipNetworkComponentInstall;
  1576. }
  1577. }
  1578. else if (FAILED(hr))
  1579. {
  1580. // $REVIEW - logerror
  1581. TraceTag(ttidWizard, "Unexpected Error: 0x%08X",(DWORD)hr);
  1582. pitp->pWizard->SetExitNoReturn();
  1583. goto Done;
  1584. }
  1585. if (!IsUpgrade(pitp->pWizard) && !IsUnattended(pitp->pWizard))
  1586. { // Attended install
  1587. InstallDefNetworking:
  1588. StartSpooler();
  1589. if (IsFreshInstall(pitp->pWizard))
  1590. {
  1591. InstallDefaultComponents(pitp->pWizard, EDC_DEFAULT, pitp->hwndDlg);
  1592. }
  1593. }
  1594. else
  1595. { // Unattended install or upgrade
  1596. //
  1597. HRESULT hr2;
  1598. EPageDisplayMode i;
  1599. BOOL j;
  1600. Assert(NULL != pitp->pWizard->PNetCfg());
  1601. StartSpooler();
  1602. // Upgrade installed components
  1603. //
  1604. TraceTag(ttidWizard, "Processing installed adapters...");
  1605. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 15);
  1606. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1607. UAW_NetAdapters, &i, &j);
  1608. TraceHr(ttidWizard, FAL, hr2, FALSE, "Processing installed adapters failed.");
  1609. TraceTag(ttidWizard, "Upgrading Installed Protocols...");
  1610. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 25);
  1611. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1612. UAW_NetProtocols, &i, &j);
  1613. TraceHr(ttidWizard, FAL, hr2, FALSE, "Upgrading Installed Protocols failed.");
  1614. TraceTag(ttidWizard, "Upgrading Installed Clients...");
  1615. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 40);
  1616. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1617. UAW_NetClients, &i, &j);
  1618. TraceHr(ttidWizard, FAL, hr2, FALSE, "Upgrading Installed Clients failed.");
  1619. TraceTag(ttidWizard, "Upgrading Installed Services...");
  1620. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 55);
  1621. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1622. UAW_NetServices, &i, &j);
  1623. TraceHr(ttidWizard, FAL, hr2, FALSE, "Upgrading Installed Services failed.");
  1624. TraceTag(ttidWizard, "Restoring pre-upgrade bindings...");
  1625. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 70);
  1626. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1627. UAW_NetBindings, &i, &j);
  1628. TraceHr(ttidWizard, FAL, hr2, FALSE, "Restoring pre-upgrade bindings failed.");
  1629. TraceTag(ttidWizard, "Removing unsupported components...");
  1630. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, 85);
  1631. hr2 = HrDoUnattend(pitp->hwndDlg, pitp->pWizard->PNetCfg(),
  1632. UAW_RemoveNetComponents, &i, &j);
  1633. TraceHr(ttidWizard, FAL, hr2, FALSE, "Removing unsupported components failed.");
  1634. // If we are upgrading and have an answerfile, update lana
  1635. // configuration using the information in the file.
  1636. // Note: This must be done after all the components have been
  1637. // installed (Upgraded), so that all the bindings are present
  1638. // when we update hte configuration.
  1639. //
  1640. if (IsUpgrade (pitp->pWizard) && IsUnattended (pitp->pWizard) &&
  1641. (S_OK == pitp->pWizard->PNetCfg()->FindComponent (
  1642. c_szInfId_MS_NetBIOS, NULL)))
  1643. {
  1644. PWSTR pszAnswerFile;
  1645. PWSTR pszAnswerSection;
  1646. hr = HrGetAnswerFileParametersForComponent (c_szInfId_MS_NetBIOS,
  1647. &pszAnswerFile, &pszAnswerSection);
  1648. if (S_OK == hr)
  1649. {
  1650. NC_TRY
  1651. {
  1652. UpdateLanaConfigUsingAnswerfile (pszAnswerFile,
  1653. pszAnswerSection);
  1654. }
  1655. NC_CATCH_ALL
  1656. {
  1657. TraceTag (ttidWizard, "Possible delayload failure of "
  1658. "netcfgx dll while trying to update lana "
  1659. "information.");
  1660. }
  1661. CoTaskMemFree (pszAnswerFile);
  1662. CoTaskMemFree (pszAnswerSection);
  1663. }
  1664. // We can't let the error stop us.
  1665. hr = S_OK;
  1666. }
  1667. // Install networking, if no networking is present. "no networking"
  1668. // means no visible LAN-enabled protocol installed.
  1669. //
  1670. // First try to install default components as opposed to
  1671. // mandatory components because TCP/IP is both mandatory
  1672. // and default. So, if we install mandatory first then,
  1673. // default components will never be installed as TCP/IP is
  1674. // a visible LAN-enabled protocol.
  1675. // Raid bug 337827
  1676. InstallDefaultComponentsIfNeeded(pitp->pWizard);
  1677. // Install mandatory components.
  1678. InstallDefaultComponents(pitp->pWizard, EDC_MANDATORY, pitp->hwndDlg);
  1679. // Special Case. Need an extra OBOUser ref-count for File and Print
  1680. // when upgrading from NT3.51 or NT4 and GSNW is installed. This is
  1681. // because ref-counting didn't exist pre-NT5
  1682. //
  1683. OBOUserAddRefSpecialCase(pitp->pWizard);
  1684. #if DBG
  1685. if (FIsDebugFlagSet (dfidBreakOnEndOfUpgrade))
  1686. {
  1687. AssertSz(FALSE, "THIS IS NOT A BUG! The debug flag "
  1688. "\"BreakOnEndOfUpgrade\" has been set. Set your breakpoints now.");
  1689. }
  1690. #endif // DBG
  1691. }
  1692. // Convert any components which were OC and are now regular networking components
  1693. //
  1694. if (IsUpgrade(pitp->pWizard))
  1695. {
  1696. FixupOldOcComponents(pitp->pWizard);
  1697. }
  1698. //
  1699. // Upgrade system32\drivers\etc\services file if necessary
  1700. //
  1701. if (IsUpgrade(pitp->pWizard))
  1702. {
  1703. UpgradeEtcServicesFile(pitp->pWizard);
  1704. }
  1705. SkipNetworkComponentInstall:
  1706. OnUpgradeUpdateProgressCap(pitp->hwndDlg, pitp->pWizard, c_nMaxProgressRange);
  1707. // Commit any changes
  1708. //
  1709. (VOID)HrCommitINetCfgChanges(GetParent(pitp->hwndDlg), pitp->pWizard);
  1710. // Add unbound LAN adapters to the processing queue. For ATM this will
  1711. // have the side effect of creating virtual LAN adapters but not creating
  1712. // the connections associated with them
  1713. //
  1714. Assert(pitp->pWizard->FProcessLanPages());
  1715. (VOID)pitp->pWizard->PAdapterQueue()->HrQueryUnboundAdapters(pitp->pWizard);
  1716. // Commit the changes caused by processing the unbound adapters
  1717. //
  1718. (VOID)HrCommitINetCfgChanges(GetParent(pitp->hwndDlg), pitp->pWizard);
  1719. // Now for the ATM case create connections for the virtual LAN adapters
  1720. // and commit the changes
  1721. //
  1722. (VOID)pitp->pWizard->PAdapterQueue()->HrQueryUnboundAdapters(pitp->pWizard);
  1723. (VOID)HrCommitINetCfgChanges(GetParent(pitp->hwndDlg), pitp->pWizard);
  1724. uMsg = PWM_PROCEED;
  1725. Done:
  1726. // Shutdown the progress timer if it's not already stopped
  1727. //
  1728. {
  1729. LPARAM lParam = pitp->pWizard->GetPageData(IDD_Upgrade);
  1730. Assert(lParam);
  1731. UpgradeData * pData = reinterpret_cast<UpgradeData *>(lParam);
  1732. ::KillTimer(pitp->hwndDlg, c_uiUpgradeRefreshID);
  1733. // Set the progress indicator to its full position
  1734. //
  1735. HWND hwndProgress = GetDlgItem(pitp->hwndDlg, IDC_UPGRADE_PROGRESS);
  1736. SendMessage(hwndProgress, PBM_SETPOS,
  1737. c_nMaxProgressRange, 0);
  1738. UpdateWindow(hwndProgress);
  1739. }
  1740. // Uninitialize COM for this thread
  1741. //
  1742. if (fUninitCOM)
  1743. {
  1744. CoUninitialize();
  1745. }
  1746. EnsureUniqueComputerName(pitp->hwndDlg, IsUnattended(pitp->pWizard));
  1747. ValidateNetBiosName();
  1748. PostMessage(pitp->hwndDlg, uMsg, (WPARAM)0, (LPARAM)0);
  1749. delete pitp;
  1750. #if DBG
  1751. RtlValidateProcessHeaps ();
  1752. #endif
  1753. TraceTag(ttidWizard, "Leaving InstallUpgradeWorkThrd...");
  1754. return 0;
  1755. }
  1756. //
  1757. // Function: OnUpgradePageActivate
  1758. //
  1759. // Purpose: Handle the PSN_SETACTIVE notification by either: Creating a
  1760. // thread to process install/upgrade requirements or to just
  1761. // deny activation of the page.
  1762. //
  1763. // Parameters: hwndDlg [IN] - Handle to the upgrade child dialog
  1764. //
  1765. // Returns: BOOL, TRUE on success
  1766. //
  1767. BOOL OnUpgradePageActivate( HWND hwndDlg )
  1768. {
  1769. TraceFileFunc(ttidGuiModeSetup);
  1770. // Retrieve the CWizard instance from the dialog
  1771. CWizard * pWizard =
  1772. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  1773. Assert(NULL != pWizard);
  1774. // Retrieve the page data stashed within the wizard for this page
  1775. LPARAM lParam = pWizard->GetPageData(IDD_Upgrade);
  1776. Assert(lParam);
  1777. UpgradeData * pData = reinterpret_cast<UpgradeData *>(lParam);
  1778. if(!pData)
  1779. {
  1780. return false;
  1781. }
  1782. // Based on the page data decide whether focus is acceptable
  1783. if (pData->fProcessed)
  1784. {
  1785. // Accept focus
  1786. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0);
  1787. PAGEDIRECTION PageDir = pWizard->GetPageDirection(IDD_Upgrade);
  1788. if (NWPD_FORWARD == PageDir)
  1789. {
  1790. // Get to this page when the user navigates back and forth
  1791. // and we already processed InstallUpgradeWorkThrd
  1792. if (g_pSetupWizard != NULL)
  1793. {
  1794. g_pSetupWizard->PSetupData()->ShowHideWizardPage(TRUE);
  1795. }
  1796. pWizard->SetPageDirection(IDD_Upgrade, NWPD_BACKWARD);
  1797. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
  1798. }
  1799. else
  1800. {
  1801. // if there are any adapters previous to the current in the queue
  1802. // jump to them before accepting focus here
  1803. if (!OnProcessPrevAdapterPagePrev(hwndDlg, 0))
  1804. {
  1805. pWizard->SetPageDirection(IDD_Upgrade, NWPD_FORWARD);
  1806. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
  1807. }
  1808. }
  1809. }
  1810. else
  1811. {
  1812. HANDLE hthrd;
  1813. DWORD dwThreadId = 0;
  1814. PropSheet_SetWizButtons( GetParent( hwndDlg ), 0);
  1815. TraceTag(ttidWizard,"Upgrade/Install Page commencing");
  1816. // Install the Asyncmac software-enumerated device.
  1817. // Important to do this before the INetCfg lock is obtained, because
  1818. // the installation of this device causes or class installer to be
  1819. // invoked which needs to get its own lock to process the installation.
  1820. //
  1821. static const GUID DEVICE_GUID_ASYNCMAC =
  1822. {0xeeab7790,0xc514,0x11d1,{0xb4,0x2b,0x00,0x80,0x5f,0xc1,0x27,0x0e}};
  1823. (VOID) HrInstallSoftwareDeviceOnInterface (
  1824. &DEVICE_GUID_ASYNCMAC,
  1825. &GUID_NDIS_LAN_CLASS,
  1826. L"asyncmac",
  1827. TRUE, // force installation since this happens during GUI mode.
  1828. L"netrasa.inf",
  1829. hwndDlg);
  1830. // Not processed yet, spin up the thread to do the Install/Upgrade
  1831. pData->fProcessed = TRUE;
  1832. ::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0);
  1833. InitThreadParam * pitp = new InitThreadParam;
  1834. HRESULT hr = S_OK;
  1835. if(pitp)
  1836. {
  1837. pitp->hwndDlg = hwndDlg;
  1838. pitp->pWizard = pWizard;
  1839. TraceTag(ttidWizard, "Creating INetCfg Instance");
  1840. hr = HrInitAndGetINetCfg(pitp->pWizard);
  1841. }
  1842. else
  1843. {
  1844. hr = E_OUTOFMEMORY;
  1845. }
  1846. if (SUCCEEDED(hr))
  1847. {
  1848. // We are installing and only show progress, hide the page
  1849. if (g_pSetupWizard != NULL)
  1850. {
  1851. g_pSetupWizard->PSetupData()->ShowHideWizardPage(FALSE);
  1852. }
  1853. // Create the work thread
  1854. hthrd = CreateThread( NULL, STACK_SIZE_TINY,
  1855. (LPTHREAD_START_ROUTINE)InstallUpgradeWorkThrd,
  1856. (LPVOID)pitp, 0, &dwThreadId );
  1857. if (NULL != hthrd)
  1858. {
  1859. CloseHandle( hthrd );
  1860. }
  1861. else
  1862. {
  1863. hr = HRESULT_FROM_WIN32(GetLastError());
  1864. Assert(hr);
  1865. // Kill the timer we created since the thread won't be around
  1866. // to kill it for us.
  1867. //
  1868. ::KillTimer(hwndDlg, c_uiUpgradeRefreshID);
  1869. }
  1870. }
  1871. if (FAILED(hr) || (NULL == hthrd))
  1872. {
  1873. // Failed to create the required netsetup thread
  1874. delete pitp;
  1875. AssertSz(0,"Unable to create netsetup thread.");
  1876. TraceHr(ttidWizard, FAL, hr, FALSE, "OnUpgradePageActivate - Create thread failed");
  1877. pWizard->SetExitNoReturn();
  1878. PostMessage(hwndDlg, PWM_EXIT, (WPARAM)0, (LPARAM)0);
  1879. }
  1880. }
  1881. return( TRUE );
  1882. }
  1883. //
  1884. // Function: OnUpgradePageExit
  1885. //
  1886. // Purpose: Handle the PWN_EXIT notification
  1887. //
  1888. // Parameters: hwndDlg [IN] - Handle to the upgrade child dialog
  1889. //
  1890. // Returns: BOOL, TRUE if the action was processed internally
  1891. //
  1892. BOOL OnUpgradePageExit( HWND hwndDlg )
  1893. {
  1894. TraceFileFunc(ttidGuiModeSetup);
  1895. // Retrieve the CWizard instance from the dialog
  1896. CWizard * pWizard =
  1897. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  1898. Assert(NULL != pWizard);
  1899. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  1900. // goto the exit page
  1901. HPROPSHEETPAGE hPage = pWizard->GetPageHandle(IDD_Exit);
  1902. PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0,
  1903. (LPARAM)(HPROPSHEETPAGE)hPage);
  1904. return (TRUE);
  1905. }
  1906. //
  1907. // Function: OnUpgradePageProceed
  1908. //
  1909. // Purpose: Handle the PWN_PROCEED notification
  1910. //
  1911. // Parameters: hwndDlg [IN] - Handle to the upgrade child dialog
  1912. //
  1913. // Returns: BOOL, TRUE if the action was processed internally
  1914. //
  1915. BOOL OnUpgradePageProceed( HWND hwndDlg )
  1916. {
  1917. TraceFileFunc(ttidGuiModeSetup);
  1918. int nIdx;
  1919. int rgIdcShow[] = { BTN_UPGRADE_TYPICAL, BTN_UPGRADE_CUSTOM,
  1920. TXT_UPGRADE_TYPICAL_1, TXT_UPGRADE_CUSTOM_1,
  1921. TXT_UPGRADE_INSTRUCTIONS};
  1922. int rgIdcShowWorkstation[] = { BTN_UPGRADE_TYPICAL, BTN_UPGRADE_CUSTOM,
  1923. TXT_UPGRADE_TYPICAL_1_WS, TXT_UPGRADE_CUSTOM_1,
  1924. TXT_UPGRADE_INSTRUCTIONS};
  1925. int rgIdcHide[] = {TXT_UPGRADE_WAIT, IDC_UPGRADE_PROGRESS};
  1926. PRODUCT_FLAVOR pf;
  1927. GetProductFlavor(NULL, &pf);
  1928. // Retrieve the CWizard instance from the dialog
  1929. CWizard * pWizard =
  1930. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  1931. Assert(NULL != pWizard);
  1932. // Expose the typical/custom controls on the upgrade page
  1933. // and hide the "working" controls unless there are no adapters
  1934. //
  1935. if (pWizard->PAdapterQueue()->FAdaptersInstalled())
  1936. {
  1937. for (nIdx=0; nIdx < celems(rgIdcHide); nIdx++)
  1938. ShowWindow(GetDlgItem(hwndDlg, rgIdcHide[nIdx]), SW_HIDE);
  1939. if (PF_WORKSTATION == pf)
  1940. {
  1941. for (nIdx=0; nIdx < celems(rgIdcShowWorkstation); nIdx++)
  1942. ShowWindow(GetDlgItem(hwndDlg, rgIdcShowWorkstation[nIdx]), SW_SHOW);
  1943. }
  1944. else
  1945. {
  1946. for (nIdx=0; nIdx < celems(rgIdcShow); nIdx++)
  1947. ShowWindow(GetDlgItem(hwndDlg, rgIdcShow[nIdx]), SW_SHOW);
  1948. }
  1949. }
  1950. ::SetFocus(GetDlgItem(hwndDlg, BTN_UPGRADE_TYPICAL));
  1951. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
  1952. // If upgrading, or we're in one of the interesting unattended mode,
  1953. // or there are no adapters or this is sbs version then automatically
  1954. // advance the UI in "typical" mode. In case of sbs, join page also
  1955. // advances automatically.
  1956. //
  1957. // SBS requires a static IP address for the LAN network card and the
  1958. // networking configuration is done in SBS setup.
  1959. if (IsUpgrade(pWizard) ||
  1960. !pWizard->PAdapterQueue()->FAdaptersInstalled() ||
  1961. (IsUnattended(pWizard) &&
  1962. ((UM_FULLUNATTENDED == pWizard->GetUnattendedMode()) ||
  1963. (UM_DEFAULTHIDE == pWizard->GetUnattendedMode()) ||
  1964. (UM_READONLY == pWizard->GetUnattendedMode()))) ||
  1965. IsSBS())
  1966. {
  1967. PostMessage(GetParent(hwndDlg), PSM_PRESSBUTTON, (WPARAM)(PSBTN_NEXT), 0);
  1968. }
  1969. else
  1970. {
  1971. // make sure the page is visible.
  1972. if (g_pSetupWizard != NULL)
  1973. {
  1974. g_pSetupWizard->PSetupData()->ShowHideWizardPage(TRUE);
  1975. g_pSetupWizard->PSetupData()->BillBoardSetProgressText(TEXT(""));
  1976. }
  1977. }
  1978. return (TRUE);
  1979. }
  1980. //
  1981. // Function: OnUpgradePageNext
  1982. //
  1983. // Purpose: Handle the PWN_WIZNEXT notification
  1984. //
  1985. // Parameters: hwndDlg [IN] - Handle to the upgrade child dialog
  1986. //
  1987. // Returns: BOOL, TRUE if the action was processed internally
  1988. //
  1989. BOOL OnUpgradePageNext(HWND hwndDlg)
  1990. {
  1991. TraceFileFunc(ttidGuiModeSetup);
  1992. // Retrieve the CWizard instance from the dialog
  1993. CWizard * pWizard =
  1994. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  1995. Assert(NULL != pWizard);
  1996. pWizard->SetPageDirection(IDD_Upgrade, NWPD_BACKWARD);
  1997. // Based on UI selection, hide or unhide new adapters
  1998. //
  1999. if (IsDlgButtonChecked(hwndDlg, BTN_UPGRADE_TYPICAL))
  2000. {
  2001. pWizard->PAdapterQueue()->HideAllAdapters();
  2002. }
  2003. else
  2004. {
  2005. pWizard->PAdapterQueue()->UnhideNewAdapters();
  2006. }
  2007. return OnProcessNextAdapterPageNext(hwndDlg, FALSE);
  2008. }
  2009. //
  2010. // Function: OnUpgradePagePrev
  2011. //
  2012. // Purpose: Handle the PWN_WIZBACK notification
  2013. //
  2014. // Parameters: hwndDlg [IN] - Handle to the upgrade child dialog
  2015. //
  2016. // Returns: BOOL, TRUE if the action was processed internally
  2017. //
  2018. BOOL OnUpgradePagePrev(HWND hwndDlg)
  2019. {
  2020. TraceFileFunc(ttidGuiModeSetup);
  2021. // Retrieve the CWizard instance from the dialog
  2022. CWizard * pWizard =
  2023. reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
  2024. Assert(NULL != pWizard);
  2025. pWizard->SetPageDirection(IDD_Upgrade, NWPD_FORWARD);
  2026. return FALSE;
  2027. }
  2028. //
  2029. // Function: OnUpgradeInitDialog
  2030. //
  2031. // Purpose: Handle the InitDialog message for the upgrade page
  2032. //
  2033. // Parameters: hwndDlg [IN] - Handle to the upgrade page window
  2034. // lParam [IN] - LPARAM value from the WM_INITDIALOG message
  2035. //
  2036. // Returns: FALSE (let the dialog proc set focus)
  2037. //
  2038. BOOL OnUpgradeInitDialog(HWND hwndDlg, LPARAM lParam)
  2039. {
  2040. TraceFileFunc(ttidGuiModeSetup);
  2041. // Initialize our pointers to property sheet info.
  2042. //
  2043. PROPSHEETPAGE* psp = (PROPSHEETPAGE*)lParam;
  2044. Assert(psp->lParam);
  2045. ::SetWindowLongPtr(hwndDlg, DWLP_USER, psp->lParam);
  2046. // Cast the property sheet lParam data into the wizard which it is
  2047. //
  2048. CWizard * pWizard = reinterpret_cast<CWizard *>(psp->lParam);
  2049. Assert(NULL != pWizard);
  2050. // Get the private data we stashed away for this page
  2051. //
  2052. lParam = pWizard->GetPageData(IDD_Upgrade);
  2053. Assert(lParam);
  2054. UpgradeData * pData = reinterpret_cast<UpgradeData *>(lParam);
  2055. // Start the progress
  2056. //
  2057. HWND hwndProgress = GetDlgItem(hwndDlg, IDC_UPGRADE_PROGRESS);
  2058. // Subclass the progress and make it also call the BB callback.
  2059. // Only do this if we are called from GUI mode setup.
  2060. if (g_pSetupWizard != NULL)
  2061. {
  2062. PCWSTR str = SzLoadIds(IDS_BB_NETWORK);
  2063. OldProgressProc = (WNDPROC)SetWindowLongPtr(hwndProgress,GWLP_WNDPROC,(LONG_PTR)NewProgessProc);
  2064. // Set the string for the progress on the billboard.
  2065. g_pSetupWizard->PSetupData()->BillBoardSetProgressText(str);
  2066. }
  2067. SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0,c_nMaxProgressRange));
  2068. SendMessage(hwndProgress, PBM_SETPOS, 1, 0);
  2069. SetTimer(hwndDlg, c_uiUpgradeRefreshID, c_uiUpgradeRefreshRate, NULL);
  2070. // Disable prev/next until initial work is complete
  2071. //
  2072. PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
  2073. // Default the mode buttons to typical
  2074. //
  2075. CheckRadioButton(hwndDlg, BTN_UPGRADE_TYPICAL,
  2076. BTN_UPGRADE_CUSTOM, BTN_UPGRADE_TYPICAL);
  2077. // Create the bold font and apply to the mode buttons
  2078. //
  2079. SetupFonts(hwndDlg, &pData->hBoldFont, FALSE);
  2080. if (pData->hBoldFont)
  2081. {
  2082. SetWindowFont(GetDlgItem(hwndDlg, BTN_UPGRADE_TYPICAL),
  2083. pData->hBoldFont, FALSE);
  2084. SetWindowFont(GetDlgItem(hwndDlg, BTN_UPGRADE_CUSTOM),
  2085. pData->hBoldFont, FALSE);
  2086. }
  2087. HICON hIcon = LoadIcon(_Module.GetResourceInstance(),
  2088. MAKEINTRESOURCE(IDI_LB_GEN_M_16));
  2089. if (hIcon)
  2090. {
  2091. SendMessage(GetDlgItem(hwndDlg, TXT_UPGRADE_ICON), STM_SETICON,
  2092. (WPARAM)hIcon, 0L);
  2093. }
  2094. return FALSE;
  2095. }
  2096. //
  2097. // Function: dlgprocUpgrade
  2098. //
  2099. // Purpose: Dialog Procedure for the Upgrade wizard page
  2100. //
  2101. // Parameters: standard dlgproc parameters
  2102. //
  2103. // Returns: BOOL
  2104. //
  2105. INT_PTR CALLBACK dlgprocUpgrade(HWND hwndDlg, UINT uMsg,
  2106. WPARAM wParam, LPARAM lParam)
  2107. {
  2108. TraceFileFunc(ttidGuiModeSetup);
  2109. BOOL frt = FALSE;
  2110. switch (uMsg)
  2111. {
  2112. case PWM_EXIT:
  2113. frt = OnUpgradePageExit(hwndDlg);
  2114. break;
  2115. case PWM_PROCEED:
  2116. frt = OnUpgradePageProceed(hwndDlg);
  2117. break;
  2118. case WM_INITDIALOG:
  2119. frt = OnUpgradeInitDialog(hwndDlg, lParam);
  2120. break;
  2121. case WM_TIMER:
  2122. OnUpgradeUpdateProgress(hwndDlg);
  2123. break;
  2124. case WM_NOTIFY:
  2125. {
  2126. LPNMHDR pnmh = (LPNMHDR)lParam;
  2127. switch (pnmh->code)
  2128. {
  2129. // propsheet notification
  2130. case PSN_HELP:
  2131. break;
  2132. case PSN_SETACTIVE:
  2133. frt = OnUpgradePageActivate( hwndDlg );
  2134. break;
  2135. case PSN_APPLY:
  2136. break;
  2137. case PSN_KILLACTIVE:
  2138. break;
  2139. case PSN_RESET:
  2140. break;
  2141. case PSN_WIZBACK:
  2142. frt = OnUpgradePagePrev(hwndDlg);
  2143. break;
  2144. case PSN_WIZFINISH:
  2145. break;
  2146. case PSN_WIZNEXT:
  2147. frt = OnUpgradePageNext(hwndDlg);
  2148. break;
  2149. default:
  2150. break;
  2151. }
  2152. }
  2153. break;
  2154. default:
  2155. break;
  2156. }
  2157. return( frt );
  2158. }
  2159. //
  2160. // Function: UpgradePageCleanup
  2161. //
  2162. // Purpose: As a callback function to allow any page allocated memory
  2163. // to be cleaned up, after the page will no longer be accessed.
  2164. //
  2165. // Parameters: pWizard [IN] - The wizard against which the page called
  2166. // register page
  2167. // lParam [IN] - The lParam supplied in the RegisterPage call
  2168. //
  2169. // Returns: nothing
  2170. //
  2171. VOID UpgradePageCleanup(CWizard *pWizard, LPARAM lParam)
  2172. {
  2173. TraceFileFunc(ttidGuiModeSetup);
  2174. UpgradeData * pData;
  2175. pData = reinterpret_cast<UpgradeData*>(lParam);
  2176. if (NULL != pData)
  2177. {
  2178. DeleteObject(pData->hBoldFont);
  2179. MemFree(pData);
  2180. }
  2181. }
  2182. //
  2183. // Function: CreateUpgradePage
  2184. //
  2185. // Purpose: To determine if the upgrade page needs to be shown, and to
  2186. // to create the page if requested. Note the upgrade page is
  2187. // responsible for initial installs also.
  2188. //
  2189. // Parameters: pWizard [IN] - Ptr to a Wizard instance
  2190. // pData [IN] - Context data to describe the world in
  2191. // which the Wizard will be run
  2192. // fCountOnly [IN] - If True, only the maximum number of
  2193. // pages this routine will create need
  2194. // be determined.
  2195. // pnPages [IN] - Increment by the number of pages
  2196. // to create/created
  2197. //
  2198. // Returns: HRESULT, S_OK on success
  2199. //
  2200. HRESULT HrCreateUpgradePage(CWizard *pWizard, PINTERNAL_SETUP_DATA pData,
  2201. BOOL fCountOnly, UINT *pnPages)
  2202. {
  2203. TraceFileFunc(ttidGuiModeSetup);
  2204. HRESULT hr = S_OK;
  2205. // Batch Mode or for fresh install
  2206. if (!IsPostInstall(pWizard))
  2207. {
  2208. hr = E_OUTOFMEMORY;
  2209. UpgradeData * pData = reinterpret_cast<UpgradeData*>
  2210. (MemAlloc(sizeof(UpgradeData)));
  2211. if (NULL == pData)
  2212. {
  2213. goto Error;
  2214. }
  2215. pData->fProcessed = FALSE;
  2216. pData->hBoldFont = NULL;
  2217. pData->nCurrentCap = 0;
  2218. (*pnPages)++;
  2219. // If not only counting, create and register the page
  2220. if (!fCountOnly)
  2221. {
  2222. HPROPSHEETPAGE hpsp;
  2223. PROPSHEETPAGE psp;
  2224. TraceTag(ttidWizard, "Creating Upgrade Page");
  2225. psp.dwSize = sizeof( PROPSHEETPAGE );
  2226. psp.dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  2227. psp.hInstance = _Module.GetResourceInstance();
  2228. psp.pszTemplate = MAKEINTRESOURCE( IDD_Upgrade );
  2229. psp.hIcon = NULL;
  2230. psp.pfnDlgProc = dlgprocUpgrade;
  2231. psp.lParam = reinterpret_cast<LPARAM>(pWizard);
  2232. psp.pszHeaderTitle = SzLoadIds(IDS_T_Upgrade);
  2233. psp.pszHeaderSubTitle = SzLoadIds(IDS_ST_Upgrade);
  2234. hpsp = CreatePropertySheetPage( &psp );
  2235. if (hpsp)
  2236. {
  2237. pWizard->RegisterPage(IDD_Upgrade, hpsp,
  2238. UpgradePageCleanup,
  2239. reinterpret_cast<LPARAM>(pData));
  2240. hr = S_OK;
  2241. }
  2242. else
  2243. {
  2244. MemFree(pData);
  2245. }
  2246. }
  2247. }
  2248. Error:
  2249. TraceHr(ttidWizard, FAL, hr, FALSE, "HrCreateUpgradePage");
  2250. return hr;
  2251. }
  2252. //
  2253. // Function: AppendUpgradePage
  2254. //
  2255. // Purpose: Add the Upgrade page, if it was created, to the set of pages
  2256. // that will be displayed.
  2257. //
  2258. // Parameters: pahpsp [IN,OUT] - Array of pages to add our page to
  2259. // pcPages [IN,OUT] - Count of pages in pahpsp
  2260. //
  2261. // Returns: Nothing
  2262. //
  2263. VOID AppendUpgradePage(CWizard *pWizard, HPROPSHEETPAGE* pahpsp, UINT *pcPages)
  2264. {
  2265. TraceFileFunc(ttidGuiModeSetup);
  2266. if (!IsPostInstall(pWizard))
  2267. {
  2268. HPROPSHEETPAGE hPage = pWizard->GetPageHandle(IDD_Upgrade);
  2269. Assert(hPage);
  2270. pahpsp[*pcPages] = hPage;
  2271. (*pcPages)++;
  2272. }
  2273. }