Files
QSafe/windows/QSafe.Desktop/App.xaml.cs
T

69 lines
3.5 KiB
C#

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