Beispiel #1
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         while (LockObject.IsReadLockHeld || LockObject.IsUpgradeableReadLockHeld || LockObject.IsUpgradeableReadLockHeld)
         {
             Utils.SafeSleep();
         }
         LockObject.Dispose();
     }
 }
        /// <summary>
        /// Alternative to Form.ShowDialog() that will not stall out unit tests.
        /// </summary>
        /// <param name="frmForm"></param>
        /// <param name="owner"></param>
        /// <returns></returns>
        public static DialogResult ShowDialogSafe(this Form frmForm, IWin32Window owner = null)
        {
            if (!Utils.IsUnitTest)
            {
                return(frmForm.ShowDialog(owner));
            }
            // Unit tests cannot use ShowDialog because that will stall them out
            bool blnDoClose = false;

            void FormOnShown(object sender, EventArgs args) => blnDoClose = true;

            frmForm.Shown        += FormOnShown;
            frmForm.ShowInTaskbar = false;
            frmForm.Show(owner);
            while (!blnDoClose)
            {
                Utils.SafeSleep(true);
            }
            frmForm.Close();
            return(frmForm.DialogResult);
        }
        private static void DoThreadSafeCore(this Control objControl, bool blnSync, Func <Task> funcToRun)
        {
            if (funcToRun == null)
            {
                return;
            }
            try
            {
                if (objControl.IsNullOrDisposed())
                {
                    if (blnSync)
                    {
                        Task tskRunning = funcToRun.Invoke();
                        if (tskRunning.Status == TaskStatus.Created)
                        {
                            tskRunning.RunSynchronously();
                        }
                        while (!tskRunning.IsCompleted)
                        {
                            Utils.SafeSleep();
                        }
                        if (tskRunning.Exception != null)
                        {
                            throw tskRunning.Exception;
                        }
                    }
                    else
                    {
                        Task.Run(() => funcToRun.Invoke().ContinueWith(x =>
                        {
                            if (x.Exception != null)
                            {
                                throw x.Exception;
                            }
                        }));
                    }
                }
                else
                {
                    // ReSharper disable once InlineTemporaryVariable
                    Control myControlCopy = objControl; //to have the Object for sure, regardless of other threads
                    if (myControlCopy.InvokeRequired)
                    {
                        IAsyncResult objResult = myControlCopy.BeginInvoke(funcToRun);
                        // funcToRun actually creates a Task that performs what is being run, so we need to get that task and then work with the task instead of the IAsyncResult
                        objResult.AsyncWaitHandle.WaitOne();
                        object objReturnRaw = myControlCopy.EndInvoke(objResult);
                        if (objReturnRaw is Task tskRunning)
                        {
                            if (blnSync)
                            {
                                if (tskRunning.Status == TaskStatus.Created)
                                {
                                    tskRunning.RunSynchronously();
                                }
                                while (!tskRunning.IsCompleted)
                                {
                                    Utils.SafeSleep();
                                }
                                if (tskRunning.Exception != null)
                                {
                                    throw tskRunning.Exception;
                                }
                            }
                            else
                            {
                                Task.Run(() => tskRunning.ContinueWith(x =>
                                {
                                    if (x.Exception != null)
                                    {
                                        throw x.Exception;
                                    }
                                }));
                            }
                        }

                        objResult.AsyncWaitHandle.Close();
                    }
                    else
                    {
                        Task tskRunning = funcToRun.Invoke();
                        if (tskRunning.Status == TaskStatus.Created)
                        {
                            tskRunning.RunSynchronously();
                        }
                        while (!tskRunning.IsCompleted)
                        {
                            Utils.SafeSleep();
                        }
                        if (tskRunning.Exception != null)
                        {
                            throw tskRunning.Exception;
                        }
                    }
                }
            }
            catch (ObjectDisposedException) // e)
            {
                //we really don't need to care about that.
                //Log.Trace(e);
            }
            catch (InvalidAsynchronousStateException e)
            {
                //we really don't need to care about that.
                Log.Trace(e);
            }
            catch (System.Threading.ThreadAbortException)
            {
                //no need to do anything here - actually we can't anyway...
            }
            catch (Exception e)
            {
                Log.Error(e);
#if DEBUG
                Program.MainForm?.ShowMessageBox(objControl, e.ToString());
#endif
            }
        }
Beispiel #4
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();
                }
            }
        }
Beispiel #5
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 DPI Stuff
                SetProcessDPI(GlobalOptions.DpiScalingMethodSetting);
                // 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...");
                    Utils.SafeSleep(TimeSpan.FromSeconds(2));
                }
            }
        }
Beispiel #6
0
        private async Task <bool> LoadFromFileCoreAsync(bool blnSync, string strFile)
        {
            while (IsLoadMethodRunning)
            {
                if (blnSync)
                {
                    Utils.SafeSleep();
                }
                else
                {
                    await Utils.SafeSleepAsync();
                }
            }

            IsLoadMethodRunning = true;
            try
            {
                DownLoadRunning = null;
                string         strErrorText = string.Empty;
                XPathNavigator xmlSourceNode;
                if (!File.Exists(strFile))
                {
                    xmlSourceNode = null;
                    strErrorText  = blnSync
                                    // ReSharper disable once MethodHasAsyncOverload
                        ? LanguageManager.GetString("MessageTitle_FileNotFound")
                        : await LanguageManager.GetStringAsync("MessageTitle_FileNotFound");
                }
                else
                {
                    // If we run into any problems loading the character cache, fail out early.
                    try
                    {
                        XPathDocument xmlDoc = blnSync ? LoadXPathDocument() : await Task.Run(LoadXPathDocument);

                        XPathDocument LoadXPathDocument()
                        {
                            using (StreamReader objStreamReader = new StreamReader(strFile, Encoding.UTF8, true))
                            {
                                using (XmlReader objXmlReader =
                                           XmlReader.Create(objStreamReader, GlobalSettings.SafeXmlReaderSettings))
                                {
                                    return(new XPathDocument(objXmlReader));
                                }
                            }
                        }

                        xmlSourceNode = xmlDoc.CreateNavigator().SelectSingleNodeAndCacheExpression("/character");
                    }
                    catch (Exception ex)
                    {
                        xmlSourceNode = null;
                        strErrorText  = ex.ToString();
                    }
                }

                if (xmlSourceNode != null)
                {
                    Description    = xmlSourceNode.SelectSingleNodeAndCacheExpression("description")?.Value;
                    BuildMethod    = xmlSourceNode.SelectSingleNodeAndCacheExpression("buildmethod")?.Value;
                    Background     = xmlSourceNode.SelectSingleNodeAndCacheExpression("background")?.Value;
                    CharacterNotes = xmlSourceNode.SelectSingleNodeAndCacheExpression("notes")?.Value;
                    GameNotes      = xmlSourceNode.SelectSingleNodeAndCacheExpression("gamenotes")?.Value;
                    Concept        = xmlSourceNode.SelectSingleNodeAndCacheExpression("concept")?.Value;
                    Karma          = xmlSourceNode.SelectSingleNodeAndCacheExpression("totalkarma")?.Value;
                    Metatype       = xmlSourceNode.SelectSingleNodeAndCacheExpression("metatype")?.Value;
                    Metavariant    = xmlSourceNode.SelectSingleNodeAndCacheExpression("metavariant")?.Value;
                    PlayerName     = xmlSourceNode.SelectSingleNodeAndCacheExpression("playername")?.Value;
                    CharacterName  = xmlSourceNode.SelectSingleNodeAndCacheExpression("name")?.Value;
                    CharacterAlias = xmlSourceNode.SelectSingleNodeAndCacheExpression("alias")?.Value;
                    Created        = xmlSourceNode.SelectSingleNodeAndCacheExpression("created")?.Value == bool.TrueString;
                    Essence        = xmlSourceNode.SelectSingleNodeAndCacheExpression("totaless")?.Value;
                    string strSettings = xmlSourceNode.SelectSingleNodeAndCacheExpression("settings")?.Value ?? string.Empty;
                    if (!string.IsNullOrEmpty(strSettings))
                    {
                        if (SettingsManager.LoadedCharacterSettings.TryGetValue(
                                strSettings, out CharacterSettings objSettings))
                        {
                            SettingsFile = objSettings.DisplayName;
                        }
                        else
                        {
                            string strTemp = blnSync
                                             // ReSharper disable once MethodHasAsyncOverload
                                ? LanguageManager.GetString("MessageTitle_FileNotFound") +
                                             // ReSharper disable once MethodHasAsyncOverload
                                             LanguageManager.GetString("String_Space")
                                : await LanguageManager.GetStringAsync("MessageTitle_FileNotFound") +
                                             await LanguageManager.GetStringAsync("String_Space");

                            SettingsFile = strTemp + '[' + strSettings + ']';
                        }
                    }
                    else
                    {
                        SettingsFile = string.Empty;
                    }
                    string strMugshotBase64 = xmlSourceNode.SelectSingleNodeAndCacheExpression("mugshot")?.Value ?? string.Empty;
                    if (string.IsNullOrEmpty(strMugshotBase64))
                    {
                        XPathNavigator xmlMainMugshotIndex = xmlSourceNode.SelectSingleNodeAndCacheExpression("mainmugshotindex");
                        if (xmlMainMugshotIndex != null &&
                            int.TryParse(xmlMainMugshotIndex.Value, out int intMainMugshotIndex) &&
                            intMainMugshotIndex >= 0)
                        {
                            XPathNodeIterator xmlMugshotList = xmlSourceNode.SelectAndCacheExpression("mugshots/mugshot");
                            if (xmlMugshotList.Count > intMainMugshotIndex)
                            {
                                int intIndex = 0;
                                foreach (XPathNavigator xmlMugshot in xmlMugshotList)
                                {
                                    if (intMainMugshotIndex == intIndex)
                                    {
                                        strMugshotBase64 = xmlMugshot.Value;
                                        break;
                                    }

                                    ++intIndex;
                                }
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(strMugshotBase64))
                    {
                        if (blnSync)
                        {
                            // ReSharper disable once MethodHasAsyncOverload
                            using (Image imgMugshot = strMugshotBase64.ToImage())
                                // ReSharper disable once MethodHasAsyncOverload
                                Mugshot = imgMugshot.GetCompressedImage();
                        }
                        else
                        {
                            using (Image imgMugshot = await strMugshotBase64.ToImageAsync())
                                Mugshot = await imgMugshot.GetCompressedImageAsync();
                        }
                    }
                }
                else
                {
                    ErrorText = strErrorText;
                }

                FilePath = strFile;
                if (!string.IsNullOrEmpty(strFile))
                {
                    int last = strFile.LastIndexOf(Path.DirectorySeparatorChar) + 1;
                    if (strFile.Length > last)
                    {
                        FileName = strFile.Substring(last);
                    }
                }

                return(string.IsNullOrEmpty(strErrorText));
            }
            finally
            {
                IsLoadMethodRunning = false;
            }
        }