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 } }
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(); } } }
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)); } } }
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; } }