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

// Copyright (c) 2001 Microsoft Corporation
//
// File: cys.cpp
//
// Synopsis: Configure Your Server Wizard main
//
// History: 02/02/2001 JeffJon Created
#include "pch.h"
#include "resource.h"
#include "InstallationUnitProvider.h"
// include the wizard pages
#include "BeforeBeginPage.h"
#include "CustomServerPage.h"
#include "DecisionPage.h"
#include "DnsForwarderPage.h"
#include "DomainPage.h"
#include "ExpressDHCPPage.h"
#include "ExpressDNSPage.h"
#include "ExpressRebootPage.h"
#include "FileServerPage.h"
#include "FinishPage.h"
#include "IndexingPage.h"
#include "InstallationProgressPage.h"
#include "MilestonePage.h"
#include "NetbiosPage.h"
#include "POP3Page.h"
#include "PrintServerPage.h"
#include "RemoteDesktopPage.h"
#include "UninstallMilestonePage.h"
#include "UninstallProgressPage.h"
#include "WebApplicationPage.h"
#include "WelcomePage.h"
#include "ExpressRebootPage.h"
HINSTANCE hResourceModuleHandle = 0;
const wchar_t* HELPFILE_NAME = 0; // no context help available
// This is the name of a mutex that is used to see if CYS is running
const wchar_t* RUNTIME_NAME = L"cysui";
DWORD DEFAULT_LOGGING_OPTIONS =
Log::OUTPUT_TO_FILE
| Log::OUTPUT_FUNCCALLS
| Log::OUTPUT_LOGS
| Log::OUTPUT_ERRORS
| Log::OUTPUT_HEADER
| Log::OUTPUT_RUN_TIME;
// a system modal popup thingy
Popup popup(IDS_WIZARD_TITLE, true);
// this is the mutex that indicates that CYS is running.
HANDLE cysRunningMutex = INVALID_HANDLE_VALUE;
// This is a brush that is used to paint all the backgrounds. It
// needs to be created and deleted from inside main
HBRUSH brush = 0;
// these are the valid exit codes returned from the cys.exe process
enum ExitCode
{
// the operation failed.
EXIT_CODE_UNSUCCESSFUL = 0,
// the operation succeeded
EXIT_CODE_SUCCESSFUL = 1,
// other exit codes can be added here...
};
enum StartPages
{
CYS_WELCOME_PAGE = 0,
CYS_BEFORE_BEGIN_PAGE,
CYS_EXPRESS_REBOOT_PAGE,
CYS_FINISH_PAGE
};
UINT
TerminalServerPostBoot()
{
LOG_FUNCTION(TerminalServerPostBoot);
UINT startPage = CYS_WELCOME_PAGE;
InstallationUnitProvider::GetInstance().
SetCurrentInstallationUnit(TERMINALSERVER_SERVER);
// Create the log file
bool logFileAvailable = false;
String logName;
HANDLE logfileHandle = AppendLogFile(
CYS_LOGFILE_NAME,
logName);
if (logfileHandle &&
logfileHandle != INVALID_HANDLE_VALUE)
{
LOG(String::format(L"New log file was created: %1", logName.c_str()));
logFileAvailable = true;
}
else
{
LOG(L"Unable to create the log file!!!");
logFileAvailable = false;
}
// Prepare the finish dialog
TerminalServerInstallationUnit& tsInstallationUnit =
InstallationUnitProvider::GetInstance().GetTerminalServerInstallationUnit();
// Make sure the installation unit knows we are doing an install
tsInstallationUnit.SetInstalling(true);
if (tsInstallationUnit.GetApplicationMode() == 1)
{
CYS_APPEND_LOG(String::load(IDS_LOG_TERMINAL_SERVER_REBOOT_SUCCESS));
tsInstallationUnit.SetInstallResult(INSTALL_SUCCESS);
startPage = CYS_FINISH_PAGE;
}
else
{
// Failed to install Terminal Server
CYS_APPEND_LOG(String::load(IDS_LOG_TERMINAL_SERVER_REBOOT_FAILED));
tsInstallationUnit.SetInstallResult(INSTALL_FAILURE);
startPage = CYS_FINISH_PAGE;
}
CYS_APPEND_LOG(L"\r\n");
// Close the log file
Win::CloseHandle(logfileHandle);
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
TerminalServerUninstallPostBoot()
{
LOG_FUNCTION(TerminalServerUninstallPostBoot);
UINT startPage = CYS_WELCOME_PAGE;
InstallationUnitProvider::GetInstance().
SetCurrentInstallationUnit(TERMINALSERVER_SERVER);
// Create the log file
bool logFileAvailable = false;
String logName;
HANDLE logfileHandle = AppendLogFile(
CYS_LOGFILE_NAME,
logName);
if (logfileHandle &&
logfileHandle != INVALID_HANDLE_VALUE)
{
LOG(String::format(L"New log file was created: %1", logName.c_str()));
logFileAvailable = true;
}
else
{
LOG(L"Unable to create the log file!!!");
logFileAvailable = false;
}
// Prepare the finish dialog
TerminalServerInstallationUnit& tsInstallationUnit =
InstallationUnitProvider::GetInstance().GetTerminalServerInstallationUnit();
// Make sure the installation unit knows we are doing an uninstall
tsInstallationUnit.SetInstalling(false);
if (tsInstallationUnit.GetApplicationMode() == 0)
{
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_TERMINAL_SERVER_SUCCESS));
tsInstallationUnit.SetUninstallResult(UNINSTALL_SUCCESS);
startPage = CYS_FINISH_PAGE;
}
else
{
// Failed to uninstall Terminal Server
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_TERMINAL_SERVER_FAILED));
tsInstallationUnit.SetUninstallResult(UNINSTALL_FAILURE);
startPage = CYS_FINISH_PAGE;
}
CYS_APPEND_LOG(L"\r\n");
// Close the log file
Win::CloseHandle(logfileHandle);
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
FirstServerPostBoot()
{
LOG_FUNCTION(FirstServerPostBoot);
UINT startPage = CYS_EXPRESS_REBOOT_PAGE;
InstallationUnitProvider::GetInstance().
SetCurrentInstallationUnit(EXPRESS_SERVER);
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
DCPromoPostBoot()
{
LOG_FUNCTION(DCPromoPostBoot);
UINT startPage = CYS_WELCOME_PAGE;
InstallationUnitProvider::GetInstance().
SetCurrentInstallationUnit(DC_SERVER);
// Create the log file
bool logFileAvailable = false;
String logName;
HANDLE logfileHandle = AppendLogFile(
CYS_LOGFILE_NAME,
logName);
if (logfileHandle &&
logfileHandle != INVALID_HANDLE_VALUE)
{
LOG(String::format(L"New log file was created: %1", logName.c_str()));
logFileAvailable = true;
}
else
{
LOG(L"Unable to create the log file!!!");
logFileAvailable = false;
}
// Make sure the installation unit knows we are doing an install
InstallationUnitProvider::GetInstance().
GetCurrentInstallationUnit().SetInstalling(true);
// Prepare the finish page
if (State::GetInstance().IsDC())
{
CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_SUCCESS));
InstallationUnitProvider::GetInstance().
GetADInstallationUnit().SetInstallResult(INSTALL_SUCCESS);
startPage = CYS_FINISH_PAGE;
}
else
{
CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_FAILED));
InstallationUnitProvider::GetInstance().
GetADInstallationUnit().SetInstallResult(INSTALL_FAILURE);
startPage = CYS_FINISH_PAGE;
}
CYS_APPEND_LOG(L"\r\n");
// Close the log file
Win::CloseHandle(logfileHandle);
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
DCDemotePostBoot()
{
LOG_FUNCTION(DCDemotePostBoot);
UINT startPage = CYS_WELCOME_PAGE;
InstallationUnitProvider::GetInstance().
SetCurrentInstallationUnit(DC_SERVER);
// Create the log file
bool logFileAvailable = false;
String logName;
HANDLE logfileHandle = AppendLogFile(
CYS_LOGFILE_NAME,
logName);
if (logfileHandle &&
logfileHandle != INVALID_HANDLE_VALUE)
{
LOG(String::format(L"New log file was created: %1", logName.c_str()));
logFileAvailable = true;
}
else
{
LOG(L"Unable to create the log file!!!");
logFileAvailable = false;
}
// Make sure the installation unit knows we are doing an uninstall
InstallationUnitProvider::GetInstance().
GetCurrentInstallationUnit().SetInstalling(false);
// Prepare the finish page
if (!State::GetInstance().IsDC())
{
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DOMAIN_CONTROLLER_SUCCESS));
InstallationUnitProvider::GetInstance().
GetADInstallationUnit().SetUninstallResult(UNINSTALL_SUCCESS);
startPage = CYS_FINISH_PAGE;
}
else
{
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DOMAIN_CONTROLLER_FAILED));
InstallationUnitProvider::GetInstance().
GetADInstallationUnit().SetUninstallResult(UNINSTALL_FAILURE);
startPage = CYS_FINISH_PAGE;
}
CYS_APPEND_LOG(L"\r\n");
// Close the log file
Win::CloseHandle(logfileHandle);
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
DoRebootOperations()
{
LOG_FUNCTION(DoRebootOperations);
UINT startPage = 0;
// Check to see if we are in a reboot scenario
String homeKeyValue;
if (State::GetInstance().GetHomeRegkey(homeKeyValue))
{
// Now set the home regkey back to "home" so that we won't run
// through these again. This has to be done before doing the
// operation because the user could leave this dialog up
// and cause a reboot (like demoting a DC) and then the
// post reboot operations would run again
if (homeKeyValue.icompare(CYS_HOME_REGKEY_DEFAULT_VALUE) != 0)
{
bool result =
State::GetInstance().SetHomeRegkey(CYS_HOME_REGKEY_DEFAULT_VALUE);
ASSERT(result);
}
// Reset the must run key now that we have done the reboot stuff
bool regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_REGKEY_MUST_RUN,
CYS_HOME_RUN_KEY_DONT_RUN,
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// Set the reboot scenario in the state object so that we know we
// are running in that context
State::GetInstance().SetRebootScenario(true);
// Now run the post reboot operations if necessary
if (homeKeyValue.icompare(CYS_HOME_REGKEY_TERMINAL_SERVER_VALUE) == 0)
{
startPage = TerminalServerPostBoot();
}
else if (homeKeyValue.icompare(CYS_HOME_REGKEY_UNINSTALL_TERMINAL_SERVER_VALUE) == 0)
{
startPage = TerminalServerUninstallPostBoot();
}
else if (homeKeyValue.icompare(CYS_HOME_REGKEY_FIRST_SERVER_VALUE) == 0)
{
startPage = FirstServerPostBoot();
}
else if (homeKeyValue.icompare(CYS_HOME_REGKEY_DCPROMO_VALUE) == 0)
{
startPage = DCPromoPostBoot();
}
else if (homeKeyValue.icompare(CYS_HOME_REGKEY_DCDEMOTE_VALUE) == 0)
{
startPage = DCDemotePostBoot();
}
else
{
// We are NOT running a reboot scenario
State::GetInstance().SetRebootScenario(false);
}
}
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
GetStartPageFromCommandLine()
{
LOG_FUNCTION(GetStartPageFromCommandLine);
UINT startPage = 0;
StringVector args;
int argc = Win::GetCommandLineArgs(std::back_inserter(args));
if (argc > 1)
{
const String skipWelcome(L"/skipWelcome");
for (
StringVector::iterator itr = args.begin();
itr != args.end();
++itr)
{
if (itr &&
(*itr).icompare(skipWelcome) == 0)
{
startPage = 1;
break;
}
}
}
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
UINT
GetStartPage()
{
LOG_FUNCTION(GetStartPage);
UINT startPage = 0;
// First check for the reboot scenarios
startPage = DoRebootOperations();
if (startPage == 0)
{
// Now look at the commandline to see if any
// switches were provided
startPage = GetStartPageFromCommandLine();
}
LOG(String::format(
L"startPage = %1!d!",
startPage));
return startPage;
}
// This is the DlgProc of the property sheet that we are subclassing. I need
// to hold on to it so I can call it if we don't handle the message in our
// replacement DlgProc.
static WNDPROC replacedSheetWndProc = 0;
// This is the DlgProc that we will use to replace the property sheet
// DlgProc. It handles the WM_CTLCOLORDLG message to paint the background
// color
LRESULT
ReplacementWndProc(
HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
switch (message)
{
case WM_CTLCOLORDLG:
case WM_CTLCOLORSTATIC:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORSCROLLBAR:
{
HDC deviceContext = reinterpret_cast<HDC>(wparam);
ASSERT(deviceContext);
if (deviceContext)
{
SetTextColor(deviceContext, GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(deviceContext, GetSysColor(COLOR_WINDOW));
}
return
reinterpret_cast<LRESULT>(
Win::GetSysColorBrush(COLOR_WINDOW));
}
default:
if (replacedSheetWndProc)
{
return ::CallWindowProc(
replacedSheetWndProc,
hwnd,
message,
wparam,
lparam);
}
break;
}
return 0;
}
// This callback function is called by the property sheet. During initialization
// I use this to subclass the property sheet, replacing their DlgProc with my
// own so that I can change the background color.
int
CALLBACK
SheetCallbackProc(
HWND hwnd,
UINT message,
LPARAM /*lparam*/)
{
LOG_FUNCTION(SheetCallbackProc);
if (message == PSCB_INITIALIZED)
{
LONG_PTR ptr = 0;
HRESULT hr = Win::GetWindowLongPtr(
hwnd,
GWLP_WNDPROC,
ptr);
if (SUCCEEDED(hr))
{
replacedSheetWndProc = reinterpret_cast<WNDPROC>(ptr);
hr = Win::SetWindowLongPtr(
hwnd,
GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(ReplacementWndProc));
ASSERT(SUCCEEDED(hr));
}
}
return 0;
}
ExitCode
RunWizard()
{
LOG_FUNCTION(RunWizard);
ExitCode exitCode = EXIT_CODE_SUCCESSFUL;
UINT startPage = GetStartPage();
State::GetInstance().SetStartPage(startPage);
// Create the wizard and add all the pages
Wizard wiz(
IDS_WIZARD_TITLE,
IDB_BANNER16,
IDB_BANNER256,
IDB_WATERMARK16,
IDB_WATERMARK256);
// NOTE: Do not change the order of the following
// page additions. They are important for being able
// to start the wizard at one of these pages directly.
// The order of these pages cooresponds directly to
// the order of the StartPages enum above
wiz.AddPage(new WelcomePage()); // CYS_WELCOME_PAGE
wiz.AddPage(new BeforeBeginPage()); // CYS_BEFORE_BEGIN_PAGE
wiz.AddPage(new ExpressRebootPage()); // CYS_EXPRESS_REBOOT_PAGE
wiz.AddPage(new FinishPage()); // CYS_FINISH_PAGE
//
//
//
wiz.AddPage(new DecisionPage());
wiz.AddPage(new CustomServerPage());
wiz.AddPage(new ADDomainPage());
wiz.AddPage(new NetbiosDomainPage());
wiz.AddPage(new DNSForwarderPage());
wiz.AddPage(new ExpressDNSPage());
wiz.AddPage(new ExpressDHCPPage());
wiz.AddPage(new PrintServerPage());
wiz.AddPage(new FileServerPage());
wiz.AddPage(new IndexingPage());
wiz.AddPage(new MilestonePage());
wiz.AddPage(new UninstallMilestonePage());
wiz.AddPage(new InstallationProgressPage());
wiz.AddPage(new UninstallProgressPage());
wiz.AddPage(new WebApplicationPage());
wiz.AddPage(new POP3Page());
// Run the wizard
switch (wiz.ModalExecute(
0,
startPage,
SheetCallbackProc))
{
case -1:
{
/* popup.Error(
Win::GetDesktopWindow(),
E_FAIL,
IDS_PROP_SHEET_FAILED);
*/
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
case ID_PSREBOOTSYSTEM:
{
// we can infer that if we are supposed to reboot, then the
// operation was successful.
exitCode = EXIT_CODE_SUCCESSFUL;
break;
}
default:
{
// do nothing.
break;
}
}
return exitCode;
}
ExitCode
Start()
{
LOG_FUNCTION(Start);
ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
do
{
// Put any checks that should stop the wizard from running here...
// User must be an Administrator
bool isAdmin = ::IsCurrentUserAdministrator();
if (!isAdmin)
{
LOG(L"Current user is not an Administrator");
// Since the user is not an administrator
// close the mutex so that a non-admin can't
// leave this message box up and prevent
// an administrator from running CYS
Win::CloseHandle(cysRunningMutex);
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_NOT_ADMIN,
MB_OK);
// State::GetInstance().SetRerunWizard(false);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
// The Sys OC Manager cannot be running
if (State::GetInstance().IsWindowsSetupRunning())
{
LOG(L"Windows setup is running");
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_WINDOWS_SETUP_RUNNING_DURING_CYS_STARTUP,
MB_OK);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
// Machine cannot be in the middle of a DC upgrade
if (State::GetInstance().IsUpgradeState())
{
LOG(L"Machine needs to complete DC upgrade");
String commandline = Win::GetCommandLine();
// If we were launched from explorer then
// don't show the message, just exit silently
if (commandline.find(EXPLORER_SWITCH) == String::npos)
{
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_DC_UPGRADE_NOT_COMPLETE,
MB_OK);
}
// State::GetInstance().SetRerunWizard(false);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
// Machine cannot have DCPROMO running or a reboot pending
if (State::GetInstance().IsDCPromoRunning())
{
LOG(L"DCPROMO is running");
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_DCPROMO_RUNNING,
MB_OK);
// State::GetInstance().SetRerunWizard(false);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
else if (State::GetInstance().IsDCPromoPendingReboot())
{
LOG(L"DCPROMO was run, pending reboot");
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_DCPROMO_PENDING_REBOOT,
MB_OK);
// State::GetInstance().SetRerunWizard(false);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
DWORD productSKU = State::GetInstance().RetrieveProductSKU();
if (CYS_UNSUPPORTED_SKU == productSKU)
{
LOG(L"Cannot run CYS on any SKU but servers");
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_SERVER_ONLY,
MB_OK);
// State::GetInstance().SetRerunWizard(false);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
// The machine cannot be a member of a cluster
if (IsClusterServer())
{
LOG(L"Machine is a member of a cluster");
Win::CloseHandle(cysRunningMutex);
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_CLUSTER,
MB_OK);
exitCode = EXIT_CODE_UNSUCCESSFUL;
break;
}
// We can run the wizard. Yea!!!
exitCode = RunWizard();
}
while (0);
LOG(String::format(L"exitCode = %1!d!", static_cast<int>(exitCode)));
return exitCode;
}
int WINAPI
WinMain(
HINSTANCE hInstance,
HINSTANCE /* hPrevInstance */ ,
PSTR /* lpszCmdLine */ ,
int /* nCmdShow */)
{
hResourceModuleHandle = hInstance;
ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
String mutexName = L"Global\\";
mutexName += RUNTIME_NAME;
HRESULT hr = Win::CreateMutex(0, true, mutexName, cysRunningMutex);
if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS))
{
// First close the handle so that the owner can reacquire if they
// restart
Win::CloseHandle(cysRunningMutex);
// Now show the error message
popup.MessageBox(
Win::GetDesktopWindow(),
IDS_ALREADY_RUNNING,
MB_OK);
}
else
{
do
{
hr = ::CoInitialize(0);
if (FAILED(hr))
{
ASSERT(SUCCEEDED(hr));
break;
}
// Initialize the common controls so that we can use
// animation in the NetDetectProgressDialog
INITCOMMONCONTROLSEX commonControlsEx;
commonControlsEx.dwSize = sizeof(commonControlsEx);
commonControlsEx.dwICC = ICC_ANIMATE_CLASS;
BOOL init = ::InitCommonControlsEx(&commonControlsEx);
ASSERT(init);
// For now there is no more rerunning CYS
// do
// {
exitCode = Start();
// } while(State::GetInstance().RerunWizard());
InstallationUnitProvider::Destroy();
State::Destroy();
CoUninitialize();
} while(false);
}
if (brush)
{
// delete the background brush
(void)Win::DeleteObject(brush);
}
return static_cast<int>(exitCode);
}