Skip to content

Commit 14b8a99

Browse files
committed
Fixed shutdown attempts failing due to an access denied error.
1 parent e17c9b6 commit 14b8a99

1 file changed

Lines changed: 119 additions & 6 deletions

File tree

VidCoder/Services/SystemOperations.cs

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,114 @@ private static extern bool InitiateSystemShutdownEx(
8787
bool bRebootAfterShutdown,
8888
ShutdownReason dwReason);
8989

90+
private const string ShutdownPrivilegeName = "SeShutdownPrivilege";
91+
92+
private const uint TokenAdjustPrivileges = 0x20;
93+
private const uint TokenQuery = 0x8;
94+
private const uint SePrivilegeEnabled = 0x2;
95+
96+
[StructLayout(LayoutKind.Sequential)]
97+
private struct Luid
98+
{
99+
public uint LowPart;
100+
public int HighPart;
101+
}
102+
103+
[StructLayout(LayoutKind.Sequential)]
104+
private struct LuidAndAttributes
105+
{
106+
public Luid Luid;
107+
public uint Attributes;
108+
}
109+
110+
[StructLayout(LayoutKind.Sequential)]
111+
private struct TokenPrivileges
112+
{
113+
public uint PrivilegeCount;
114+
public LuidAndAttributes Privileges;
115+
}
116+
117+
[DllImport("advapi32.dll", SetLastError = true)]
118+
private static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle);
119+
120+
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
121+
private static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out Luid lpLuid);
122+
123+
[DllImport("advapi32.dll", SetLastError = true)]
124+
private static extern bool AdjustTokenPrivileges(
125+
IntPtr tokenHandle,
126+
bool disableAllPrivileges,
127+
ref TokenPrivileges newState,
128+
uint bufferLength,
129+
IntPtr previousState,
130+
IntPtr returnLength);
131+
132+
[DllImport("kernel32.dll")]
133+
private static extern IntPtr GetCurrentProcess();
134+
135+
[DllImport("kernel32.dll", SetLastError = true)]
136+
[return: MarshalAs(UnmanagedType.Bool)]
137+
private static extern bool CloseHandle(IntPtr hObject);
138+
90139
[DllImport("winmm.dll")]
91140
static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);
92141

142+
private static bool TryEnableShutdownPrivilege(out string failureMessage)
143+
{
144+
failureMessage = null;
145+
146+
if (!OpenProcessToken(GetCurrentProcess(), TokenAdjustPrivileges | TokenQuery, out IntPtr token))
147+
{
148+
failureMessage = new Win32Exception().Message;
149+
return false;
150+
}
151+
152+
try
153+
{
154+
if (!LookupPrivilegeValue(null, ShutdownPrivilegeName, out Luid luid))
155+
{
156+
failureMessage = new Win32Exception().Message;
157+
return false;
158+
}
159+
160+
TokenPrivileges tokenPrivileges = new TokenPrivileges
161+
{
162+
PrivilegeCount = 1,
163+
Privileges = new LuidAndAttributes
164+
{
165+
Luid = luid,
166+
Attributes = SePrivilegeEnabled,
167+
},
168+
};
169+
170+
if (!AdjustTokenPrivileges(token, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
171+
{
172+
failureMessage = new Win32Exception().Message;
173+
return false;
174+
}
175+
176+
if (Marshal.GetLastWin32Error() == 1300) // ERROR_NOT_ALL_ASSIGNED
177+
{
178+
failureMessage = "The process does not hold the shutdown privilege.";
179+
return false;
180+
}
181+
182+
return true;
183+
}
184+
finally
185+
{
186+
CloseHandle(token);
187+
}
188+
}
189+
190+
private static void TryEnableShutdownPrivilegeAndLog()
191+
{
192+
if (!TryEnableShutdownPrivilege(out string failureMessage))
193+
{
194+
logger.LogError("Could not enable shutdown privilege: " + failureMessage);
195+
}
196+
}
197+
93198
public void Sleep()
94199
{
95200
logger.Log("Sleeping.");
@@ -99,24 +204,32 @@ public void Sleep()
99204
public void LogOff()
100205
{
101206
logger.Log("Logging off.");
207+
TryEnableShutdownPrivilegeAndLog();
102208
ExitWindowsEx(ExitWindows.LogOff, ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned);
103209
}
104210

105211
public void ShutDown()
106212
{
107213
logger.Log("Shutting down.");
108-
InitiateSystemShutdownEx(
109-
null,
110-
null,
214+
TryEnableShutdownPrivilegeAndLog();
215+
216+
if (!InitiateSystemShutdownEx(
217+
null,
218+
null,
111219
0,
112-
true,
113-
false,
114-
ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned);
220+
true,
221+
false,
222+
ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned))
223+
{
224+
var error = new Win32Exception();
225+
logger.LogError($"System shutdown failed: {error.Message}");
226+
}
115227
}
116228

117229
public void Restart()
118230
{
119231
logger.Log("Restarting.");
232+
TryEnableShutdownPrivilegeAndLog();
120233
ExitWindowsEx(ExitWindows.Reboot, ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned);
121234
}
122235

0 commit comments

Comments
 (0)