using System.IO; using System.Security.Cryptography; using System.Text; using System.Windows; using System.Runtime.InteropServices; using System.Windows.Interop; using QSafe.Core; namespace QSafe.Desktop; public partial class App : Application { private Mutex? single; private bool ownsMutex; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); bool smoke = e.Args.Contains("--smoke-test"); bool demo = smoke || e.Args.Contains("--demo"); var path = demo ? Path.Combine(Path.GetTempPath(), "QSafe-Demo", Guid.NewGuid().ToString("N")) : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Kusoft", "QSafe"); single = new Mutex(false, "Local\\QSafe-" + Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(path)))[..20]); try { ownsMutex = single.WaitOne(0); } catch (AbandonedMutexException) { ownsMutex = true; } if (!ownsMutex) { MessageBox.Show("QSafe уже запущен. Откройте существующее окно.", "QSafe"); Shutdown(); return; } try { var store = new LocalStore(path); int connectionIndex = Array.IndexOf(e.Args, "--connection"); if (!demo && connectionIndex >= 0) { if (connectionIndex + 1 >= e.Args.Length) throw new InvalidDataException("Укажите личный файл локального подключения."); store.Configure(Connection.Parse(LocalStore.ReadBounded(e.Args[connectionIndex + 1], 65536))); } if (!demo && e.Args.Contains("--configure-only")) { Shutdown(); return; } MainWindow = new MainWindow(store, demo); MainWindow.Show(); if (smoke) { var timer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; timer.Tick += (_, _) => { timer.Stop(); MainWindow.Close(); }; timer.Start(); } } catch { MessageBox.Show("Не удалось открыть локальное хранилище или защищённые настройки. Данные не изменены. Проверьте доступ к папке %LOCALAPPDATA%\\Kusoft\\QSafe.", "QSafe", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(1); } } protected override void OnExit(ExitEventArgs e) { if (ownsMutex) single?.ReleaseMutex(); single?.Dispose(); base.OnExit(e); } } public static class NativeWindow { [DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attribute, ref int value, int size); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetWindowDisplayAffinity(IntPtr hwnd, uint affinity); public static void Style(Window window) { window.SourceInitialized += (_, _) => { var handle = new WindowInteropHelper(window).Handle; int dark = 1; DwmSetWindowAttribute(handle, 20, ref dark, sizeof(int)); // Demo contains only synthetic credentials and can be captured for interface review. SetProtection(window, !(Application.Current.MainWindow is MainWindow main && main.IsDemo)); }; } public static void SetProtection(Window window, bool enabled) { var handle = new WindowInteropHelper(window).Handle; if (handle != IntPtr.Zero) SetWindowDisplayAffinity(handle, enabled ? 0x11u : 0u); } }