Skip to content

Commit 1a54eed

Browse files
authored
Merge pull request #3250 from Jack251970/sys_shutdown_restart_hibernate
Improve Shutdown & Restart & Hibernate in Sys Plugin
2 parents f0cb036 + 3bd4ca4 commit 1a54eed

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

Plugins/Flow.Launcher.Plugin.Sys/Main.cs

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Runtime.InteropServices;
56
using System.Windows;
67
using Flow.Launcher.Infrastructure;
78
using Flow.Launcher.Infrastructure.Logger;
89
using Flow.Launcher.Infrastructure.UserSettings;
910
using Flow.Launcher.Plugin.SharedCommands;
1011
using Windows.Win32;
1112
using Windows.Win32.Foundation;
13+
using Windows.Win32.Security;
1214
using Windows.Win32.System.Shutdown;
1315
using Application = System.Windows.Application;
1416
using Control = System.Windows.Controls.Control;
@@ -20,6 +22,10 @@ public class Main : IPlugin, ISettingProvider, IPluginI18n
2022
private PluginInitContext context;
2123
private Dictionary<string, string> KeywordTitleMappings = new Dictionary<string, string>();
2224

25+
// SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure, software updates, or other predefined reasons.
26+
// SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure
27+
private const SHUTDOWN_REASON REASON = SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED;
28+
2329
public Control CreateSettingPanel()
2430
{
2531
var results = Commands();
@@ -100,6 +106,44 @@ public void Init(PluginInitContext context)
100106
};
101107
}
102108

109+
private static unsafe bool EnableShutdownPrivilege()
110+
{
111+
try
112+
{
113+
if (!PInvoke.OpenProcessToken(Process.GetCurrentProcess().SafeHandle, TOKEN_ACCESS_MASK.TOKEN_ADJUST_PRIVILEGES | TOKEN_ACCESS_MASK.TOKEN_QUERY, out var tokenHandle))
114+
{
115+
return false;
116+
}
117+
118+
if (!PInvoke.LookupPrivilegeValue(null, PInvoke.SE_SHUTDOWN_NAME, out var luid))
119+
{
120+
return false;
121+
}
122+
123+
var privileges = new TOKEN_PRIVILEGES
124+
{
125+
PrivilegeCount = 1,
126+
Privileges = new() { e0 = new LUID_AND_ATTRIBUTES { Luid = luid, Attributes = TOKEN_PRIVILEGES_ATTRIBUTES.SE_PRIVILEGE_ENABLED } }
127+
};
128+
129+
if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, &privileges, 0, null, null))
130+
{
131+
return false;
132+
}
133+
134+
if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.NO_ERROR)
135+
{
136+
return false;
137+
}
138+
139+
return true;
140+
}
141+
catch (Exception)
142+
{
143+
return false;
144+
}
145+
}
146+
103147
private List<Result> Commands()
104148
{
105149
var results = new List<Result>();
@@ -120,10 +164,12 @@ private List<Result> Commands()
120164
context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_shutdown_computer"),
121165
context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"),
122166
MessageBoxButton.YesNo, MessageBoxImage.Warning);
167+
123168
if (result == MessageBoxResult.Yes)
124-
{
125-
Process.Start("shutdown", "/s /t 0");
126-
}
169+
if (EnableShutdownPrivilege())
170+
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, REASON);
171+
else
172+
Process.Start("shutdown", "/s /t 0");
127173

128174
return true;
129175
}
@@ -140,10 +186,12 @@ private List<Result> Commands()
140186
context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer"),
141187
context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"),
142188
MessageBoxButton.YesNo, MessageBoxImage.Warning);
189+
143190
if (result == MessageBoxResult.Yes)
144-
{
145-
Process.Start("shutdown", "/r /t 0");
146-
}
191+
if (EnableShutdownPrivilege())
192+
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON);
193+
else
194+
Process.Start("shutdown", "/r /t 0");
147195

148196
return true;
149197
}
@@ -162,7 +210,10 @@ private List<Result> Commands()
162210
MessageBoxButton.YesNo, MessageBoxImage.Warning);
163211

164212
if (result == MessageBoxResult.Yes)
165-
Process.Start("shutdown", "/r /o /t 0");
213+
if (EnableShutdownPrivilege())
214+
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, REASON);
215+
else
216+
Process.Start("shutdown", "/r /o /t 0");
166217

167218
return true;
168219
}
@@ -181,7 +232,7 @@ private List<Result> Commands()
181232
MessageBoxButton.YesNo, MessageBoxImage.Warning);
182233

183234
if (result == MessageBoxResult.Yes)
184-
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, 0);
235+
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON);
185236

186237
return true;
187238
}
@@ -204,7 +255,11 @@ private List<Result> Commands()
204255
SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_sleep"),
205256
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xec46"),
206257
IcoPath = "Images\\sleep.png",
207-
Action = c => PInvoke.SetSuspendState(false, false, false)
258+
Action = c =>
259+
{
260+
PInvoke.SetSuspendState(false, false, false);
261+
return true;
262+
}
208263
},
209264
new Result
210265
{
@@ -214,12 +269,7 @@ private List<Result> Commands()
214269
IcoPath = "Images\\hibernate.png",
215270
Action= c =>
216271
{
217-
var info = ShellCommand.SetProcessStartInfo("shutdown", arguments:"/h");
218-
info.WindowStyle = ProcessWindowStyle.Hidden;
219-
info.UseShellExecute = true;
220-
221-
ShellCommand.Execute(info);
222-
272+
PInvoke.SetSuspendState(true, false, false);
223273
return true;
224274
}
225275
},
@@ -231,10 +281,7 @@ private List<Result> Commands()
231281
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xe773"),
232282
Action = c =>
233283
{
234-
{
235-
System.Diagnostics.Process.Start("control.exe", "srchadmin.dll");
236-
}
237-
284+
Process.Start("control.exe", "srchadmin.dll");
238285
return true;
239286
}
240287
},
@@ -272,10 +319,7 @@ private List<Result> Commands()
272319
CopyText = recycleBinFolder,
273320
Action = c =>
274321
{
275-
{
276-
System.Diagnostics.Process.Start("explorer", recycleBinFolder);
277-
}
278-
322+
Process.Start("explorer", recycleBinFolder);
279323
return true;
280324
}
281325
},

Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,10 @@ LockWorkStation
33
SHEmptyRecycleBin
44
S_OK
55
E_UNEXPECTED
6-
SetSuspendState
6+
SetSuspendState
7+
OpenProcessToken
8+
WIN32_ERROR
9+
LookupPrivilegeValue
10+
AdjustTokenPrivileges
11+
TOKEN_PRIVILEGES
12+
SE_SHUTDOWN_NAME

0 commit comments

Comments
 (0)