using System.Diagnostics; using System.Runtime.InteropServices; using AutoShutdown.Models; namespace AutoShutdown.Services; internal sealed class PowerService { [DllImport("PowrProf.dll", SetLastError = true)] private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent); [DllImport("user32.dll", SetLastError = true)] private static extern bool LockWorkStation(); public void Execute(PowerAction action, int delaySeconds, bool forceApps) { switch (action) { case PowerAction.Shutdown: RunShutdownCommand($"/s /t {Math.Max(0, delaySeconds)}{ForceFlag(forceApps)}"); break; case PowerAction.Restart: RunShutdownCommand($"/r /t {Math.Max(0, delaySeconds)}{ForceFlag(forceApps)}"); break; case PowerAction.LogOff: if (delaySeconds > 0) { using var timer = new System.Threading.Timer(_ => RunShutdownCommand($"/l{ForceFlag(forceApps)}"), null, TimeSpan.FromSeconds(delaySeconds), Timeout.InfiniteTimeSpan); Thread.Sleep(TimeSpan.FromSeconds(delaySeconds + 1)); } else { RunShutdownCommand($"/l{ForceFlag(forceApps)}"); } break; case PowerAction.Lock: DelayThen(delaySeconds, () => LockWorkStation()); break; case PowerAction.Sleep: DelayThen(delaySeconds, () => SetSuspendState(false, forceApps, false)); break; case PowerAction.Hibernate: DelayThen(delaySeconds, () => SetSuspendState(true, forceApps, false)); break; } } public bool CancelShutdown() { var result = RunProcess("shutdown.exe", "/a", showWindow: false); return result == 0; } private static string ForceFlag(bool forceApps) => forceApps ? " /f" : string.Empty; private static void DelayThen(int delaySeconds, Action action) { if (delaySeconds > 0) { Task.Delay(TimeSpan.FromSeconds(delaySeconds)).ContinueWith(_ => action(), TaskScheduler.Default); return; } action(); } private static void RunShutdownCommand(string arguments) { var code = RunProcess("shutdown.exe", arguments, showWindow: false); if (code != 0) { throw new InvalidOperationException($"shutdown.exe 执行失败,退出码 {code}。"); } } private static int RunProcess(string fileName, string arguments, bool showWindow) { using var process = Process.Start(new ProcessStartInfo { FileName = fileName, Arguments = arguments, UseShellExecute = false, CreateNoWindow = !showWindow, WindowStyle = showWindow ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden }); if (process is null) { return -1; } process.WaitForExit(); return process.ExitCode; } }