Vanara/System/Diagnostics/SystemShutdown.cs

140 lines
8.0 KiB
C#

using System;
using Vanara.PInvoke;
using Vanara.Security.AccessControl;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.User32;
namespace Vanara.Diagnostics
{
/// <summary>Provides access to system shutdown, restart, lock and notifications.</summary>
public static class SystemShutdown
{
/// <summary>Stops a system shutdown started by using the InitiateSystemShutdown function.</summary>
/// <param name="machineName">
/// String that specifies the network name of the computer where the shutdown is to be stopped. If NULL or an empty string, the
/// function stops the shutdown on the local computer.
/// </param>
/// <returns>0 on failure, non-zero for success</returns>
public static bool AbortShutdown(string machineName = null) => AbortSystemShutdown(machineName);
/// <summary>
/// Logs off the current user, shuts down the system, or shuts down and restarts the system. It sends the WM_QUERYENDSESSION message
/// to all applications to determine if they can be terminated.
/// </summary>
/// <param name="flags">Specifies the type of shutdown.</param>
/// <param name="reason">The reason for initiating the shutdown.</param>
/// <returns>
/// If the function succeeds, the return value is nonzero. <br></br><br>If the function fails, the return value is zero. To get
/// extended error information, call Marshal.GetLastWin32Error.</br>
/// </returns>
public static bool ExitWindows(ExitWindowsFlags flags = ExitWindowsFlags.EWX_LOGOFF, SystemShutDownReason reason = SystemShutDownReason.SHTDN_REASON_UNKNOWN)
{
var reqPriv = (flags & (ExitWindowsFlags.EWX_POWEROFF | ExitWindowsFlags.EWX_REBOOT | ExitWindowsFlags.EWX_SHUTDOWN)) != 0;
using (new PrivilegedCodeBlock(reqPriv ? new[] { SystemPrivilege.Shutdown } : new SystemPrivilege[0]))
return ExitWindowsEx(flags, reason);
}
/// <summary>Suspends the system by entering hibernation (S4).</summary>
/// <param name="wakeupEventsDisabled">
/// If this parameter is <see langword="true"/>, the system disables all wake events. If the parameter is <see langword="false"/>,
/// any system wake events remain enabled.
/// </param>
/// <returns>
/// <see langword="true"/> if the operation was successful; <see langword="false"/> if operation is not allowed by system
/// administrator settings or account privileges.
/// </returns>
public static bool Hibernate(bool wakeupEventsDisabled = false) => Suspend(true, wakeupEventsDisabled);
/// <summary>
/// Initiates a shutdown and restart of the specified computer, and restarts any applications that have been registered for restart.
/// </summary>
/// <param name="machineName">
/// The name of the computer to be shut down. If the value of this parameter is NULL, the local computer is shut down.
/// </param>
/// <param name="message">The message to be displayed in the interactive shutdown dialog box.</param>
/// <param name="gracePeriod">
/// The number of seconds to wait before shutting down the computer. If the value of this parameter is zero, the computer is shut
/// down immediately. This value is limited to MAX_SHUTDOWN_TIMEOUT.
/// <para>
/// If the value of this parameter is greater than zero, and the dwShutdownFlags parameter specifies the flag
/// SHUTDOWN_GRACE_OVERRIDE, the function fails and returns the error code ERROR_BAD_ARGUMENTS.
/// </para>
/// </param>
/// <param name="flags">One or more bit flags that specify options for the shutdown.</param>
/// <param name="reason">
/// The reason for initiating the shutdown. This parameter must be one of the system shutdown reason codes. If this parameter is
/// zero, the default is an undefined shutdown that is logged as "No title for this reason could be found". By default, it is also an
/// unplanned shutdown. Depending on how the system is configured, an unplanned shutdown triggers the creation of a file that
/// contains the system state information, which can delay shutdown. Therefore, do not use zero for this parameter.
/// </param>
public static void InitiateShutdown(string machineName, string message, TimeSpan gracePeriod, ShutdownFlags flags, SystemShutDownReason reason = SystemShutDownReason.SHTDN_REASON_UNKNOWN)
{
var graceSecs = (uint)gracePeriod.TotalSeconds;
if (graceSecs > MAX_SHUTDOWN_TIMEOUT) throw new ArgumentOutOfRangeException(nameof(gracePeriod), $"Grace period can be no longer than {MAX_SHUTDOWN_TIMEOUT} seconds.");
using (string.IsNullOrEmpty(machineName) ? new PrivilegedCodeBlock(SystemPrivilege.Shutdown) : new PrivilegedCodeBlock(SystemPrivilege.RemoteShutdown))
AdvApi32.InitiateShutdown(machineName, message, graceSecs, flags, reason);
}
/// <summary>Initiates a shutdown and optional restart of the specified computer.</summary>
/// <param name="machineName">
/// String that specifies the network name of the computer to shut down. If NULL or an empty string, the function shuts down the
/// local computer.
/// </param>
/// <param name="message">
/// String that specifies a message to display in the shutdown dialog box. This parameter can be NULL if no message is required.
/// </param>
/// <param name="timeout">
/// Time that the shutdown dialog box should be displayed, in seconds. While this dialog box is displayed, shutdown can be stopped by
/// the AbortSystemShutdown function.
/// </param>
/// <param name="forceAppsClosed">
/// If this parameter is TRUE, applications with unsaved changes are to be forcibly closed. If this parameter is FALSE, the system
/// displays a dialog box instructing the user to close the applications.
/// </param>
/// <param name="rebootAfterShutdown">
/// If this parameter is TRUE, the computer is to restart immediately after shutting down. If this parameter is FALSE, the system
/// flushes all caches to disk and clears the screen.
/// </param>
/// <param name="reason">Reason for initiating the shutdown. This parameter must be one of the system shutdown reason codes.</param>
/// <returns>0 on failure, non-zero for success</returns>
public static bool InitiateShutdown(string machineName = null, string message = null, TimeSpan? timeout = null, bool forceAppsClosed = false, bool rebootAfterShutdown = false, SystemShutDownReason reason = SystemShutDownReason.SHTDN_REASON_UNKNOWN)
{
var graceSecs = (uint)timeout.GetValueOrDefault().TotalSeconds;
if (Environment.OSVersion.Version.Major <= 5 && graceSecs > MAX_SHUTDOWN_TIMEOUT) throw new ArgumentOutOfRangeException(nameof(timeout), $"Timeout can be no longer than {MAX_SHUTDOWN_TIMEOUT} seconds on Windows XP and earlier systems.");
using (string.IsNullOrEmpty(machineName) ? new PrivilegedCodeBlock(SystemPrivilege.Shutdown) : new PrivilegedCodeBlock(SystemPrivilege.RemoteShutdown))
return InitiateSystemShutdownEx(machineName, message, graceSecs, forceAppsClosed, rebootAfterShutdown, reason);
}
/// <summary>Locks the workstation's display, protecting it from unauthorized use.</summary>
public static bool LockWorkStation() => User32.LockWorkStation();
/// <summary>Suspends the system by entering a suspend (sleep) state.</summary>
/// <param name="wakeupEventsDisabled">
/// If this parameter is <see langword="true"/>, the system disables all wake events. If the parameter is <see langword="false"/>,
/// any system wake events remain enabled.
/// </param>
/// <returns>
/// <see langword="true"/> if the operation was successful; <see langword="false"/> if operation is not allowed by system
/// administrator settings or account privileges.
/// </returns>
public static bool Suspend(bool wakeupEventsDisabled = false) => Suspend(false, wakeupEventsDisabled);
private static bool Suspend(bool hibernate, bool wakeupEventsDisabled)
{
try
{
using (new PrivilegedCodeBlock(SystemPrivilege.Shutdown))
{
if (hibernate)
return PowrProf.IsPwrHibernateAllowed() ? PowrProf.SetSuspendState(true, false, wakeupEventsDisabled) : false;
else
return PowrProf.IsPwrSuspendAllowed() ? PowrProf.SetSuspendState(false, false, wakeupEventsDisabled) : false;
}
}
catch
{
return false;
}
}
}
}