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,8 @@ 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
+ private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege" ;
26
+
23
27
public Control CreateSettingPanel ( )
24
28
{
25
29
var results = Commands ( ) ;
@@ -100,6 +104,44 @@ public void Init(PluginInitContext context)
100
104
} ;
101
105
}
102
106
107
+ private static unsafe bool EnableShutdownPrivilege ( )
108
+ {
109
+ try
110
+ {
111
+ if ( ! PInvoke . OpenProcessToken ( Process . GetCurrentProcess ( ) . SafeHandle , TOKEN_ACCESS_MASK . TOKEN_ADJUST_PRIVILEGES | TOKEN_ACCESS_MASK . TOKEN_QUERY , out var tokenHandle ) )
112
+ {
113
+ return false ;
114
+ }
115
+
116
+ if ( ! PInvoke . LookupPrivilegeValue ( null , SE_SHUTDOWN_NAME , out var luid ) )
117
+ {
118
+ return false ;
119
+ }
120
+
121
+ var privileges = new TOKEN_PRIVILEGES
122
+ {
123
+ PrivilegeCount = 1 ,
124
+ Privileges = new ( ) { e0 = new LUID_AND_ATTRIBUTES { Luid = luid , Attributes = TOKEN_PRIVILEGES_ATTRIBUTES . SE_PRIVILEGE_ENABLED } }
125
+ } ;
126
+
127
+ if ( ! PInvoke . AdjustTokenPrivileges ( tokenHandle , false , & privileges , 0 , null , null ) )
128
+ {
129
+ return false ;
130
+ }
131
+
132
+ if ( Marshal . GetLastWin32Error ( ) != ( int ) WIN32_ERROR . NO_ERROR )
133
+ {
134
+ return false ;
135
+ }
136
+
137
+ return true ;
138
+ }
139
+ catch ( Exception )
140
+ {
141
+ return false ;
142
+ }
143
+ }
144
+
103
145
private List < Result > Commands ( )
104
146
{
105
147
var results = new List < Result > ( ) ;
@@ -125,8 +167,11 @@ private List<Result> Commands()
125
167
// software updates, or other predefined reasons.
126
168
// SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure
127
169
if ( result == MessageBoxResult . Yes )
128
- PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS . EWX_POWEROFF ,
129
- SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
170
+ if ( EnableShutdownPrivilege ( ) )
171
+ PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS . EWX_POWEROFF ,
172
+ SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
173
+ else
174
+ Process . Start ( "shutdown" , "/s /t 0" ) ;
130
175
131
176
return true ;
132
177
}
@@ -145,8 +190,11 @@ private List<Result> Commands()
145
190
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
146
191
147
192
if ( result == MessageBoxResult . Yes )
148
- PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_REBOOT ,
149
- SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
193
+ if ( EnableShutdownPrivilege ( ) )
194
+ PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_REBOOT ,
195
+ SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
196
+ else
197
+ Process . Start ( "shutdown" , "/r /t 0" ) ;
150
198
151
199
return true ;
152
200
}
@@ -165,8 +213,11 @@ private List<Result> Commands()
165
213
MessageBoxButton . YesNo , MessageBoxImage . Warning ) ;
166
214
167
215
if ( result == MessageBoxResult . Yes )
168
- PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_REBOOT | EXIT_WINDOWS_FLAGS . EWX_BOOTOPTIONS ,
169
- SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
216
+ if ( EnableShutdownPrivilege ( ) )
217
+ PInvoke . ExitWindowsEx ( EXIT_WINDOWS_FLAGS . EWX_REBOOT | EXIT_WINDOWS_FLAGS . EWX_BOOTOPTIONS ,
218
+ SHUTDOWN_REASON . SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON . SHTDN_REASON_FLAG_PLANNED ) ;
219
+ else
220
+ Process . Start ( "shutdown" , "/r /o /t 0" ) ;
170
221
171
222
return true ;
172
223
}
0 commit comments