using System.Windows.Forms;
using Vanara.PInvoke;
using static Vanara.PInvoke.User32;
namespace Vanara.Windows.Forms.Forms;
/// Used to define a set of operations within which any shutdown request will be met with a reason why this application is blocking it.
/// This is to be used in either a 'using' statement or for the life of the application.
/// To use for the life of the form, define a class field:
///
/// private PreventShutdownContext disallowShutdown;
///
/// protected override void OnHandleCreated(EventArgs e)
/// {
/// base.OnHandleCreated(e);
/// disallowShutdown = new PreventShutdownContext(this, "Application defined message goes here.");
/// }
///
/// To use this for a section of code:
///
/// using (new PreventShutdownContext(this, "This app is super busy right now."))
/// {
/// // Do something that can't be interrupted...
/// }
///
public class PreventShutdownContext : IDisposable
{
private const int WM_QUERYENDSESSION = 0x11;
private HandleRef href;
/// Initializes a new instance of the class.
/// The that contains a valid window handle.
/// The reason the application must block system shutdown. Because users are typically in a hurry when shutting down the system, they may spend only a few seconds looking at the shutdown reasons that are displayed by the system. Therefore, it is important that your reason strings are short and clear.
/// If set to , this class will return false to the WM_QUERYENDSESSION by handling the e.Cancel response to Form.FormClosing.
/// The system is configured to bypass showing application reasons for preventing shutdown.
public PreventShutdownContext(Form window, string reason, bool tryToPreventShutdown = false)
{
if ((Microsoft.Win32.Registry.GetValue(@"HKEY_USERS\.DEFAULT\Control Panel\Desktop", "AutoEndTasks", 0) is uint v1 && v1 == 1) ||
(Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Control Panel\Desktop", "AutoEndTasks", 0) is uint v2 && v2 == 1))
throw new SystemException("The system is configured to bypass showing application reasons for preventing shutdown.");
href = new HandleRef(window, window.Handle);
if (tryToPreventShutdown)
window.FormClosing += (s, e) => e.Cancel = true;
Reason = reason;
}
/// The reason the application must block system shutdown. Because users are typically in a hurry when shutting down the system, they may spend only a few seconds looking at the shutdown reasons that are displayed by the system. Therefore, it is important that your reason strings are short and clear.
/// The reason string.
public string Reason
{
get
{
if (!ShutdownBlockReasonQuery(href.Handle, out var reason))
Win32Error.ThrowLastError();
return reason;
}
set
{
if (value == null) value = string.Empty;
if (ShutdownBlockReasonQuery(href.Handle, out var _))
ShutdownBlockReasonDestroy(href.Handle);
if (!ShutdownBlockReasonCreate(href.Handle, value))
Win32Error.ThrowLastError();
}
}
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
{
ShutdownBlockReasonDestroy(href.Handle);
}
}