2 * Copyright (c) 2000, Red Hat, Inc.
3 * Copyright (c) 2003, Robert Collins <rbtcollins@hotmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * A copy of the GNU General Public License can be found at
13 * Written by DJ Delorie <dj@cygnus.com>
14 * Robert Collins <rbtcollins@hotmail.com>
19 /* OK, here's how this works. Each of the steps needed for install -
20 dialogs, downloads, installs - are in their own files and have some
21 "do_*" function (prototype in dialog.h) and a resource id (IDD_* or
22 IDD_S_* in resource.h) for that step. Each step is responsible for
23 selecting the next step! See the NEXT macro in dialog.h. Note
24 that the IDD_S_* ids are fake; those are for steps that don't
25 really have a controlling dialog (some have progress dialogs, but
26 those don't count, although they could). Replace the IDD_S_* with
27 IDD_* if you create a real dialog for those steps. */
43 #include "setup_version.h"
46 #include "propsheet.h"
50 #include "AntiVirus.h"
61 #include "postinstallresults.h"
63 #include "getopt++/GetOption.h"
64 #include "getopt++/BoolOption.h"
65 #include "getopt++/StringOption.h"
67 #include "Exception.h"
70 #include "UserSettings.h"
71 #include "SourceSetting.h"
72 #include "ConnectionSetting.h"
73 #include "KeysSetting.h"
78 #ifdef __MINGW64_VERSION_MAJOR
83 bool is_new_install
= false;
84 std::string SetupArch
;
85 std::string SetupIniDir
;
89 static StringOption
Arch ("", 'a', "arch", "Architecture to install (x86_64 or x86)", false);
90 static BoolOption
UnattendedOption (false, 'q', "quiet-mode", "Unattended setup mode");
91 static BoolOption
PackageManagerOption (false, 'M', "package-manager", "Semi-attended chooser-only mode");
92 static BoolOption
NoAdminOption (false, 'B', "no-admin", "Do not check for and enforce running as Administrator");
93 static BoolOption
WaitOption (false, 'W', "wait", "When elevating, wait for elevated child process");
94 static BoolOption
HelpOption (false, 'h', "help", "Print help");
95 static BoolOption
VersionOption (false, 'V', "version", "Show version");
96 static StringOption
SetupBaseNameOpt ("setup", 'i', "ini-basename", "Use a different basename, e.g. \"foo\", instead of \"setup\"", false);
97 BoolOption
UnsupportedOption (false, '\0', "allow-unsupported-windows", "Allow old, unsupported Windows versions");
98 std::string SetupBaseName
;
103 HANDLE my_stdout
= GetStdHandle (STD_OUTPUT_HANDLE
);
104 if (my_stdout
!= INVALID_HANDLE_VALUE
&& GetFileType (my_stdout
) != FILE_TYPE_UNKNOWN
)
107 if (AttachConsole ((DWORD
) -1))
109 std::ofstream
*conout
= new std::ofstream ("conout$");
110 std::cout
.rdbuf (conout
->rdbuf ());
115 // Other threads talk to these pages, so we need to have it externable.
116 ThreeBarProgressPage Progress
;
117 PostInstallResultsPage PostInstallResults
;
122 /* nondisplay classes */
123 LocalDirSetting localDir
;
124 SourceSetting SourceSettings
;
125 ConnectionSetting ConnectionSettings
;
126 SiteSetting ChosenSites
;
127 ExtraKeysSetting ExtraKeys
;
130 AntiVirusPage AntiVirus
;
133 LocalDirPage LocalDir
;
139 DesktopSetupPage Desktop
;
140 PropSheet MainWindow
;
142 Log (LOG_TIMESTAMP
) << "Current Directory: " << local_dir
<< endLog
;
144 // Initialize common controls
145 INITCOMMONCONTROLSEX icce
= { sizeof (INITCOMMONCONTROLSEX
),
146 ICC_WIN95_CLASSES
| ICC_LISTVIEW_CLASSES
};
147 InitCommonControlsEx (&icce
);
149 // Initialize COM and ShellLink instance here. For some reason
150 // Windows 7 fails to create the ShellLink instance if this is
151 // done later, in the thread which actually creates the shortcuts.
152 extern IShellLink
*sl
;
153 CoInitializeEx (NULL
, COINIT_APARTMENTTHREADED
);
154 HRESULT res
= CoCreateInstance (CLSID_ShellLink
, NULL
,
155 CLSCTX_INPROC_SERVER
, IID_IShellLink
,
160 sprintf (buf
, "CoCreateInstance failed with error 0x%x.\n"
161 "Setup will not be able to create Cygwin Icons\n"
162 "in the Start Menu or on the Desktop.", (int) res
);
163 mbox (NULL
, buf
, "Cygwin Setup", MB_OK
);
166 // Init window class lib
167 Window::SetAppInstance (hinstance
);
181 PostInstallResults
.Create ();
184 // Add pages to sheet
185 MainWindow
.AddPage (&Splash
);
186 MainWindow
.AddPage (&AntiVirus
);
187 MainWindow
.AddPage (&Source
);
188 MainWindow
.AddPage (&Root
);
189 MainWindow
.AddPage (&LocalDir
);
190 MainWindow
.AddPage (&Net
);
191 MainWindow
.AddPage (&Site
);
192 MainWindow
.AddPage (&Chooser
);
193 MainWindow
.AddPage (&Prereq
);
194 MainWindow
.AddPage (&Confirm
);
195 MainWindow
.AddPage (&Progress
);
196 MainWindow
.AddPage (&PostInstallResults
);
197 MainWindow
.AddPage (&Desktop
);
199 // Create the PropSheet main window
200 MainWindow
.Create ();
209 WinMain (HINSTANCE h
,
210 HINSTANCE hPrevInstance
, LPSTR command_line
, int cmd_show
)
215 // Make sure the C runtime functions use the same codepage as the GUI
217 snprintf(locale
, sizeof locale
, ".%u", GetACP());
218 setlocale(LC_ALL
, locale
);
222 for (argc
= 0, _argv
= __argv
; *_argv
; _argv
++)
227 bool help_option
= false;
228 bool invalid_option
= false;
230 GetCurrentDirectory (MAX_PATH
, cwd
);
231 local_dir
= std::string (cwd
);
233 if (!GetOption::GetInstance ().Process (argc
,_argv
, NULL
))
234 help_option
= invalid_option
= true;
238 if (!((std::string
) Arch
).size ())
246 else if (((std::string
) Arch
).find ("64") != std::string::npos
)
248 else if (((std::string
) Arch
).find ("32") != std::string::npos
249 || ((std::string
) Arch
).find ("x86") != std::string::npos
)
253 char buff
[80 + ((std::string
) Arch
).size ()];
254 sprintf (buff
, "Invalid option for --arch: \"%s\"",
255 ((std::string
) Arch
).c_str ());
256 fprintf (stderr
, "*** %s\n", buff
);
257 mbox (NULL
, buff
, "Invalid option", MB_ICONEXCLAMATION
| MB_OK
);
261 unattended_mode
= PackageManagerOption
? chooseronly
262 : (UnattendedOption
? unattended
: attended
);
264 bool output_only
= help_option
|| VersionOption
;
266 SetupBaseName
= SetupBaseNameOpt
;
267 SetupArch
= is_64bit
? "x86_64" : "x86";
268 SetupIniDir
= SetupArch
+"/";
270 /* Initialize well known SIDs. We need the admin SID to test if we're
271 supposed to elevate. */
272 nt_sec
.initialiseWellKnownSIDs ();
273 /* Check if we have to elevate. */
274 bool elevate
= !output_only
&& OSMajorVersion () >= 6
275 && !NoAdminOption
&& !nt_sec
.isRunAsAdmin ();
277 if (unattended_mode
|| output_only
|| !elevate
)
280 /* Start logging only if we don't elevate. Same for setting default
281 security settings. */
282 LogSingleton::SetInstance (*LogFile::createLogFile ());
283 const char *sep
= isdirsep (local_dir
[local_dir
.size () - 1])
285 /* Don't create log files for help or version output only. */
286 if (!elevate
&& !output_only
)
288 Logger ().setFile (LOG_BABBLE
, local_dir
+ sep
+ "setup.log.full",
290 Logger ().setFile (0, local_dir
+ sep
+ "setup.log", true);
291 Log (LOG_PLAIN
) << "Starting cygwin install, version "
292 << setup_version
<< endLog
;
298 Log (LOG_PLAIN
) << "\nError during option processing.\n" << endLog
;
299 Log (LOG_PLAIN
) << "Cygwin setup " << setup_version
<< endLog
;
300 Log (LOG_PLAIN
) << "\nCommand Line Options:\n" << endLog
;
301 GetOption::GetInstance ().ParameterUsage (Log (LOG_PLAIN
));
302 Log (LOG_PLAIN
) << endLog
;
303 Log (LOG_PLAIN
) << "The default is to both download and install packages, unless either --download or --local-install is specified." << endLog
;
304 Logger ().exit (invalid_option
? 1 : 0, false);
310 Log (LOG_PLAIN
) << "Cygwin setup " << setup_version
<< endLog
;
311 Logger ().exit (0, false);
315 /* Check if Cygwin works on this Windows version */
316 if (!UnsupportedOption
&& (OSMajorVersion () < 6))
318 mbox (NULL
, "Cygwin is not supported on this Windows version",
319 "Cygwin Setup", MB_ICONEXCLAMATION
| MB_OK
);
320 Logger ().exit (1, false);
325 char exe_path
[MAX_PATH
];
326 if (!GetModuleFileName(NULL
, exe_path
, ARRAYSIZE(exe_path
)))
329 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
330 sei
.lpVerb
= "runas";
331 sei
.lpFile
= exe_path
;
332 sei
.nShow
= SW_NORMAL
;
334 sei
.fMask
|= SEE_MASK_NOCLOSEPROCESS
;
336 // Avoid another isRunAsAdmin check in the child.
337 std::string
command_line_cs (command_line
);
338 command_line_cs
+= " -";
339 command_line_cs
+= NoAdminOption
.shortOption();
340 sei
.lpParameters
= command_line_cs
.c_str ();
342 if (ShellExecuteEx(&sei
))
345 /* Wait until child process is finished. */
346 if (WaitOption
&& sei
.hProcess
!= NULL
)
347 if (!WaitForSingleObject (sei
.hProcess
, INFINITE
))
348 GetExitCodeProcess (sei
.hProcess
, &exitcode
);
349 Logger ().setExitMsg (IDS_ELEVATED
);
350 Logger ().exit (exitcode
, false);
352 Log (LOG_PLAIN
) << "Starting elevated child process failed" << endLog
;
353 Logger ().exit (1, false);
357 /* Set default DACL and Group. */
358 nt_sec
.setDefaultSecurity ((root_scope
== IDC_ROOT_SYSTEM
));
360 UserSettings Settings
;
361 UserSettings::instance().load (local_dir
);
363 Settings
.save (); // Clean exit.. save user options.
365 Logger ().setExitMsg (IDS_REBOOT_REQUIRED
);
366 Logger ().exit (rebootneeded
? IDS_REBOOT_REQUIRED
: 0);
371 TOPLEVEL_CATCH(NULL
, "main");