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.

923 lines
22 KiB

  1. // Copyright (c) 2001 Microsoft Corporation
  2. //
  3. // File: cys.cpp
  4. //
  5. // Synopsis: Configure Your Server Wizard main
  6. //
  7. // History: 02/02/2001 JeffJon Created
  8. #include "pch.h"
  9. #include "resource.h"
  10. #include "InstallationUnitProvider.h"
  11. // include the wizard pages
  12. #include "BeforeBeginPage.h"
  13. #include "CustomServerPage.h"
  14. #include "DecisionPage.h"
  15. #include "DnsForwarderPage.h"
  16. #include "DomainPage.h"
  17. #include "ExpressDHCPPage.h"
  18. #include "ExpressDNSPage.h"
  19. #include "ExpressRebootPage.h"
  20. #include "FileServerPage.h"
  21. #include "FinishPage.h"
  22. #include "IndexingPage.h"
  23. #include "InstallationProgressPage.h"
  24. #include "MilestonePage.h"
  25. #include "NetbiosPage.h"
  26. #include "POP3Page.h"
  27. #include "PrintServerPage.h"
  28. #include "RemoteDesktopPage.h"
  29. #include "UninstallMilestonePage.h"
  30. #include "UninstallProgressPage.h"
  31. #include "WebApplicationPage.h"
  32. #include "WelcomePage.h"
  33. #include "ExpressRebootPage.h"
  34. HINSTANCE hResourceModuleHandle = 0;
  35. const wchar_t* HELPFILE_NAME = 0; // no context help available
  36. // This is the name of a mutex that is used to see if CYS is running
  37. const wchar_t* RUNTIME_NAME = L"cysui";
  38. DWORD DEFAULT_LOGGING_OPTIONS =
  39. Log::OUTPUT_TO_FILE
  40. | Log::OUTPUT_FUNCCALLS
  41. | Log::OUTPUT_LOGS
  42. | Log::OUTPUT_ERRORS
  43. | Log::OUTPUT_HEADER
  44. | Log::OUTPUT_RUN_TIME;
  45. // a system modal popup thingy
  46. Popup popup(IDS_WIZARD_TITLE, true);
  47. // this is the mutex that indicates that CYS is running.
  48. HANDLE cysRunningMutex = INVALID_HANDLE_VALUE;
  49. // This is a brush that is used to paint all the backgrounds. It
  50. // needs to be created and deleted from inside main
  51. HBRUSH brush = 0;
  52. // these are the valid exit codes returned from the cys.exe process
  53. enum ExitCode
  54. {
  55. // the operation failed.
  56. EXIT_CODE_UNSUCCESSFUL = 0,
  57. // the operation succeeded
  58. EXIT_CODE_SUCCESSFUL = 1,
  59. // other exit codes can be added here...
  60. };
  61. enum StartPages
  62. {
  63. CYS_WELCOME_PAGE = 0,
  64. CYS_BEFORE_BEGIN_PAGE,
  65. CYS_EXPRESS_REBOOT_PAGE,
  66. CYS_FINISH_PAGE
  67. };
  68. UINT
  69. TerminalServerPostBoot()
  70. {
  71. LOG_FUNCTION(TerminalServerPostBoot);
  72. UINT startPage = CYS_WELCOME_PAGE;
  73. InstallationUnitProvider::GetInstance().
  74. SetCurrentInstallationUnit(TERMINALSERVER_SERVER);
  75. // Create the log file
  76. bool logFileAvailable = false;
  77. String logName;
  78. HANDLE logfileHandle = AppendLogFile(
  79. CYS_LOGFILE_NAME,
  80. logName);
  81. if (logfileHandle &&
  82. logfileHandle != INVALID_HANDLE_VALUE)
  83. {
  84. LOG(String::format(L"New log file was created: %1", logName.c_str()));
  85. logFileAvailable = true;
  86. }
  87. else
  88. {
  89. LOG(L"Unable to create the log file!!!");
  90. logFileAvailable = false;
  91. }
  92. // Prepare the finish dialog
  93. TerminalServerInstallationUnit& tsInstallationUnit =
  94. InstallationUnitProvider::GetInstance().GetTerminalServerInstallationUnit();
  95. // Make sure the installation unit knows we are doing an install
  96. tsInstallationUnit.SetInstalling(true);
  97. if (tsInstallationUnit.GetApplicationMode() == 1)
  98. {
  99. CYS_APPEND_LOG(String::load(IDS_LOG_TERMINAL_SERVER_REBOOT_SUCCESS));
  100. tsInstallationUnit.SetInstallResult(INSTALL_SUCCESS);
  101. startPage = CYS_FINISH_PAGE;
  102. }
  103. else
  104. {
  105. // Failed to install Terminal Server
  106. CYS_APPEND_LOG(String::load(IDS_LOG_TERMINAL_SERVER_REBOOT_FAILED));
  107. tsInstallationUnit.SetInstallResult(INSTALL_FAILURE);
  108. startPage = CYS_FINISH_PAGE;
  109. }
  110. CYS_APPEND_LOG(L"\r\n");
  111. // Close the log file
  112. Win::CloseHandle(logfileHandle);
  113. LOG(String::format(
  114. L"startPage = %1!d!",
  115. startPage));
  116. return startPage;
  117. }
  118. UINT
  119. TerminalServerUninstallPostBoot()
  120. {
  121. LOG_FUNCTION(TerminalServerUninstallPostBoot);
  122. UINT startPage = CYS_WELCOME_PAGE;
  123. InstallationUnitProvider::GetInstance().
  124. SetCurrentInstallationUnit(TERMINALSERVER_SERVER);
  125. // Create the log file
  126. bool logFileAvailable = false;
  127. String logName;
  128. HANDLE logfileHandle = AppendLogFile(
  129. CYS_LOGFILE_NAME,
  130. logName);
  131. if (logfileHandle &&
  132. logfileHandle != INVALID_HANDLE_VALUE)
  133. {
  134. LOG(String::format(L"New log file was created: %1", logName.c_str()));
  135. logFileAvailable = true;
  136. }
  137. else
  138. {
  139. LOG(L"Unable to create the log file!!!");
  140. logFileAvailable = false;
  141. }
  142. // Prepare the finish dialog
  143. TerminalServerInstallationUnit& tsInstallationUnit =
  144. InstallationUnitProvider::GetInstance().GetTerminalServerInstallationUnit();
  145. // Make sure the installation unit knows we are doing an uninstall
  146. tsInstallationUnit.SetInstalling(false);
  147. if (tsInstallationUnit.GetApplicationMode() == 0)
  148. {
  149. CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_TERMINAL_SERVER_SUCCESS));
  150. tsInstallationUnit.SetUninstallResult(UNINSTALL_SUCCESS);
  151. startPage = CYS_FINISH_PAGE;
  152. }
  153. else
  154. {
  155. // Failed to uninstall Terminal Server
  156. CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_TERMINAL_SERVER_FAILED));
  157. tsInstallationUnit.SetUninstallResult(UNINSTALL_FAILURE);
  158. startPage = CYS_FINISH_PAGE;
  159. }
  160. CYS_APPEND_LOG(L"\r\n");
  161. // Close the log file
  162. Win::CloseHandle(logfileHandle);
  163. LOG(String::format(
  164. L"startPage = %1!d!",
  165. startPage));
  166. return startPage;
  167. }
  168. UINT
  169. FirstServerPostBoot()
  170. {
  171. LOG_FUNCTION(FirstServerPostBoot);
  172. UINT startPage = CYS_EXPRESS_REBOOT_PAGE;
  173. InstallationUnitProvider::GetInstance().
  174. SetCurrentInstallationUnit(EXPRESS_SERVER);
  175. LOG(String::format(
  176. L"startPage = %1!d!",
  177. startPage));
  178. return startPage;
  179. }
  180. UINT
  181. DCPromoPostBoot()
  182. {
  183. LOG_FUNCTION(DCPromoPostBoot);
  184. UINT startPage = CYS_WELCOME_PAGE;
  185. InstallationUnitProvider::GetInstance().
  186. SetCurrentInstallationUnit(DC_SERVER);
  187. // Create the log file
  188. bool logFileAvailable = false;
  189. String logName;
  190. HANDLE logfileHandle = AppendLogFile(
  191. CYS_LOGFILE_NAME,
  192. logName);
  193. if (logfileHandle &&
  194. logfileHandle != INVALID_HANDLE_VALUE)
  195. {
  196. LOG(String::format(L"New log file was created: %1", logName.c_str()));
  197. logFileAvailable = true;
  198. }
  199. else
  200. {
  201. LOG(L"Unable to create the log file!!!");
  202. logFileAvailable = false;
  203. }
  204. // Make sure the installation unit knows we are doing an install
  205. InstallationUnitProvider::GetInstance().
  206. GetCurrentInstallationUnit().SetInstalling(true);
  207. // Prepare the finish page
  208. if (State::GetInstance().IsDC())
  209. {
  210. CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_SUCCESS));
  211. InstallationUnitProvider::GetInstance().
  212. GetADInstallationUnit().SetInstallResult(INSTALL_SUCCESS);
  213. startPage = CYS_FINISH_PAGE;
  214. }
  215. else
  216. {
  217. CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_FAILED));
  218. InstallationUnitProvider::GetInstance().
  219. GetADInstallationUnit().SetInstallResult(INSTALL_FAILURE);
  220. startPage = CYS_FINISH_PAGE;
  221. }
  222. CYS_APPEND_LOG(L"\r\n");
  223. // Close the log file
  224. Win::CloseHandle(logfileHandle);
  225. LOG(String::format(
  226. L"startPage = %1!d!",
  227. startPage));
  228. return startPage;
  229. }
  230. UINT
  231. DCDemotePostBoot()
  232. {
  233. LOG_FUNCTION(DCDemotePostBoot);
  234. UINT startPage = CYS_WELCOME_PAGE;
  235. InstallationUnitProvider::GetInstance().
  236. SetCurrentInstallationUnit(DC_SERVER);
  237. // Create the log file
  238. bool logFileAvailable = false;
  239. String logName;
  240. HANDLE logfileHandle = AppendLogFile(
  241. CYS_LOGFILE_NAME,
  242. logName);
  243. if (logfileHandle &&
  244. logfileHandle != INVALID_HANDLE_VALUE)
  245. {
  246. LOG(String::format(L"New log file was created: %1", logName.c_str()));
  247. logFileAvailable = true;
  248. }
  249. else
  250. {
  251. LOG(L"Unable to create the log file!!!");
  252. logFileAvailable = false;
  253. }
  254. // Make sure the installation unit knows we are doing an uninstall
  255. InstallationUnitProvider::GetInstance().
  256. GetCurrentInstallationUnit().SetInstalling(false);
  257. // Prepare the finish page
  258. if (!State::GetInstance().IsDC())
  259. {
  260. CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DOMAIN_CONTROLLER_SUCCESS));
  261. InstallationUnitProvider::GetInstance().
  262. GetADInstallationUnit().SetUninstallResult(UNINSTALL_SUCCESS);
  263. startPage = CYS_FINISH_PAGE;
  264. }
  265. else
  266. {
  267. CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DOMAIN_CONTROLLER_FAILED));
  268. InstallationUnitProvider::GetInstance().
  269. GetADInstallationUnit().SetUninstallResult(UNINSTALL_FAILURE);
  270. startPage = CYS_FINISH_PAGE;
  271. }
  272. CYS_APPEND_LOG(L"\r\n");
  273. // Close the log file
  274. Win::CloseHandle(logfileHandle);
  275. LOG(String::format(
  276. L"startPage = %1!d!",
  277. startPage));
  278. return startPage;
  279. }
  280. UINT
  281. DoRebootOperations()
  282. {
  283. LOG_FUNCTION(DoRebootOperations);
  284. UINT startPage = 0;
  285. // Check to see if we are in a reboot scenario
  286. String homeKeyValue;
  287. if (State::GetInstance().GetHomeRegkey(homeKeyValue))
  288. {
  289. // Now set the home regkey back to "home" so that we won't run
  290. // through these again. This has to be done before doing the
  291. // operation because the user could leave this dialog up
  292. // and cause a reboot (like demoting a DC) and then the
  293. // post reboot operations would run again
  294. if (homeKeyValue.icompare(CYS_HOME_REGKEY_DEFAULT_VALUE) != 0)
  295. {
  296. bool result =
  297. State::GetInstance().SetHomeRegkey(CYS_HOME_REGKEY_DEFAULT_VALUE);
  298. ASSERT(result);
  299. }
  300. // Reset the must run key now that we have done the reboot stuff
  301. bool regkeyResult = SetRegKeyValue(
  302. CYS_HOME_REGKEY,
  303. CYS_HOME_REGKEY_MUST_RUN,
  304. CYS_HOME_RUN_KEY_DONT_RUN,
  305. HKEY_LOCAL_MACHINE,
  306. true);
  307. ASSERT(regkeyResult);
  308. // Set the reboot scenario in the state object so that we know we
  309. // are running in that context
  310. State::GetInstance().SetRebootScenario(true);
  311. // Now run the post reboot operations if necessary
  312. if (homeKeyValue.icompare(CYS_HOME_REGKEY_TERMINAL_SERVER_VALUE) == 0)
  313. {
  314. startPage = TerminalServerPostBoot();
  315. }
  316. else if (homeKeyValue.icompare(CYS_HOME_REGKEY_UNINSTALL_TERMINAL_SERVER_VALUE) == 0)
  317. {
  318. startPage = TerminalServerUninstallPostBoot();
  319. }
  320. else if (homeKeyValue.icompare(CYS_HOME_REGKEY_FIRST_SERVER_VALUE) == 0)
  321. {
  322. startPage = FirstServerPostBoot();
  323. }
  324. else if (homeKeyValue.icompare(CYS_HOME_REGKEY_DCPROMO_VALUE) == 0)
  325. {
  326. startPage = DCPromoPostBoot();
  327. }
  328. else if (homeKeyValue.icompare(CYS_HOME_REGKEY_DCDEMOTE_VALUE) == 0)
  329. {
  330. startPage = DCDemotePostBoot();
  331. }
  332. else
  333. {
  334. // We are NOT running a reboot scenario
  335. State::GetInstance().SetRebootScenario(false);
  336. }
  337. }
  338. LOG(String::format(
  339. L"startPage = %1!d!",
  340. startPage));
  341. return startPage;
  342. }
  343. UINT
  344. GetStartPageFromCommandLine()
  345. {
  346. LOG_FUNCTION(GetStartPageFromCommandLine);
  347. UINT startPage = 0;
  348. StringVector args;
  349. int argc = Win::GetCommandLineArgs(std::back_inserter(args));
  350. if (argc > 1)
  351. {
  352. const String skipWelcome(L"/skipWelcome");
  353. for (
  354. StringVector::iterator itr = args.begin();
  355. itr != args.end();
  356. ++itr)
  357. {
  358. if (itr &&
  359. (*itr).icompare(skipWelcome) == 0)
  360. {
  361. startPage = 1;
  362. break;
  363. }
  364. }
  365. }
  366. LOG(String::format(
  367. L"startPage = %1!d!",
  368. startPage));
  369. return startPage;
  370. }
  371. UINT
  372. GetStartPage()
  373. {
  374. LOG_FUNCTION(GetStartPage);
  375. UINT startPage = 0;
  376. // First check for the reboot scenarios
  377. startPage = DoRebootOperations();
  378. if (startPage == 0)
  379. {
  380. // Now look at the commandline to see if any
  381. // switches were provided
  382. startPage = GetStartPageFromCommandLine();
  383. }
  384. LOG(String::format(
  385. L"startPage = %1!d!",
  386. startPage));
  387. return startPage;
  388. }
  389. // This is the DlgProc of the property sheet that we are subclassing. I need
  390. // to hold on to it so I can call it if we don't handle the message in our
  391. // replacement DlgProc.
  392. static WNDPROC replacedSheetWndProc = 0;
  393. // This is the DlgProc that we will use to replace the property sheet
  394. // DlgProc. It handles the WM_CTLCOLORDLG message to paint the background
  395. // color
  396. LRESULT
  397. ReplacementWndProc(
  398. HWND hwnd,
  399. UINT message,
  400. WPARAM wparam,
  401. LPARAM lparam)
  402. {
  403. switch (message)
  404. {
  405. case WM_CTLCOLORDLG:
  406. case WM_CTLCOLORSTATIC:
  407. case WM_CTLCOLOREDIT:
  408. case WM_CTLCOLORLISTBOX:
  409. case WM_CTLCOLORSCROLLBAR:
  410. {
  411. HDC deviceContext = reinterpret_cast<HDC>(wparam);
  412. ASSERT(deviceContext);
  413. if (deviceContext)
  414. {
  415. SetTextColor(deviceContext, GetSysColor(COLOR_WINDOWTEXT));
  416. SetBkColor(deviceContext, GetSysColor(COLOR_WINDOW));
  417. }
  418. return
  419. reinterpret_cast<LRESULT>(
  420. Win::GetSysColorBrush(COLOR_WINDOW));
  421. }
  422. default:
  423. if (replacedSheetWndProc)
  424. {
  425. return ::CallWindowProc(
  426. replacedSheetWndProc,
  427. hwnd,
  428. message,
  429. wparam,
  430. lparam);
  431. }
  432. break;
  433. }
  434. return 0;
  435. }
  436. // This callback function is called by the property sheet. During initialization
  437. // I use this to subclass the property sheet, replacing their DlgProc with my
  438. // own so that I can change the background color.
  439. int
  440. CALLBACK
  441. SheetCallbackProc(
  442. HWND hwnd,
  443. UINT message,
  444. LPARAM /*lparam*/)
  445. {
  446. LOG_FUNCTION(SheetCallbackProc);
  447. if (message == PSCB_INITIALIZED)
  448. {
  449. LONG_PTR ptr = 0;
  450. HRESULT hr = Win::GetWindowLongPtr(
  451. hwnd,
  452. GWLP_WNDPROC,
  453. ptr);
  454. if (SUCCEEDED(hr))
  455. {
  456. replacedSheetWndProc = reinterpret_cast<WNDPROC>(ptr);
  457. hr = Win::SetWindowLongPtr(
  458. hwnd,
  459. GWLP_WNDPROC,
  460. reinterpret_cast<LONG_PTR>(ReplacementWndProc));
  461. ASSERT(SUCCEEDED(hr));
  462. }
  463. }
  464. return 0;
  465. }
  466. ExitCode
  467. RunWizard()
  468. {
  469. LOG_FUNCTION(RunWizard);
  470. ExitCode exitCode = EXIT_CODE_SUCCESSFUL;
  471. UINT startPage = GetStartPage();
  472. State::GetInstance().SetStartPage(startPage);
  473. // Create the wizard and add all the pages
  474. Wizard wiz(
  475. IDS_WIZARD_TITLE,
  476. IDB_BANNER16,
  477. IDB_BANNER256,
  478. IDB_WATERMARK16,
  479. IDB_WATERMARK256);
  480. // NOTE: Do not change the order of the following
  481. // page additions. They are important for being able
  482. // to start the wizard at one of these pages directly.
  483. // The order of these pages cooresponds directly to
  484. // the order of the StartPages enum above
  485. wiz.AddPage(new WelcomePage()); // CYS_WELCOME_PAGE
  486. wiz.AddPage(new BeforeBeginPage()); // CYS_BEFORE_BEGIN_PAGE
  487. wiz.AddPage(new ExpressRebootPage()); // CYS_EXPRESS_REBOOT_PAGE
  488. wiz.AddPage(new FinishPage()); // CYS_FINISH_PAGE
  489. //
  490. //
  491. //
  492. wiz.AddPage(new DecisionPage());
  493. wiz.AddPage(new CustomServerPage());
  494. wiz.AddPage(new ADDomainPage());
  495. wiz.AddPage(new NetbiosDomainPage());
  496. wiz.AddPage(new DNSForwarderPage());
  497. wiz.AddPage(new ExpressDNSPage());
  498. wiz.AddPage(new ExpressDHCPPage());
  499. wiz.AddPage(new PrintServerPage());
  500. wiz.AddPage(new FileServerPage());
  501. wiz.AddPage(new IndexingPage());
  502. wiz.AddPage(new MilestonePage());
  503. wiz.AddPage(new UninstallMilestonePage());
  504. wiz.AddPage(new InstallationProgressPage());
  505. wiz.AddPage(new UninstallProgressPage());
  506. wiz.AddPage(new WebApplicationPage());
  507. wiz.AddPage(new POP3Page());
  508. // Run the wizard
  509. switch (wiz.ModalExecute(
  510. 0,
  511. startPage,
  512. SheetCallbackProc))
  513. {
  514. case -1:
  515. {
  516. /* popup.Error(
  517. Win::GetDesktopWindow(),
  518. E_FAIL,
  519. IDS_PROP_SHEET_FAILED);
  520. */
  521. exitCode = EXIT_CODE_UNSUCCESSFUL;
  522. break;
  523. }
  524. case ID_PSREBOOTSYSTEM:
  525. {
  526. // we can infer that if we are supposed to reboot, then the
  527. // operation was successful.
  528. exitCode = EXIT_CODE_SUCCESSFUL;
  529. break;
  530. }
  531. default:
  532. {
  533. // do nothing.
  534. break;
  535. }
  536. }
  537. return exitCode;
  538. }
  539. ExitCode
  540. Start()
  541. {
  542. LOG_FUNCTION(Start);
  543. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  544. do
  545. {
  546. // Put any checks that should stop the wizard from running here...
  547. // User must be an Administrator
  548. bool isAdmin = ::IsCurrentUserAdministrator();
  549. if (!isAdmin)
  550. {
  551. LOG(L"Current user is not an Administrator");
  552. // Since the user is not an administrator
  553. // close the mutex so that a non-admin can't
  554. // leave this message box up and prevent
  555. // an administrator from running CYS
  556. Win::CloseHandle(cysRunningMutex);
  557. popup.MessageBox(
  558. Win::GetDesktopWindow(),
  559. IDS_NOT_ADMIN,
  560. MB_OK);
  561. // State::GetInstance().SetRerunWizard(false);
  562. exitCode = EXIT_CODE_UNSUCCESSFUL;
  563. break;
  564. }
  565. // The Sys OC Manager cannot be running
  566. if (State::GetInstance().IsWindowsSetupRunning())
  567. {
  568. LOG(L"Windows setup is running");
  569. popup.MessageBox(
  570. Win::GetDesktopWindow(),
  571. IDS_WINDOWS_SETUP_RUNNING_DURING_CYS_STARTUP,
  572. MB_OK);
  573. exitCode = EXIT_CODE_UNSUCCESSFUL;
  574. break;
  575. }
  576. // Machine cannot be in the middle of a DC upgrade
  577. if (State::GetInstance().IsUpgradeState())
  578. {
  579. LOG(L"Machine needs to complete DC upgrade");
  580. String commandline = Win::GetCommandLine();
  581. // If we were launched from explorer then
  582. // don't show the message, just exit silently
  583. if (commandline.find(EXPLORER_SWITCH) == String::npos)
  584. {
  585. popup.MessageBox(
  586. Win::GetDesktopWindow(),
  587. IDS_DC_UPGRADE_NOT_COMPLETE,
  588. MB_OK);
  589. }
  590. // State::GetInstance().SetRerunWizard(false);
  591. exitCode = EXIT_CODE_UNSUCCESSFUL;
  592. break;
  593. }
  594. // Machine cannot have DCPROMO running or a reboot pending
  595. if (State::GetInstance().IsDCPromoRunning())
  596. {
  597. LOG(L"DCPROMO is running");
  598. popup.MessageBox(
  599. Win::GetDesktopWindow(),
  600. IDS_DCPROMO_RUNNING,
  601. MB_OK);
  602. // State::GetInstance().SetRerunWizard(false);
  603. exitCode = EXIT_CODE_UNSUCCESSFUL;
  604. break;
  605. }
  606. else if (State::GetInstance().IsDCPromoPendingReboot())
  607. {
  608. LOG(L"DCPROMO was run, pending reboot");
  609. popup.MessageBox(
  610. Win::GetDesktopWindow(),
  611. IDS_DCPROMO_PENDING_REBOOT,
  612. MB_OK);
  613. // State::GetInstance().SetRerunWizard(false);
  614. exitCode = EXIT_CODE_UNSUCCESSFUL;
  615. break;
  616. }
  617. DWORD productSKU = State::GetInstance().RetrieveProductSKU();
  618. if (CYS_UNSUPPORTED_SKU == productSKU)
  619. {
  620. LOG(L"Cannot run CYS on any SKU but servers");
  621. popup.MessageBox(
  622. Win::GetDesktopWindow(),
  623. IDS_SERVER_ONLY,
  624. MB_OK);
  625. // State::GetInstance().SetRerunWizard(false);
  626. exitCode = EXIT_CODE_UNSUCCESSFUL;
  627. break;
  628. }
  629. // The machine cannot be a member of a cluster
  630. if (IsClusterServer())
  631. {
  632. LOG(L"Machine is a member of a cluster");
  633. Win::CloseHandle(cysRunningMutex);
  634. popup.MessageBox(
  635. Win::GetDesktopWindow(),
  636. IDS_CLUSTER,
  637. MB_OK);
  638. exitCode = EXIT_CODE_UNSUCCESSFUL;
  639. break;
  640. }
  641. // We can run the wizard. Yea!!!
  642. exitCode = RunWizard();
  643. }
  644. while (0);
  645. LOG(String::format(L"exitCode = %1!d!", static_cast<int>(exitCode)));
  646. return exitCode;
  647. }
  648. int WINAPI
  649. WinMain(
  650. HINSTANCE hInstance,
  651. HINSTANCE /* hPrevInstance */ ,
  652. PSTR /* lpszCmdLine */ ,
  653. int /* nCmdShow */)
  654. {
  655. hResourceModuleHandle = hInstance;
  656. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  657. String mutexName = L"Global\\";
  658. mutexName += RUNTIME_NAME;
  659. HRESULT hr = Win::CreateMutex(0, true, mutexName, cysRunningMutex);
  660. if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS))
  661. {
  662. // First close the handle so that the owner can reacquire if they
  663. // restart
  664. Win::CloseHandle(cysRunningMutex);
  665. // Now show the error message
  666. popup.MessageBox(
  667. Win::GetDesktopWindow(),
  668. IDS_ALREADY_RUNNING,
  669. MB_OK);
  670. }
  671. else
  672. {
  673. do
  674. {
  675. hr = ::CoInitialize(0);
  676. if (FAILED(hr))
  677. {
  678. ASSERT(SUCCEEDED(hr));
  679. break;
  680. }
  681. // Initialize the common controls so that we can use
  682. // animation in the NetDetectProgressDialog
  683. INITCOMMONCONTROLSEX commonControlsEx;
  684. commonControlsEx.dwSize = sizeof(commonControlsEx);
  685. commonControlsEx.dwICC = ICC_ANIMATE_CLASS;
  686. BOOL init = ::InitCommonControlsEx(&commonControlsEx);
  687. ASSERT(init);
  688. // For now there is no more rerunning CYS
  689. // do
  690. // {
  691. exitCode = Start();
  692. // } while(State::GetInstance().RerunWizard());
  693. InstallationUnitProvider::Destroy();
  694. State::Destroy();
  695. CoUninitialize();
  696. } while(false);
  697. }
  698. if (brush)
  699. {
  700. // delete the background brush
  701. (void)Win::DeleteObject(brush);
  702. }
  703. return static_cast<int>(exitCode);
  704. }