2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics ;
4
4
using System . IO ;
5
+ using System . Runtime . InteropServices ;
5
6
using System . Windows ;
6
7
using Flow . Launcher . Infrastructure ;
7
8
using Flow . Launcher . Infrastructure . Logger ;
8
9
using Flow . Launcher . Infrastructure . UserSettings ;
9
10
using Flow . Launcher . Plugin . SharedCommands ;
10
11
using Windows . Win32 ;
11
12
using Windows . Win32 . Foundation ;
13
+ using Windows . Win32 . Security ;
12
14
using Windows . Win32 . System . Shutdown ;
13
15
using Application = System . Windows . Application ;
14
16
using Control = System . Windows . Controls . Control ;
@@ -20,6 +22,10 @@ public class Main : IPlugin, ISettingProvider, IPluginI18n
20
22
private PluginInitContext context ;
21
23
private Dictionary < string , string > KeywordTitleMappings = new Dictionary < string , string > ( ) ;
22
24
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
+
23
29
public Control CreateSettingPanel ( )
24
30
{
25
31
var results = Commands ( ) ;
@@ -100,6 +106,44 @@ public void Init(PluginInitContext context)
100
106
} ;
101
107
}
102
108
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
+
103
147
private List < Result > Commands ( )
104
148
{
105
149
var results = new List < Result > ( ) ;
@@ -120,10 +164,12 @@ private List<Result> Commands()
120
164
context . API . GetTranslation ( "flowlauncher_plugin_sys_dlgtext_shutdown_computer" ) ,
121
165
context . API . GetTranslation ( "flowlauncher_plugin_sys_shutdown_computer" ) ,
122
166
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
167
+
123
168
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" ) ;
127
173
128
174
return true ;
129
175
}
@@ -140,10 +186,12 @@ private List<Result> Commands()
140
186
context . API . GetTranslation ( "flowlauncher_plugin_sys_dlgtext_restart_computer" ) ,
141
187
context . API . GetTranslation ( "flowlauncher_plugin_sys_restart_computer" ) ,
142
188
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
189
+
143
190
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" ) ;
147
195
148
196
return true ;
149
197
}
@@ -162,7 +210,10 @@ private List<Result> Commands()
162
210
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
163
211
164
212
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" ) ;
166
217
167
218
return true ;
168
219
}
@@ -181,7 +232,7 @@ private List<Result> Commands()
181
232
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
182
233
183
234
if ( result == MessageBoxResult . Yes )
184
- PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_LOGOFF , 0 ) ;
235
+ PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_LOGOFF , REASON ) ;
185
236
186
237
return true ;
187
238
}
@@ -204,7 +255,11 @@ private List<Result> Commands()
204
255
SubTitle = context . API . GetTranslation ( "flowlauncher_plugin_sys_sleep" ) ,
205
256
Glyph = new GlyphInfo ( FontFamily : "/Resources/#Segoe Fluent Icons" , Glyph : "\xec46 " ) ,
206
257
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
+ }
208
263
} ,
209
264
new Result
210
265
{
@@ -214,12 +269,7 @@ private List<Result> Commands()
214
269
IcoPath = "Images\\ hibernate.png" ,
215
270
Action = c =>
216
271
{
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 ) ;
223
273
return true ;
224
274
}
225
275
} ,
@@ -231,10 +281,7 @@ private List<Result> Commands()
231
281
Glyph = new GlyphInfo ( FontFamily : "/Resources/#Segoe Fluent Icons" , Glyph : "\xe773 " ) ,
232
282
Action = c =>
233
283
{
234
- {
235
- System . Diagnostics . Process . Start ( "control.exe" , "srchadmin.dll" ) ;
236
- }
237
-
284
+ Process . Start ( "control.exe" , "srchadmin.dll" ) ;
238
285
return true ;
239
286
}
240
287
} ,
@@ -272,10 +319,7 @@ private List<Result> Commands()
272
319
CopyText = recycleBinFolder ,
273
320
Action = c =>
274
321
{
275
- {
276
- System . Diagnostics . Process . Start ( "explorer" , recycleBinFolder ) ;
277
- }
278
-
322
+ Process . Start ( "explorer" , recycleBinFolder ) ;
279
323
return true ;
280
324
}
281
325
} ,
0 commit comments