Skip to content

Commit d166fea

Browse files
authored
[Feature] Prevent Windows Log off/Restart/Shutdown when running critical task (#758)
# Main Goal Preventing Windows from ending it's ~~life~~ session when Collapse is running critical task. Should prevent accidental shutting down when Collapse is installing/updating/repairing games. ![image](https://github.com/user-attachments/assets/97f8d356-e6a3-43ed-a0d3-9c1f2ed9675e) Thanks @neon-nyan for the screenshot. P.S. This doesn't work when you run Collapse inside a debugger, because the debugger will kill its target process when Windows is ending the session. ## PR Status : - Overall Status : Done - Commits : Done - Synced to base (Collapse:main) : Yes - Build status : OK - Crashing : No - Bug found caused by PR : 0 ### Templates <details> <summary>Changelog Prefixes</summary> ``` **[New]** **[Imp]** **[Fix]** **[Loc]** **[Doc]** ``` </details>
2 parents 5023ed1 + e45eede commit d166fea

File tree

7 files changed

+63
-31
lines changed

7 files changed

+63
-31
lines changed

CollapseLauncher/Classes/Helper/WindowUtility.cs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -451,12 +451,14 @@ private static IntPtr InstallWndProcCallback(IntPtr hwnd, WndProcDelegate wndPro
451451

452452
private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam)
453453
{
454-
const uint WM_SYSCOMMAND = 0x0112;
455-
const uint WM_SHOWWINDOW = 0x0018;
456-
const uint WM_NCHITTEST = 0x0084;
457-
const uint WM_NCCALCSIZE = 0x0083;
458-
const uint WM_SETTINGCHANGE = 0x001A;
459-
const uint WM_ACTIVATE = 0x0006;
454+
const uint WM_SYSCOMMAND = 0x0112;
455+
const uint WM_SHOWWINDOW = 0x0018;
456+
const uint WM_NCHITTEST = 0x0084;
457+
const uint WM_NCCALCSIZE = 0x0083;
458+
const uint WM_SETTINGCHANGE = 0x001A;
459+
const uint WM_ACTIVATE = 0x0006;
460+
const uint WM_QUERYENDSESSION = 0x0011;
461+
const uint WM_ENDSESSION = 0x0016;
460462

461463
switch (msg)
462464
{
@@ -592,6 +594,29 @@ private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr
592594

593595
break;
594596
}
597+
case WM_QUERYENDSESSION:
598+
// Return FALSE (0) to prevent shutdown if critical operation is in progress
599+
if (MainWindow.IsCriticalOpInProgress)
600+
{
601+
return 0;
602+
}
603+
// Let Windows continue shutdown if no critical operation
604+
break;
605+
606+
case WM_ENDSESSION:
607+
// wParam is TRUE if session is ending
608+
if (wParam != UIntPtr.Zero)
609+
{
610+
if (MainWindow.IsCriticalOpInProgress)
611+
{
612+
// Still try to block it at this stage
613+
return 0;
614+
}
615+
616+
// No critical operation, calling app close method
617+
(CurrentWindow as MainWindow)?.CloseApp();
618+
}
619+
break;
595620
}
596621

597622
return PInvoke.CallWindowProc(_oldMainWndProcPtr, hwnd, msg, wParam, lParam);

CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Hi3Helper;
1212
using Hi3Helper.SentryHelper;
1313
using Hi3Helper.Shared.Region;
14+
using Hi3Helper.Win32.ManagedTools;
1415
using Hi3Helper.Win32.Native.LibraryImport;
1516
using Microsoft.UI.Composition;
1617
using Microsoft.UI.Input;
@@ -19,6 +20,7 @@
1920
using Microsoft.UI.Xaml.Controls;
2021
using Microsoft.UI.Xaml.Media.Animation;
2122
using System;
23+
using System.Threading;
2224
using System.Threading.Tasks;
2325
using Windows.UI;
2426
using static CollapseLauncher.Dialogs.SimpleDialogs;
@@ -34,8 +36,31 @@ namespace CollapseLauncher
3436
public sealed partial class MainWindow : Window
3537
{
3638
private static bool _isForceDisableIntro;
37-
38-
public static bool IsCriticalOpInProgress { get; set; }
39+
40+
private static readonly Lock CriticalOpLock = new Lock();
41+
public static bool IsCriticalOpInProgress
42+
{
43+
get;
44+
set
45+
{
46+
lock (CriticalOpLock)
47+
{
48+
var lastValue = field;
49+
field = value;
50+
51+
if (value)
52+
{
53+
ShutdownBlocker.StartBlocking(WindowUtility.CurrentWindowPtr, Locale.Lang._Dialogs.EnsureExitSubtitle,
54+
ILoggerHelper.GetILogger("ShutdownBlocker"));
55+
}
56+
else if (lastValue)
57+
{
58+
ShutdownBlocker.StopBlocking(WindowUtility.CurrentWindowPtr,
59+
ILoggerHelper.GetILogger("ShutdownBlocker"));
60+
}
61+
}
62+
}
63+
}
3964

4065
public void InitializeWindowProperties(bool startOobe = false)
4166
{

CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ public static Task<ContentDialogResult> Dialog_UninstallGame(string gameLocation
994994
public static Task<ContentDialogResult> Dialog_EnsureExit()
995995
{
996996
return SpawnDialog(Lang._Dialogs.EnsureExitTitle,
997-
Lang._Dialogs.EnsureExitSubtitle,
997+
$"{Lang._Dialogs.EnsureExitSubtitle} {Lang._Dialogs.EnsureExitSubtitle2}",
998998
null,
999999
Lang._Misc.NoCancel,
10001000
Lang._Misc.Yes,

CollapseLauncher/packages.lock.json

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,6 @@
105105
"resolved": "0.41.2",
106106
"contentHash": "oso8cno80OzCgAQOygtJXT1UhlVr2eSjwzXLqSLHyfKmSJ+3OcwDbrpzNwMj3/1SgncvQxP7OsNQ3bRfE3HvjQ=="
107107
},
108-
"Microsoft.DotNet.ILCompiler": {
109-
"type": "Direct",
110-
"requested": "[9.0.5, )",
111-
"resolved": "9.0.5",
112-
"contentHash": "rfDodV68TLSUgVM6ZQusuUXD7GAIqwCKJWlPtfsd99iLlLbeGfqUQE7Xo8xLa1ju5GCdSBO0q35suzZ8ppclpA=="
113-
},
114108
"Microsoft.Extensions.DependencyInjection.Abstractions": {
115109
"type": "Direct",
116110
"requested": "[9.0.5, )",
@@ -630,15 +624,6 @@
630624
"resolved": "0.5.0",
631625
"contentHash": "5Tw6O9sBDAN1aV+kpOSVvqvFk6Ahk6bYz0TTx3808Dp40M45gKTtzTzI9SS1VeAkljE6BAOeKaykpPnG36oOgw=="
632626
},
633-
"Microsoft.DotNet.ILCompiler": {
634-
"type": "Direct",
635-
"requested": "[9.0.5, )",
636-
"resolved": "9.0.5",
637-
"contentHash": "rfDodV68TLSUgVM6ZQusuUXD7GAIqwCKJWlPtfsd99iLlLbeGfqUQE7Xo8xLa1ju5GCdSBO0q35suzZ8ppclpA==",
638-
"dependencies": {
639-
"runtime.win-x64.Microsoft.DotNet.ILCompiler": "9.0.5"
640-
}
641-
},
642627
"Microsoft.Graphics.Win2D": {
643628
"type": "Direct",
644629
"requested": "[1.3.2, )",
@@ -688,11 +673,6 @@
688673
"Microsoft.WindowsAppSDK.Base": "1.8.250501001-experimental",
689674
"Microsoft.WindowsAppSDK.InteractiveExperiences": "1.8.250506001-experimental"
690675
}
691-
},
692-
"runtime.win-x64.Microsoft.DotNet.ILCompiler": {
693-
"type": "Transitive",
694-
"resolved": "9.0.5",
695-
"contentHash": "/x+iKUhSOhYrbaEr9x78wZmBk7Le8FlY9Xwx7uENRFCZ7K5sGrTffkJiig22EzYuALh8SeixjSzVFS0nm5+NgQ=="
696676
}
697677
}
698678
}

Hi3Helper.Core/Lang/Locale/LangDialogs.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ public sealed partial class LangDialogs
212212
public string UACWarningDontShowAgain { get; set; } = LangFallback?._Dialogs.UACWarningDontShowAgain;
213213
public string EnsureExitTitle { get; set; } = LangFallback?._Dialogs.EnsureExitTitle;
214214
public string EnsureExitSubtitle { get; set; } = LangFallback?._Dialogs.EnsureExitSubtitle;
215+
public string EnsureExitSubtitle2 { get; set; } = LangFallback?._Dialogs.EnsureExitSubtitle2;
215216

216217
public string UserFeedback_DialogTitle { get; set; } = LangFallback?._Dialogs.UserFeedback_DialogTitle;
217218
public string UserFeedback_TextFieldTitleHeader { get; set; } = LangFallback?._Dialogs.UserFeedback_TextFieldTitleHeader;

Hi3Helper.Core/Lang/en_US.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,8 @@
10801080
"UACWarningDontShowAgain": "Don't Show Again",
10811081

10821082
"EnsureExitTitle": "Exiting Application",
1083-
"EnsureExitSubtitle": "There are critical operations running in the background. Are you sure you want to exit?",
1083+
"EnsureExitSubtitle": "There are critical operations running in the background.",
1084+
"EnsureExitSubtitle2": "Are you sure you want to exit?",
10841085

10851086
"UserFeedback_DialogTitle": "Share Your Thoughts",
10861087
"UserFeedback_TextFieldTitleHeader": "Feedback Title",

0 commit comments

Comments
 (0)