From 05d17bded458146135410c2816934cf4f1813a63 Mon Sep 17 00:00:00 2001 From: purr Date: Fri, 1 May 2026 15:30:43 +0200 Subject: [PATCH] Implement window close behavior using WM_SYSCOMMAND/SC_CLOSE to support applications that intercept close commands. This change ensures compatibility with minimize-to-tray and custom close behaviors. --- src/WinMan.Windows/Windows/Win32Window.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/WinMan.Windows/Windows/Win32Window.cs b/src/WinMan.Windows/Windows/Win32Window.cs index 05d7532..75348d3 100644 --- a/src/WinMan.Windows/Windows/Win32Window.cs +++ b/src/WinMan.Windows/Windows/Win32Window.cs @@ -189,13 +189,19 @@ internal Win32Window(Win32Workspace workspace, IntPtr hwnd) m_title = m_workspace.RunInBackgroundAsync(GetTitleWithFallback); } + private const uint WM_SYSCOMMAND = 0x0112; + private const nuint SC_CLOSE = 0xF060; + public void Close() { unsafe { var flags = SendMessageTimeout_fuFlags.SMTO_NORMAL | SendMessageTimeout_fuFlags.SMTO_ABORTIFHUNG; nuint result = 0; - if (new LRESULT() == SendMessageTimeout(new(m_hwnd), Constants.WM_CLOSE, new(), new(), flags, 3000, &result)) + // Mimic the title-bar X button by posting WM_SYSCOMMAND/SC_CLOSE. + // Apps such as ShareX and Excel intercept SC_CLOSE for minimize-to-tray + // or per-window close behavior; sending raw WM_CLOSE bypasses that. + if (new LRESULT() == SendMessageTimeout(new(m_hwnd), WM_SYSCOMMAND, new(SC_CLOSE), new(), flags, 3000, &result)) { int err = Marshal.GetLastWin32Error(); err = err == 0 ? (int)Constants.ERROR_TIMEOUT : err;