Files
covenant-setup/ui/Covenant.Setup.Ui/Program.cs
T
2026-06-11 12:18:42 -05:00

134 lines
3.9 KiB
C#

using System.Runtime.InteropServices;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
namespace Covenant.Setup.Ui;
internal static class Program
{
[STAThread]
private static void Main(string[] args)
{
WinRT.ComWrappersSupport.InitializeComWrappers();
var mockScenarioName = ReadMockScenario(args);
Mocking.Scenario? mockScenario = null;
if (mockScenarioName is not null)
{
try
{
mockScenario = Mocking.Scenario.LoadFile(mockScenarioName);
}
catch (Exception ex)
{
UiTrace.Write("mock_scenario_load_error", new { ex.Message });
NativeDialog.Show(IntPtr.Zero, $"Failed to load mock scenario: {ex.Message}", "covenant-setup", NativeDialogIcon.Error);
return;
}
}
var pipeName = ReadPipeName(args);
if (string.IsNullOrWhiteSpace(pipeName))
{
if (mockScenario is not null)
{
pipeName = $"covenant-setup-mock-{Environment.ProcessId}-{Guid.NewGuid():N}";
}
else
{
UiTrace.Write("missing_pipe_argument");
NativeDialog.Show(IntPtr.Zero, "Missing named pipe argument.", "covenant-setup", NativeDialogIcon.Error);
return;
}
}
UiTrace.Write("process_start", new { ProcessId = Environment.ProcessId, PipeName = pipeName });
Application.Start(_params =>
{
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
if (dispatcherQueue is not null)
{
SynchronizationContext.SetSynchronizationContext(
new DispatcherQueueSynchronizationContext(dispatcherQueue));
}
_ = new InstallerUiApp(pipeName, mockScenario);
});
}
internal static string? ReadPipeName(string[] args)
{
var value = ReadArgValue(args, "--pipe");
const string pipePrefix = @"\\.\pipe\";
if (value is not null && value.StartsWith(pipePrefix, StringComparison.OrdinalIgnoreCase))
{
value = value[pipePrefix.Length..];
}
return value;
}
internal static string? ReadMockScenario(string[] args)
{
return ReadArgValue(args, "--mock");
}
private static string? ReadArgValue(string[] args, string flag)
{
for (var i = 0; i < args.Length - 1; i++)
{
if (string.Equals(args[i], flag, StringComparison.OrdinalIgnoreCase))
{
return args[i + 1];
}
}
return null;
}
}
public sealed partial class InstallerUiApp : Application
{
private readonly string _pipeName;
private readonly Mocking.Scenario? _mockScenario;
private Window? _window;
internal InstallerUiApp(string pipeName, Mocking.Scenario? mockScenario)
{
_pipeName = pipeName;
_mockScenario = mockScenario;
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var window = new InstallerUiWindow(_pipeName);
_window = window;
window.Activate();
window.StartPipeLoop();
if (_mockScenario is not null)
{
_ = Task.Run(() => new Mocking.MockEngineClient(_pipeName, _mockScenario, new Mocking.MockEngineOptions { StrictExpectations = false }).RunAsync());
}
}
}
internal enum NativeDialogIcon : uint
{
Error = 0x00000010,
Information = 0x00000040
}
internal static class NativeDialog
{
public static void Show(IntPtr owner, string message, string title, NativeDialogIcon icon)
{
_ = MessageBoxW(owner, message, title, (uint)icon);
}
[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type);
}