示例#1
0
        static void Main()
        {
            PageViewTelemetry pvt = null;
            var startTime         = DateTimeOffset.UtcNow;

            using (GlobalChummerMutex = new Mutex(false, @"Global\" + strChummerGuid))
            {
                IsMono = Type.GetType("Mono.Runtime") != null;
                // Mono doesn't always play nice with ProfileOptimization, so it's better to just not bother with it when running under Mono
                if (!IsMono)
                {
                    ProfileOptimization.SetProfileRoot(Utils.GetStartupPath);
                    ProfileOptimization.StartProfile("chummerprofile");
                }

                Stopwatch sw = Stopwatch.StartNew();
                //If debuging and launched from other place (Bootstrap), launch debugger
                if (Environment.GetCommandLineArgs().Contains("/debug") && !Debugger.IsAttached)
                {
                    Debugger.Launch();
                }
                sw.TaskEnd("dbgchk");
                //Various init stuff (that mostly "can" be removed as they serve
                //debugging more than function


                //Needs to be called before Log is setup, as it moves where log might be.
                FixCwd();


                sw.TaskEnd("fixcwd");

                AppDomain.CurrentDomain.FirstChanceException += ExceptionHeatmap.OnException;

                sw.TaskEnd("appdomain 2");

                string strInfo =
                    $"Application Chummer5a build {System.Reflection.Assembly.GetExecutingAssembly().GetName().Version} started at {DateTime.UtcNow} with command line arguments {Environment.CommandLine}";
                sw.TaskEnd("infogen");

                sw.TaskEnd("infoprnt");

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                sw.TaskEnd("languagefreestartup");
#if !DEBUG
                AppDomain.CurrentDomain.UnhandledException += (o, e) =>
                {
                    if (e.ExceptionObject is Exception ex)
                    {
                        CrashHandler.WebMiniDumpHandler(ex);
                    }

                    //main.Hide();
                    //main.ShowInTaskbar = false;
                };
#endif
                AppDomain.CurrentDomain.UnhandledException += (o, e) =>
                {
                    try
                    {
                        if (e.ExceptionObject is Exception myException)
                        {
                            TelemetryClient tc = new TelemetryClient();
                            tc.TrackException(myException);
                        }
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                    }
                };


                sw.TaskEnd("Startup");


                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

                if (!string.IsNullOrEmpty(LanguageManager.ManagerErrorMessage))
                {
                    MessageBox.Show(LanguageManager.ManagerErrorMessage, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                if (!string.IsNullOrEmpty(GlobalOptions.ErrorMessage))
                {
                    MessageBox.Show(GlobalOptions.ErrorMessage, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                try
                {
                    LogManager.ThrowExceptions = true;
                    ConfigurationItemFactory.Default.Targets.RegisterDefinition(
                        "ApplicationInsightsTarget",
                        typeof(Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget)
                        );
                    LogManager.ThrowExceptions = false;
                    Log = NLog.LogManager.GetCurrentClassLogger();
                    if (GlobalOptions.UseLogging)
                    {
                        foreach (var rule in NLog.LogManager.Configuration.LoggingRules.ToList())
                        {
                            //only change the loglevel, if it's off - otherwise it has been changed manually
                            if (rule.Levels.Count == 0)
                            {
                                rule.EnableLoggingForLevels(LogLevel.Debug, LogLevel.Fatal);
                            }
                        }
                    }
                    Log.Info(strInfo);



                    if (GlobalOptions.UseLoggingApplicationInsights)
                    {
#if DEBUG
                        //If you set true as DeveloperMode (see above), you can see the sending telemetry in the debugging output window in IDE.
                        TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = true;
#else
                        TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = false;
#endif
                        TelemetryConfiguration.Active.TelemetryInitializers.Add(new CustomTelemetryInitializer());
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use((next) => new TranslateExceptionTelemetryProcessor(next));
                        var replacePath = Environment.UserName;
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use((next) => new DropUserdataTelemetryProcessor(next, replacePath));
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Build();
                        //for now lets disable live view. We may make another GlobalOption to enable it at a later stage...
                        //var live = new LiveStreamProvider(ApplicationInsightsConfig);
                        //live.Enable();

                        //Log an Event with AssemblyVersion and CultureInfo

                        if (Properties.Settings.Default.UploadClientId == Guid.Empty)
                        {
                            Properties.Settings.Default.UploadClientId = Guid.NewGuid();
                            Properties.Settings.Default.Save();
                        }
                        MetricIdentifier mi = new MetricIdentifier("Chummer", "Program Start", "Version", "Culture");
                        var metric          = TelemetryClient.GetMetric(mi);
                        metric.TrackValue(1,
                                          Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                                          CultureInfo.CurrentUICulture.TwoLetterISOLanguageName);

                        // Log a page view:
                        pvt = new PageViewTelemetry("frmChummerMain()")
                        {
                            Name = "Chummer Startup: " +
                                   System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
                        };
                        pvt.Id = Properties.Settings.Default.UploadClientId.ToString();
                        pvt.Context.Operation.Name = "Operation Program.Main()";
                        pvt.Properties.Add("parameters", Environment.CommandLine);
                        pvt.Timestamp = startTime;

                        UploadObjectAsMetric.UploadObject(TelemetryClient, typeof(GlobalOptions));
                    }
                    else
                    {
                        TelemetryConfiguration.Active.DisableTelemetry = true;
                    }
                    if (Utils.IsUnitTest)
                    {
                        TelemetryConfiguration.Active.DisableTelemetry = true;
                    }

                    //make sure the Settings are upgraded/preserved after an upgrade
                    //see for details: https://stackoverflow.com/questions/534261/how-do-you-keep-user-config-settings-across-different-assembly-versions-in-net/534335#534335
                    if (Properties.Settings.Default.UpgradeRequired)
                    {
                        if (UnblockPath(AppDomain.CurrentDomain.BaseDirectory))
                        {
                            Properties.Settings.Default.Upgrade();
                            Properties.Settings.Default.UpgradeRequired = false;
                            Properties.Settings.Default.Save();
                        }
                        else
                        {
                            Log.Warn("Files could not be unblocked in " + AppDomain.CurrentDomain.BaseDirectory);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    Log.Error(e);
                }


                // Make sure the default language has been loaded before attempting to open the Main Form.
                LanguageManager.TranslateWinForm(GlobalOptions.Language, null);

                MainForm = new frmChummerMain(false, pvt);
                Application.Run(MainForm);
                Log.Info(ExceptionHeatmap.GenerateInfo());
                if (GlobalOptions.UseLoggingApplicationInsights)
                {
                    if (TelemetryClient != null)
                    {
                        //if (pvt != null)
                        //{
                        //    pvt.Duration = DateTimeOffset.UtcNow - pvt.Timestamp;
                        //    ApplicationInsightsTelemetryClient.TrackPageView(pvt);
                        //}
                        TelemetryClient.Flush();
                        //we have to wait a bit to give it time to upload the data
                        Console.WriteLine("Waiting a bit to flush logging data...");
                        Thread.Sleep(5000);
                    }
                }
            }
        }
示例#2
0
        static void Main()
        {
            //for some fun try out this command line parameter: chummer://plugin:SINners:Load:5ff55b9d-7d1c-4067-a2f5-774127346f4e
            PageViewTelemetry pvt = null;
            var startTime         = DateTimeOffset.UtcNow;

            using (GlobalChummerMutex = new Mutex(false, @"Global\" + strChummerGuid))
            {
                // Set default cultures based on the currently set language
                CultureInfo.DefaultThreadCurrentCulture   = GlobalOptions.CultureInfo;
                CultureInfo.DefaultThreadCurrentUICulture = GlobalOptions.CultureInfo;
                string strPostErrorMessage   = string.Empty;
                string settingsDirectoryPath = Path.Combine(Utils.GetStartupPath, "settings");
                if (!Directory.Exists(settingsDirectoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(settingsDirectoryPath);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        string strMessage = LanguageManager.GetString("Message_Insufficient_Permissions_Warning", GlobalOptions.Language, false);
                        if (string.IsNullOrEmpty(strMessage))
                        {
                            strMessage = ex.ToString();
                        }
                        strPostErrorMessage = strMessage;
                    }
                    catch (Exception ex)
                    {
                        strPostErrorMessage = ex.ToString();
                    }
                }
                IsMono = Type.GetType("Mono.Runtime") != null;
                // Mono doesn't always play nice with ProfileOptimization, so it's better to just not bother with it when running under Mono
                if (!IsMono)
                {
                    ProfileOptimization.SetProfileRoot(Utils.GetStartupPath);
                    ProfileOptimization.StartProfile("chummerprofile");
                }

                Stopwatch sw = Stopwatch.StartNew();
                //If debugging and launched from other place (Bootstrap), launch debugger
                if (Environment.GetCommandLineArgs().Contains("/debug") && !Debugger.IsAttached)
                {
                    Debugger.Launch();
                }
                sw.TaskEnd("dbgchk");
                //Various init stuff (that mostly "can" be removed as they serve
                //debugging more than function


                //Needs to be called before Log is setup, as it moves where log might be.
                FixCwd();


                sw.TaskEnd("fixcwd");

                AppDomain.CurrentDomain.FirstChanceException += ExceptionHeatMap.OnException;

                sw.TaskEnd("appdomain 2");

                string strInfo =
                    string.Format(GlobalOptions.InvariantCultureInfo, "Application Chummer5a build {0} started at {1} with command line arguments {2}",
                                  Assembly.GetExecutingAssembly().GetName().Version, DateTime.UtcNow, Environment.CommandLine);
                sw.TaskEnd("infogen");

                sw.TaskEnd("infoprnt");

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                sw.TaskEnd("languagefreestartup");
#if !DEBUG
                AppDomain.CurrentDomain.UnhandledException += (o, e) =>
                {
                    if (e.ExceptionObject is Exception ex)
                    {
                        CrashHandler.WebMiniDumpHandler(ex);
                    }

                    //main.Hide();
                    //main.ShowInTaskbar = false;
                };
#else
                AppDomain.CurrentDomain.UnhandledException += (o, e) =>
                {
                    try
                    {
                        if (e.ExceptionObject is Exception myException)
                        {
                            myException.Data.Add("IsCrash", bool.TrueString);
                            ExceptionTelemetry et = new ExceptionTelemetry(myException)
                            {
                                SeverityLevel = SeverityLevel.Critical
                            };
                            //we have to enable the uploading of THIS message, so it isn't filtered out in the DropUserdataTelemetryProcessos
                            foreach (DictionaryEntry d in myException.Data)
                            {
                                if (d.Key != null && d.Value != null)
                                {
                                    et.Properties.Add(d.Key.ToString(), d.Value.ToString());
                                }
                            }
                            ChummerTelemetryClient.TrackException(myException);
                            ChummerTelemetryClient.Flush();
                        }
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                    }
                };
#endif

                sw.TaskEnd("Startup");

                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

                if (!string.IsNullOrEmpty(LanguageManager.ManagerErrorMessage))
                {
                    // MainForm is null at the moment, so we have to show error box manually
                    MessageBox.Show(LanguageManager.ManagerErrorMessage, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                if (!string.IsNullOrEmpty(GlobalOptions.ErrorMessage))
                {
                    // MainForm is null at the moment, so we have to show error box manually
                    MessageBox.Show(GlobalOptions.ErrorMessage, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                if (!string.IsNullOrEmpty(strPostErrorMessage))
                {
                    // MainForm is null at the moment, so we have to show error box manually
                    MessageBox.Show(strPostErrorMessage, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                try
                {
                    TelemetryConfiguration.Active.InstrumentationKey = "012fd080-80dc-4c10-97df-4f2cf8c805d5";
                    LogManager.ThrowExceptions = true;
                    if (GlobalOptions.UseLoggingApplicationInsights > UseAILogging.OnlyMetric)
                    {
                        ConfigurationItemFactory.Default.Targets.RegisterDefinition(
                            "ApplicationInsightsTarget",
                            typeof(ApplicationInsightsTarget)
                            );
                    }

                    LogManager.ThrowExceptions = false;
                    Log = LogManager.GetCurrentClassLogger();
                    if (GlobalOptions.UseLogging)
                    {
                        foreach (LoggingRule objRule in LogManager.Configuration.LoggingRules)
                        {
#if DEBUG
                            //enable logging to EventLog when Debugging
                            if (objRule.Levels.Count == 0 && objRule.RuleName == "ELChummer")
                            {
                                objRule.EnableLoggingForLevels(LogLevel.Trace, LogLevel.Fatal);
                            }
#endif
                            //only change the loglevel, if it's off - otherwise it has been changed manually
                            if (objRule.Levels.Count == 0)
                            {
                                objRule.EnableLoggingForLevels(LogLevel.Debug, LogLevel.Fatal);
                            }
                        }
                    }

                    if (Properties.Settings.Default.UploadClientId == Guid.Empty)
                    {
                        Properties.Settings.Default.UploadClientId = Guid.NewGuid();
                        Properties.Settings.Default.Save();
                    }

                    if (!Utils.IsUnitTest && GlobalOptions.UseLoggingApplicationInsights >= UseAILogging.OnlyMetric)
                    {
#if DEBUG
                        //If you set true as DeveloperMode (see above), you can see the sending telemetry in the debugging output window in IDE.
                        TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = true;
#else
                        TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = false;
#endif
                        TelemetryConfiguration.Active.TelemetryInitializers.Add(new CustomTelemetryInitializer());
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use(next => new TranslateExceptionTelemetryProcessor(next));
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use(next => new DropUserdataTelemetryProcessor(next, Environment.UserName));
                        TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Build();
                        //for now lets disable live view.We may make another GlobalOption to enable it at a later stage...
                        //var live = new LiveStreamProvider(ApplicationInsightsConfig);
                        //live.Enable();

                        //Log an Event with AssemblyVersion and CultureInfo
                        MetricIdentifier objMetricIdentifier = new MetricIdentifier("Chummer", "Program Start", "Version", "Culture", dimension3Name: "AISetting", dimension4Name: "OSVersion");
                        string           strOSVersion        = helpers.Application_Insights.OSVersion.GetOSInfo();
                        Metric           objMetric           = ChummerTelemetryClient.GetMetric(objMetricIdentifier);
                        objMetric.TrackValue(1,
                                             Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                                             CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
                                             GlobalOptions.UseLoggingApplicationInsights.ToString(),
                                             strOSVersion);

                        //Log a page view:
                        pvt = new PageViewTelemetry("frmChummerMain()")
                        {
                            Name = "Chummer Startup: " +
                                   Assembly.GetExecutingAssembly().GetName().Version,
                            Id        = Properties.Settings.Default.UploadClientId.ToString(),
                            Timestamp = startTime
                        };
                        pvt.Context.Operation.Name = "Operation Program.Main()";
                        pvt.Properties.Add("parameters", Environment.CommandLine);

                        UploadObjectAsMetric.UploadObject(ChummerTelemetryClient, typeof(GlobalOptions));
                    }
                    else
                    {
                        TelemetryConfiguration.Active.DisableTelemetry = true;
                    }

                    Log.Info(strInfo);
                    Log.Info("Logging options are set to " + GlobalOptions.UseLogging + " and Upload-Options are set to "
                             + GlobalOptions.UseLoggingApplicationInsights + " (Installation-Id: "
                             + Properties.Settings.Default.UploadClientId.ToString("D", GlobalOptions.InvariantCultureInfo) + ").");

                    //make sure the Settings are upgraded/preserved after an upgrade
                    //see for details: https://stackoverflow.com/questions/534261/how-do-you-keep-user-config-settings-across-different-assembly-versions-in-net/534335#534335
                    if (Properties.Settings.Default.UpgradeRequired)
                    {
                        if (UnblockPath(AppDomain.CurrentDomain.BaseDirectory))
                        {
                            Properties.Settings.Default.Upgrade();
                            Properties.Settings.Default.UpgradeRequired = false;
                            Properties.Settings.Default.Save();
                        }
                        else
                        {
                            Log.Warn("Files could not be unblocked in " + AppDomain.CurrentDomain.BaseDirectory);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    Log.Error(e);
#if DEBUG
                    throw;
#endif
                }

                //load the plugins and maybe work of any command line arguments
                //arguments come in the form of
                //              /plugin:Name:Parameter:Argument
                //              /plugin:SINners:RegisterUriScheme:0
                bool showMainForm = !Utils.IsUnitTest;
                // Make sure the default language has been loaded before attempting to open the Main Form.
                LanguageManager.LoadLanguage(GlobalOptions.Language);
                MainForm = new frmChummerMain();
                try
                {
                    PluginLoader.LoadPlugins(null);
                }
                catch (ApplicationException)
                {
                    showMainForm = false;
                }
                if (!Utils.IsUnitTest)
                {
                    string[] strArgs = Environment.GetCommandLineArgs();
                    try
                    {
                        // Process plugin args synchronously because plugin load order can end up mattering
                        foreach (string strArg in strArgs)
                        {
                            if (!strArg.Contains("/plugin"))
                            {
                                continue;
                            }
                            if (!GlobalOptions.PluginsEnabled)
                            {
                                string strMessage = "Please enable Plugins to use command-line arguments invoking specific plugin-functions!";
                                Log.Warn(strMessage);
                                MainForm.ShowMessageBox(strMessage, "Plugins not enabled", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            }
                            else
                            {
                                string strWhatPlugin = strArg.Substring(strArg.IndexOf("/plugin", StringComparison.Ordinal) + 8);
                                //some external apps choose to add a '/' before a ':' even in the middle of an url...
                                strWhatPlugin = strWhatPlugin.TrimStart(':');
                                int    intEndPlugin = strWhatPlugin.IndexOf(':');
                                string strParameter = strWhatPlugin.Substring(intEndPlugin + 1);
                                strWhatPlugin = strWhatPlugin.Substring(0, intEndPlugin);
                                IPlugin objActivePlugin = PluginLoader.MyActivePlugins.FirstOrDefault(a => a.ToString() == strWhatPlugin);
                                if (objActivePlugin == null)
                                {
                                    if (PluginLoader.MyPlugins.All(a => a.ToString() != strWhatPlugin))
                                    {
                                        string strMessage = "Plugin " + strWhatPlugin + " is not enabled in the options!" + Environment.NewLine
                                                            + "If you want to use command-line arguments, please enable this plugin and restart the program.";
                                        Log.Warn(strMessage);
                                        MainForm.ShowMessageBox(strMessage, strWhatPlugin + " not enabled", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                                    }
                                }
                                else
                                {
                                    showMainForm &= objActivePlugin.ProcessCommandLine(strParameter);
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        ExceptionTelemetry ex = new ExceptionTelemetry(e)
                        {
                            SeverityLevel = SeverityLevel.Warning
                        };
                        ChummerTelemetryClient?.TrackException(ex);
                        Log.Warn(e);
                    }
                }
                if (showMainForm)
                {
                    MainForm.MyStartupPVT = pvt;
                    Application.Run(MainForm);
                }
                PluginLoader?.Dispose();
                Log.Info(ExceptionHeatMap.GenerateInfo());
                if (GlobalOptions.UseLoggingApplicationInsights > UseAILogging.OnlyLocal &&
                    ChummerTelemetryClient != null)
                {
                    ChummerTelemetryClient.Flush();
                    //we have to wait a bit to give it time to upload the data
                    Console.WriteLine("Waiting a bit to flush logging data...");
                    Thread.Sleep(2000);
                }
            }
        }
示例#3
0
        private static void Main()
        {
            // Set DPI Stuff before anything else, even the mutex
            SetProcessDPI(GlobalSettings.DpiScalingMethodSetting);
            if (IsMainThread)
            {
                SetThreadDPI(GlobalSettings.DpiScalingMethodSetting);
            }
            using (GlobalChummerMutex = new Mutex(false, @"Global\" + ChummerGuid, out bool blnIsNewInstance))
            {
                try
                {
                    try
                    {
                        // Chummer instance already exists, so switch to it instead of opening a new instance
                        if (!blnIsNewInstance || !GlobalChummerMutex.WaitOne(TimeSpan.FromSeconds(2), false))
                        {
                            // Try to get the main chummer process by fetching the Chummer process with the earliest start time
                            Process objMainChummerProcess = MyProcess;
                            foreach (Process objLoopProcess in Process.GetProcessesByName(MyProcess.ProcessName))
                            {
                                if (objLoopProcess.StartTime.Ticks < objMainChummerProcess.StartTime.Ticks)
                                {
                                    objMainChummerProcess = objLoopProcess;
                                }
                            }

                            if (objMainChummerProcess != MyProcess)
                            {
                                NativeMethods.SendMessage(objMainChummerProcess.MainWindowHandle,
                                                          NativeMethods.WM_SHOWME, 0, IntPtr.Zero);

                                string strCommandLineArgumentsJoined =
                                    string.Join("<>", Environment.GetCommandLineArgs());
                                NativeMethods.CopyDataStruct objData = new NativeMethods.CopyDataStruct();
                                IntPtr ptrCommandLineArguments       = IntPtr.Zero;
                                try
                                {
                                    // Allocate memory for the data and copy
                                    objData = NativeMethods.CopyDataFromString(CommandLineArgsDataTypeId, strCommandLineArgumentsJoined);
                                    ptrCommandLineArguments = Marshal.AllocCoTaskMem(Marshal.SizeOf(objData));
                                    Marshal.StructureToPtr(objData, ptrCommandLineArguments, false);
                                    // Send the message
                                    NativeMethods.SendMessage(objMainChummerProcess.MainWindowHandle,
                                                              NativeMethods.WM_COPYDATA, 0, ptrCommandLineArguments);
                                }
                                finally
                                {
                                    // Free the allocated memory after the control has been returned
                                    if (ptrCommandLineArguments != IntPtr.Zero)
                                    {
                                        Marshal.FreeCoTaskMem(ptrCommandLineArguments);
                                    }
                                    if (objData.lpData != IntPtr.Zero)
                                    {
                                        Marshal.FreeHGlobal(objData.lpData);
                                    }
                                }
                            }

                            return;
                        }
                    }
                    catch (AbandonedMutexException e)
                    {
                        Log.Info(e);
                    }

                    //for some fun try out this command line parameter: chummer://plugin:SINners:Load:5ff55b9d-7d1c-4067-a2f5-774127346f4e
                    PageViewTelemetry pvt       = null;
                    DateTimeOffset    startTime = DateTimeOffset.UtcNow;
                    // Set default cultures based on the currently set language
                    CultureInfo.DefaultThreadCurrentCulture   = GlobalSettings.CultureInfo;
                    CultureInfo.DefaultThreadCurrentUICulture = GlobalSettings.CultureInfo;
                    string strPostErrorMessage   = string.Empty;
                    string settingsDirectoryPath = Path.Combine(Utils.GetStartupPath, "settings");
                    if (!Directory.Exists(settingsDirectoryPath))
                    {
                        try
                        {
                            Directory.CreateDirectory(settingsDirectoryPath);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            string strMessage = LanguageManager.GetString("Message_Insufficient_Permissions_Warning",
                                                                          GlobalSettings.Language, false);
                            if (string.IsNullOrEmpty(strMessage))
                            {
                                strMessage = ex.ToString();
                            }
                            strPostErrorMessage = strMessage;
                        }
                        catch (Exception ex)
                        {
                            strPostErrorMessage = ex.ToString();
                        }
                    }

                    IsMono = Type.GetType("Mono.Runtime") != null;
                    // Delete old ProfileOptimization file because we don't want it anymore, instead we restart profiling for each newly generated assembly
                    Utils.SafeDeleteFile(Path.Combine(Utils.GetStartupPath, "chummerprofile"));
                    // We avoid weird issues with ProfileOptimization pointing JIT to the wrong place by checking for and removing all profile optimization files that
                    // were made in an older version (i.e. an older assembly)
                    string strProfileOptimizationName = "chummerprofile_" + Utils.CurrentChummerVersion + ".profile";
                    foreach (string strProfileFile in Directory.GetFiles(Utils.GetStartupPath, "*.profile", SearchOption.TopDirectoryOnly))
                    {
                        if (!string.Equals(strProfileFile, strProfileOptimizationName,
                                           StringComparison.OrdinalIgnoreCase))
                        {
                            Utils.SafeDeleteFile(strProfileFile);
                        }
                    }
                    // Mono, non-Windows native stuff, and Win11 don't always play nice with ProfileOptimization, so it's better to just not bother with it when running under them
                    if (!IsMono && Utils.HumanReadableOSVersion.StartsWith("Windows") && !Utils.HumanReadableOSVersion.StartsWith("Windows 11"))
                    {
                        ProfileOptimization.SetProfileRoot(Utils.GetStartupPath);
                        ProfileOptimization.StartProfile(strProfileOptimizationName);
                    }

                    Stopwatch sw = Stopwatch.StartNew();
                    //If debugging and launched from other place (Bootstrap), launch debugger
                    if (Environment.GetCommandLineArgs().Contains("/debug") && !Debugger.IsAttached)
                    {
                        Debugger.Launch();
                    }

                    sw.TaskEnd("dbgchk");
                    //Various init stuff (that mostly "can" be removed as they serve
                    //debugging more than function

                    //Needs to be called before Log is setup, as it moves where log might be.
                    FixCwd();

                    sw.TaskEnd("fixcwd");

                    AppDomain.CurrentDomain.FirstChanceException += ExceptionHeatMap.OnException;

                    sw.TaskEnd("appdomain 2");

                    string strInfo =
                        string.Format(GlobalSettings.InvariantCultureInfo,
                                      "Application Chummer5a build {0} started at {1} with command line arguments {2}",
                                      Utils.CurrentChummerVersion, DateTime.UtcNow,
                                      Environment.CommandLine);
                    sw.TaskEnd("infogen");

                    sw.TaskEnd("infoprnt");

                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);

                    sw.TaskEnd("languagefreestartup");

                    void HandleCrash(object o, UnhandledExceptionEventArgs exa)
                    {
                        if (exa.ExceptionObject is Exception ex)
                        {
                            try
                            {
                                if (GlobalSettings.UseLoggingApplicationInsights >= UseAILogging.Crashes &&
                                    ChummerTelemetryClient != null &&
                                    !Utils.IsMilestoneVersion)
                                {
                                    ExceptionTelemetry et = new ExceptionTelemetry(ex)
                                    {
                                        SeverityLevel = SeverityLevel.Critical
                                    };
                                    //we have to enable the uploading of THIS message, so it isn't filtered out in the DropUserdataTelemetryProcessos
                                    foreach (DictionaryEntry d in ex.Data)
                                    {
                                        if ((d.Key != null) && (d.Value != null))
                                        {
                                            et.Properties.Add(d.Key.ToString(), d.Value.ToString());
                                        }
                                    }

                                    et.Properties.Add("IsCrash", bool.TrueString);
                                    CustomTelemetryInitializer ti = new CustomTelemetryInitializer();
                                    ti.Initialize(et);

                                    ChummerTelemetryClient.TrackException(et);
                                    ChummerTelemetryClient.Flush();
                                }
                            }
                            catch (Exception ex1)
                            {
                                Log.Error(ex1);
                            }
#if !DEBUG
                            CrashHandler.WebMiniDumpHandler(ex);
#endif
                        }
                    }

                    AppDomain.CurrentDomain.UnhandledException += HandleCrash;

                    sw.TaskEnd("Startup");

                    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

                    if (!string.IsNullOrEmpty(LanguageManager.ManagerErrorMessage))
                    {
                        // MainForm is null at the moment, so we have to show error box manually
                        MessageBox.Show(LanguageManager.ManagerErrorMessage, Application.ProductName,
                                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                    if (!string.IsNullOrEmpty(GlobalSettings.ErrorMessage))
                    {
                        // MainForm is null at the moment, so we have to show error box manually
                        MessageBox.Show(GlobalSettings.ErrorMessage, Application.ProductName, MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                        return;
                    }

                    if (!string.IsNullOrEmpty(strPostErrorMessage))
                    {
                        // MainForm is null at the moment, so we have to show error box manually
                        MessageBox.Show(strPostErrorMessage, Application.ProductName, MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                        return;
                    }

                    try
                    {
                        TelemetryConfiguration.Active.InstrumentationKey = "012fd080-80dc-4c10-97df-4f2cf8c805d5";
                        LogManager.ThrowExceptions = true;
                        if (IsMono)
                        {
                            //Mono Crashes because of Application Insights. Set Logging to local, when Mono Runtime is detected
                            GlobalSettings.UseLoggingApplicationInsights = UseAILogging.OnlyLocal;
                        }
                        if (GlobalSettings.UseLoggingApplicationInsights > UseAILogging.OnlyMetric)
                        {
                            ConfigurationItemFactory.Default.Targets.RegisterDefinition(
                                "ApplicationInsightsTarget",
                                typeof(ApplicationInsightsTarget)
                                );
                        }

                        LogManager.ThrowExceptions = false;
                        Log = LogManager.GetCurrentClassLogger();
                        if (GlobalSettings.UseLogging)
                        {
                            foreach (LoggingRule objRule in LogManager.Configuration.LoggingRules)
                            {
#if DEBUG
                                //enable logging to EventLog when Debugging
                                if (objRule.Levels.Count == 0 && objRule.RuleName == "ELChummer")
                                {
                                    objRule.EnableLoggingForLevels(LogLevel.Trace, LogLevel.Fatal);
                                }
#endif
                                //only change the loglevel, if it's off - otherwise it has been changed manually
                                if (objRule.Levels.Count == 0)
                                {
                                    objRule.EnableLoggingForLevels(LogLevel.Debug, LogLevel.Fatal);
                                }
                            }
                        }

                        if (Settings.Default.UploadClientId == Guid.Empty)
                        {
                            Settings.Default.UploadClientId = Guid.NewGuid();
                            Settings.Default.Save();
                        }

                        if (!Utils.IsUnitTest && GlobalSettings.UseLoggingApplicationInsights >= UseAILogging.OnlyMetric)
                        {
#if DEBUG
                            //If you set true as DeveloperMode (see above), you can see the sending telemetry in the debugging output window in IDE.
                            TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = true;
#else
                            TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = false;
#endif
                            TelemetryConfiguration.Active.TelemetryInitializers.Add(new CustomTelemetryInitializer());
                            TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use(next =>
                                                                                             new TranslateExceptionTelemetryProcessor(next));
                            TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Use(next =>
                                                                                             new DropUserdataTelemetryProcessor(next, Environment.UserName));
                            TelemetryConfiguration.Active.TelemetryProcessorChainBuilder.Build();
                            //for now lets disable live view.We may make another GlobalOption to enable it at a later stage...
                            //var live = new LiveStreamProvider(ApplicationInsightsConfig);
                            //live.Enable();

                            //Log an Event with AssemblyVersion and CultureInfo
                            MetricIdentifier objMetricIdentifier = new MetricIdentifier("Chummer", "Program Start",
                                                                                        "Version", "Culture", "AISetting", "OSVersion");
                            string strOSVersion = Utils.HumanReadableOSVersion;
                            Metric objMetric    = ChummerTelemetryClient.GetMetric(objMetricIdentifier);
                            objMetric.TrackValue(1,
                                                 Utils.CurrentChummerVersion.ToString(),
                                                 CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
                                                 GlobalSettings.UseLoggingApplicationInsights.ToString(),
                                                 strOSVersion);

                            //Log a page view:
                            pvt = new PageViewTelemetry("frmChummerMain()")
                            {
                                Name = "Chummer Startup: " +
                                       Utils.CurrentChummerVersion,
                                Id        = Settings.Default.UploadClientId.ToString(),
                                Timestamp = startTime
                            };
                            pvt.Context.Operation.Name = "Operation Program.Main()";
                            pvt.Properties.Add("parameters", Environment.CommandLine);

                            UploadObjectAsMetric.UploadObject(ChummerTelemetryClient, typeof(GlobalSettings));
                        }
                        else
                        {
                            TelemetryConfiguration.Active.DisableTelemetry = true;
                        }

                        Log.Info(strInfo);
                        Log.Info("Logging options are set to " + GlobalSettings.UseLogging +
                                 " and Upload-Options are set to "
                                 + GlobalSettings.UseLoggingApplicationInsights + " (Installation-Id: "
                                 + Settings.Default.UploadClientId.ToString("D",
                                                                            GlobalSettings.InvariantCultureInfo) + ").");

                        //make sure the Settings are upgraded/preserved after an upgrade
                        //see for details: https://stackoverflow.com/questions/534261/how-do-you-keep-user-config-settings-across-different-assembly-versions-in-net/534335#534335
                        if (Settings.Default.UpgradeRequired)
                        {
                            if (UnblockPath(AppDomain.CurrentDomain.BaseDirectory))
                            {
                                Settings.Default.Upgrade();
                                Settings.Default.UpgradeRequired = false;
                                Settings.Default.Save();
                            }
                            else
                            {
                                Log.Warn("Files could not be unblocked in " + AppDomain.CurrentDomain.BaseDirectory);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        Log.Error(e);
#if DEBUG
                        throw;
#endif
                    }

                    //load the plugins and maybe work of any command line arguments
                    //arguments come in the form of
                    //              /plugin:Name:Parameter:Argument
                    //              /plugin:SINners:RegisterUriScheme:0
                    bool showMainForm = !Utils.IsUnitTest;
                    bool blnRestoreDefaultLanguage;
                    try
                    {
                        // Make sure the default language has been loaded before attempting to open the Main Form.
                        blnRestoreDefaultLanguage = !LanguageManager.LoadLanguage(GlobalSettings.Language);
                    }
                    // This to catch and handle an extremely strange issue where Chummer tries to load a language it shouldn't and ends up
                    // dereferencing a null value that should be impossible by static code analysis. This code here is a failsafe so that
                    // it at least keeps working in English instead of crashing.
                    catch (NullReferenceException)
                    {
                        Utils.BreakIfDebug();
                        blnRestoreDefaultLanguage = true;
                    }

                    // Restore Chummer's language to en-US if we failed to load the default one.
                    if (blnRestoreDefaultLanguage)
                    {
                        GlobalSettings.Language = GlobalSettings.DefaultLanguage;
                    }
                    MainForm = new ChummerMainForm();
                    try
                    {
                        PluginLoader.LoadPlugins();
                    }
                    catch (ApplicationException)
                    {
                        showMainForm = false;
                    }

                    if (!Utils.IsUnitTest)
                    {
                        string[] strArgs = Environment.GetCommandLineArgs();
                        try
                        {
                            // Process plugin args synchronously because plugin load order can end up mattering
                            foreach (string strArg in strArgs)
                            {
                                if (!strArg.Contains("/plugin"))
                                {
                                    continue;
                                }
                                if (!GlobalSettings.PluginsEnabled)
                                {
                                    const string strMessage =
                                        "Please enable Plugins to use command-line arguments invoking specific plugin-functions!";
                                    Log.Warn(strMessage);
                                    MainForm.ShowMessageBox(strMessage, "Plugins not enabled", MessageBoxButtons.OK,
                                                            MessageBoxIcon.Exclamation);
                                }
                                else
                                {
                                    string strWhatPlugin =
                                        strArg.Substring(strArg.IndexOf("/plugin", StringComparison.Ordinal) + 8);
                                    //some external apps choose to add a '/' before a ':' even in the middle of an url...
                                    strWhatPlugin = strWhatPlugin.TrimStart(':');
                                    int    intEndPlugin = strWhatPlugin.IndexOf(':');
                                    string strParameter = strWhatPlugin.Substring(intEndPlugin + 1);
                                    strWhatPlugin = strWhatPlugin.Substring(0, intEndPlugin);
                                    IPlugin objActivePlugin =
                                        PluginLoader.MyActivePlugins.Find(a => a.ToString() == strWhatPlugin);
                                    if (objActivePlugin == null)
                                    {
                                        if (PluginLoader.MyPlugins.All(a => a.ToString() != strWhatPlugin))
                                        {
                                            string strMessage =
                                                "Plugin " + strWhatPlugin + " is not enabled in the options!" +
                                                Environment.NewLine
                                                + "If you want to use command-line arguments, please enable this plugin and restart the program.";
                                            Log.Warn(strMessage);
                                            MainForm.ShowMessageBox(strMessage, strWhatPlugin + " not enabled",
                                                                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                                        }
                                    }
                                    else
                                    {
                                        showMainForm &= objActivePlugin.ProcessCommandLine(strParameter);
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            ExceptionTelemetry ex = new ExceptionTelemetry(e)
                            {
                                SeverityLevel = SeverityLevel.Warning
                            };
                            ChummerTelemetryClient?.TrackException(ex);
                            Log.Warn(e);
                        }
                    }

                    // Delete the old executable if it exists (created by the update process).
                    Utils.SafeClearDirectory(Utils.GetStartupPath, "*.old");
                    // Purge the temporary directory
                    Utils.SafeClearDirectory(Utils.GetTempPath());

                    if (showMainForm)
                    {
                        MainForm.MyStartupPvt = pvt;
                        Application.Run(MainForm);
                    }

                    PluginLoader?.Dispose();
                    Log.Info(ExceptionHeatMap.GenerateInfo());
                    if (GlobalSettings.UseLoggingApplicationInsights > UseAILogging.OnlyLocal &&
                        ChummerTelemetryClient != null)
                    {
                        ChummerTelemetryClient.Flush();
                        //we have to wait a bit to give it time to upload the data
                        Console.WriteLine("Waiting a bit to flush logging data...");
                        Utils.SafeSleep(TimeSpan.FromSeconds(2));
                    }
                }
                finally
                {
                    GlobalChummerMutex.ReleaseMutex();
                }
            }
        }