1#region Copyright & License Information 2/* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10#endregion 11 12using System; 13using System.Diagnostics; 14using System.Drawing; 15using System.IO; 16using System.Linq; 17using System.Media; 18using System.Reflection; 19using System.Windows.Forms; 20 21namespace OpenRA 22{ 23 class WindowsLauncher 24 { 25 static Process gameProcess; 26 27 // Constants to be replaced by the wrapper / compilation script 28 const string ModID = "MOD_ID"; 29 const string DisplayName = "DISPLAY_NAME"; 30 const string FaqUrl = "FAQ_URL"; 31 32 [STAThread] 33 static int Main(string[] args) 34 { 35 if (args.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) 36 return RunGame(args); 37 38 return RunInnerLauncher(args); 39 } 40 41 static int RunGame(string[] args) 42 { 43 var launcherPath = Assembly.GetExecutingAssembly().Location; 44 var directory = Path.GetDirectoryName(launcherPath); 45 Directory.SetCurrentDirectory(directory); 46 47 AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); 48 49 try 50 { 51 return (int)Game.InitializeAndRun(args); 52 } 53 catch (Exception e) 54 { 55 ExceptionHandler.HandleFatalError(e); 56 return (int)RunStatus.Error; 57 } 58 } 59 60 static int RunInnerLauncher(string[] args) 61 { 62 var launcherPath = Assembly.GetExecutingAssembly().Location; 63 var launcherArgs = args.ToList(); 64 65 if (!launcherArgs.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) 66 launcherArgs.Add("Engine.LaunchPath=\"" + launcherPath + "\""); 67 68 if (!launcherArgs.Any(x => x.StartsWith("Game.Mod=", StringComparison.Ordinal))) 69 launcherArgs.Add("Game.Mod=" + ModID); 70 71 var psi = new ProcessStartInfo(launcherPath, string.Join(" ", launcherArgs)); 72 73 try 74 { 75 gameProcess = Process.Start(psi); 76 } 77 catch 78 { 79 return 1; 80 } 81 82 if (gameProcess == null) 83 return 1; 84 85 gameProcess.EnableRaisingEvents = true; 86 gameProcess.Exited += GameProcessExited; 87 88 Application.Run(); 89 90 return 0; 91 } 92 93 static void ShowErrorDialog() 94 { 95 var headerLabel = new Label 96 { 97 Location = new Point(0, 10), 98 Height = 15, 99 Text = DisplayName + " has encountered a fatal error and must close.", 100 TextAlign = ContentAlignment.TopCenter 101 }; 102 103 var docsLabel = new Label 104 { 105 Location = new Point(0, 25), 106 Height = 15, 107 Text = "Refer to the crash logs and FAQ for more information.", 108 TextAlign = ContentAlignment.TopCenter 109 }; 110 111 int formWidth; 112 using (var g = headerLabel.CreateGraphics()) 113 { 114 var headerWidth = (int)g.MeasureString(headerLabel.Text, headerLabel.Font).Width + 60; 115 var docsWidth = (int)g.MeasureString(docsLabel.Text, docsLabel.Font).Width + 60; 116 formWidth = Math.Max(headerWidth, docsWidth); 117 headerLabel.Width = formWidth; 118 docsLabel.Width = formWidth; 119 } 120 121 var form = new Form 122 { 123 Size = new Size(formWidth, 110), 124 Text = "Fatal Error", 125 MinimizeBox = false, 126 MaximizeBox = false, 127 FormBorderStyle = FormBorderStyle.FixedDialog, 128 StartPosition = FormStartPosition.CenterScreen, 129 TopLevel = true, 130 Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location) 131 }; 132 133 var viewLogs = new Button 134 { 135 Location = new Point(10, 50), 136 Size = new Size(75, 23), 137 Text = "View Logs" 138 }; 139 140 var viewFaq = new Button 141 { 142 Location = new Point(90, 50), 143 Size = new Size(75, 23), 144 Text = "View FAQ" 145 }; 146 147 var quit = new Button 148 { 149 Location = new Point(formWidth - 90, 50), 150 Size = new Size(75, 23), 151 Text = "Quit", 152 DialogResult = DialogResult.Cancel 153 }; 154 155 form.Controls.Add(headerLabel); 156 form.Controls.Add(docsLabel); 157 form.Controls.Add(viewLogs); 158 form.Controls.Add(viewFaq); 159 form.Controls.Add(quit); 160 161 viewLogs.Click += ViewLogsClicked; 162 viewFaq.Click += ViewFaqClicked; 163 form.FormClosed += FormClosed; 164 165 SystemSounds.Exclamation.Play(); 166 form.ShowDialog(); 167 } 168 169 static void GameProcessExited(object sender, EventArgs e) 170 { 171 if (gameProcess.ExitCode != (int)RunStatus.Success) 172 ShowErrorDialog(); 173 174 Exit(); 175 } 176 177 static void ViewLogsClicked(object sender, EventArgs e) 178 { 179 try 180 { 181 Process.Start(Platform.ResolvePath("^", "Logs")); 182 } 183 catch { } 184 } 185 186 static void ViewFaqClicked(object sender, EventArgs e) 187 { 188 try 189 { 190 Process.Start(FaqUrl); 191 } 192 catch { } 193 } 194 195 static void FormClosed(object sender, EventArgs e) 196 { 197 Exit(); 198 } 199 200 static void Exit() 201 { 202 Environment.Exit(0); 203 } 204 } 205} 206