From 3c321b532a8836fe1b65ce72d03d3b8bd6299649 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 20 Aug 2026 18:58:42 +0000 Subject: [PATCH 1/3] fix: disambiguate EventLogRecord and P/Invoke window subclass. CsWin32 0.3 does not emit SUBCLASSPROC; call comctl32 SetWindowSubclass directly. Alias the Core EventLogRecord so the EventLog package type does not break IEventLogReader. Co-authored-by: Paul Smith --- src/Reentry.App/NativeMethods.txt | 3 -- src/Reentry.App/Services/EndSessionHook.cs | 52 +++++++++++++++---- .../Services/Win32EventLogReader.cs | 1 + 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/Reentry.App/NativeMethods.txt b/src/Reentry.App/NativeMethods.txt index ccb2e9f..ca6951a 100644 --- a/src/Reentry.App/NativeMethods.txt +++ b/src/Reentry.App/NativeMethods.txt @@ -14,8 +14,5 @@ QueryFullProcessImageNameW OpenProcess CloseHandle GetCurrentProcessId -SetWindowSubclass -RemoveWindowSubclass -DefSubclassProc ShowWindow UpdateWindow diff --git a/src/Reentry.App/Services/EndSessionHook.cs b/src/Reentry.App/Services/EndSessionHook.cs index 3b00066..cbb3b06 100644 --- a/src/Reentry.App/Services/EndSessionHook.cs +++ b/src/Reentry.App/Services/EndSessionHook.cs @@ -1,8 +1,5 @@ +using System.Runtime.InteropServices; using Microsoft.UI.Xaml; -using Windows.Win32; -using Windows.Win32.Foundation; -using Windows.Win32.UI.Controls; -using Windows.Win32.UI.WindowsAndMessaging; namespace Reentry.App.Services; @@ -14,11 +11,22 @@ public sealed class EndSessionHook : IDisposable { private const uint WmQueryEndSession = 0x0011; private const uint WmEndSession = 0x0016; + private const nuint SubclassId = 1; + private readonly Action _onEndSession; - private HWND _hwnd; - private SUBCLASSPROC? _proc; + private nint _hwnd; + private SubclassProc? _proc; private bool _attached; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate nint SubclassProc( + nint hwnd, + uint msg, + nuint wParam, + nint lParam, + nuint idSubclass, + nuint refData); + public EndSessionHook(Action onEndSession) { _onEndSession = onEndSession; @@ -38,12 +46,12 @@ public void Attach(Window window) public void Attach(nint hwnd) { Detach(); - _hwnd = new HWND(hwnd); + _hwnd = hwnd; _proc = WndProc; - _attached = PInvoke.SetWindowSubclass(_hwnd, _proc, 1, 0); + _attached = SetWindowSubclass(_hwnd, _proc, SubclassId, 0); } - private LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam, nuint id, nuint data) + private nint WndProc(nint hwnd, uint msg, nuint wParam, nint lParam, nuint id, nuint data) { if (msg is WmQueryEndSession or WmEndSession) { @@ -51,17 +59,39 @@ private LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam, nuint catch { /* never block shutdown */ } } - return PInvoke.DefSubclassProc(hwnd, msg, wParam, lParam); + return DefSubclassProc(hwnd, msg, wParam, lParam); } private void Detach() { if (_attached && _proc is not null) { - PInvoke.RemoveWindowSubclass(_hwnd, _proc, 1); + RemoveWindowSubclass(_hwnd, _proc, SubclassId); _attached = false; } } public void Dispose() => Detach(); + + [DllImport("comctl32.dll", ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetWindowSubclass( + nint hWnd, + SubclassProc pfnSubclass, + nuint uIdSubclass, + nuint dwRefData); + + [DllImport("comctl32.dll", ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RemoveWindowSubclass( + nint hWnd, + SubclassProc pfnSubclass, + nuint uIdSubclass); + + [DllImport("comctl32.dll", ExactSpelling = true)] + private static extern nint DefSubclassProc( + nint hWnd, + uint uMsg, + nuint wParam, + nint lParam); } diff --git a/src/Reentry.App/Services/Win32EventLogReader.cs b/src/Reentry.App/Services/Win32EventLogReader.cs index af8ea6a..5f772af 100644 --- a/src/Reentry.App/Services/Win32EventLogReader.cs +++ b/src/Reentry.App/Services/Win32EventLogReader.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Eventing.Reader; using Reentry.Core.Abstractions; using Reentry.Core.Models; +using EventLogRecord = Reentry.Core.Models.EventLogRecord; namespace Reentry.App.Services; From 0591ccc3616b6cf8239cd99fb10a6fc25ac911d8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 20 Aug 2026 19:03:16 +0000 Subject: [PATCH 2/3] fix: Win32ProcessProbe LiveProcess names and HWND types. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named record args are PascalCase. Do not assign EnumWindows LPARAM to GetWindowThreadProcessId's DWORD. HWND.Value is void* — cast to long. Co-authored-by: Paul Smith --- src/Reentry.App/Services/Win32ProcessProbe.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Reentry.App/Services/Win32ProcessProbe.cs b/src/Reentry.App/Services/Win32ProcessProbe.cs index a37279b..16873dc 100644 --- a/src/Reentry.App/Services/Win32ProcessProbe.cs +++ b/src/Reentry.App/Services/Win32ProcessProbe.cs @@ -20,7 +20,7 @@ public IReadOnlyList GetProcesses() try { started = process.StartTime.ToUniversalTime(); } catch { started = DateTimeOffset.UtcNow; } - list.Add(new LiveProcess(process.Id, exe, commandLine: null, started)); + list.Add(new LiveProcess(process.Id, exe, CommandLine: null, StartedUtc: started)); } catch { @@ -44,10 +44,10 @@ public IReadOnlyList GetVisibleWindows() return true; uint pid = 0; - _ = PInvoke.GetWindowThreadProcessId(hwnd, &pid); + PInvoke.GetWindowThreadProcessId(hwnd, &pid); var title = ReadTitle(hwnd); var exe = QueryImage((int)pid) ?? ""; - list.Add(new LiveWindow(hwnd.Value, (int)pid, title, exe, IsVisible: true)); + list.Add(new LiveWindow((long)hwnd.Value, (int)pid, title, exe, IsVisible: true)); return true; }, 0); return list; From 868a35a43a57fd352e74203dca9a8c1fbb65ece8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 20 Aug 2026 19:07:12 +0000 Subject: [PATCH 3/3] fix: default unpackaged WASDK build to win-x64. WindowsAppSDKSelfContained rejects AnyCPU, which is what `dotnet build Reentry.slnx -c Release` uses. Keep explicit -r / Platform. Co-authored-by: Paul Smith --- src/Reentry.App/Reentry.App.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Reentry.App/Reentry.App.csproj b/src/Reentry.App/Reentry.App.csproj index cfa18a5..a06691f 100644 --- a/src/Reentry.App/Reentry.App.csproj +++ b/src/Reentry.App/Reentry.App.csproj @@ -20,6 +20,9 @@ Assets\reentry.ico x86;x64;ARM64 win-x86;win-x64;win-arm64 + + win-x64 true