//******************************************************************************// // App.xaml.cs // 12/4/2023 // // RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION // PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS // AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO // UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO // RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS // CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS // OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON // COMPANY. // // THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT // // UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. // // WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE // EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED // BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION // 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION // 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER // OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER // LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS // BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT // APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL // PENALTIES. // // DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : // FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, // INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS // DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR // RECONSTRUCTION OF THE DOCUMENT. // POC: Alex Kravchenko (1118268) //******************************************************************************// using Microsoft.Win32; using NLog; using Raytheon.LogDashboard.Helpers; using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows; using System.IO; using Raytheon.LogDashboard.View; using GalaSoft.MvvmLight.Messaging; using System.Reflection; namespace LogDashboard { /// /// Interaction logic for App.xaml /// public partial class App : Application { private static readonly Logger logger = LogManager.GetCurrentClassLogger(); public static bool IsManualStartup { get; private set; } = false; public ResourceDictionary ThemeDictionary => Resources.MergedDictionaries[1]; public void ChangeTheme(Uri uri) { ThemeDictionary.MergedDictionaries[1] = new ResourceDictionary { Source = uri }; } static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); [STAThread] protected override void OnStartup(StartupEventArgs e) { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; if(e.Args.Any(x => (x.EndsWith(".txt") || x.EndsWith(".log")) && File.Exists(x))) { IsManualStartup = true; try { if(!mutex.WaitOne(TimeSpan.Zero, true)) { Process proc = Process.GetCurrentProcess(); string processName = proc.ProcessName.Replace(".vshost", ""); var runningProcess = Process.GetProcesses() .FirstOrDefault(x => (x.ProcessName == processName || x.ProcessName == proc.ProcessName || x.ProcessName == proc.ProcessName + ".vshost") && x.Id != proc.Id); if(runningProcess == null) { App app = new App(); app.InitializeComponent(); MainWindow window = new MainWindow(); Raytheon.LogDashboard.View.MainWindow.HandleParameter(e.Args); app.Run(window); return; } UnsafeNative.SendMessage(runningProcess.MainWindowHandle, string.Join(" ", e.Args)); Environment.Exit(0); } } catch(Exception exception) { logger.Warn(exception, "OnStartup check exception (open with arguments)"); } } string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string logDashboardConfigFilePath = Path.Combine(assemblyFolder, "LogDashboard.xml"); // load settings from configuration file Raytheon.LogDashboard.Model.Settings.SetInstance(logDashboardConfigFilePath).Load(); if(Raytheon.LogDashboard.Model.Settings.Instance.OnlyOneAppInstance) { try { if(mutex.WaitOne(TimeSpan.Zero, true)) { mutex.ReleaseMutex(); } else { logger.Trace("OnStartup: one instance of Log Viewer already started"); Messenger.Default.Send("OnStartup: one instance of Log Viewer already started", "DisplayCustomMessage"); Environment.Exit(0); } } catch(Exception exception) { logger.Warn(exception, "OnStartup check exception"); } } try { if(!IsAssociated()) { string filePath = Process.GetCurrentProcess().MainModule.FileName; SetAssociation(".txt", "LogDashboard", filePath); SetAssociation(".log", "LogDashboard", filePath); SetAssociation(".csv", "LogDashboard", filePath); } } catch(Exception exception) { logger.Warn(exception, "OnStartup set file association exception"); } base.OnStartup(e); } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { logger.Fatal($"Unhandled exception {e.ExceptionObject as Exception}"); Environment.Exit(1); } private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { logger.Fatal($"Unhandled Exception: {e.Exception}"); Environment.Exit(2); } #region File Association private bool IsAssociated() { return Registry.CurrentUser.OpenSubKey(@"Software\Classes\LogViewer", false) != null; } [DllImport("Shell32.dll")] private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); private const int SHCNE_ASSOCCHANGED = 0x8000000; private const int SHCNF_FLUSH = 0x1000; private void SetAssociation(string extension, string progId, string applicationFilePath) { bool madeChanges = false; madeChanges |= SetKeyDefaultValue($@"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\""); madeChanges |= SetProgIdValue($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{extension}\OpenWithProgids", progId); if(madeChanges) { SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero); } } private bool SetProgIdValue(string path, string progId) { using(var key = Registry.CurrentUser.CreateSubKey(path)) { if(key.GetValueNames().All(x => x != progId)) { key.SetValue(progId, Encoding.Unicode.GetBytes(string.Empty), RegistryValueKind.Binary); return true; } } return false; } private bool SetKeyDefaultValue(string keyPath, string value) { using(var key = Registry.CurrentUser.CreateSubKey(keyPath)) { if(key.GetValue(null) as string != value) { key.SetValue(null, value); return true; } } return false; } #endregion } }