为什么.NET阻止Windows关机操作总是失败?
摘要:本文主要介绍Windows在关闭时,如何正确、可靠的阻止系统关机以及关机前执行相应业务 Windows关机,默认会给应用几s的关闭时间,但有一些场景需要在关机重启前执行更长时间的业务逻辑,确保下次开机时数据的一致性以及可靠性。我司目前业务
本文主要介绍Windows在关闭时,如何正确、可靠的阻止系统关机以及关机前执行相应业务
Windows关机,默认会给应用几s的关闭时间,但有一些场景需要在关机/重启前执行更长时间的业务逻辑,确保下次开机时数据的一致性以及可靠性。我司目前业务也用到关机阻止,但这块之前并未梳理清楚,依赖BUG编程,导致后续维护项目时关机这块又会出现新问题。
统一整理,以下是实现这一需求的几种方法,
1. Windows消息Hook勾子
1 public MainWindow()
2 {
3 InitializeComponent();
4 Loaded += OnLoaded;
5 }
6
7 private void OnLoaded(object sender, RoutedEventArgs e)
8 {
9 Loaded -= OnLoaded;
10 var source = PresentationSource.FromVisual(this) as HwndSource;
11 source?.AddHook(WndProc);
12 }
13 const int WM_QUERYENDSESSION = 0x11;
14 const int WM_ENDSESSION = 0x16;
15 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
16 {
17 if (msg == WM_QUERYENDSESSION)
18 {
19 var handle = new WindowInteropHelper(this).Handle;
20 ShutdownBlockReasonCreate(handle, "应用保存数据中,请等待...");
21 // 可以在这里执行你的业务逻辑
22 bool executeSuccess = ExecuteShutdownWork();
23 // 返回0表示阻止关机,1表示允许关机
24 handled = true;
25 return executeSuccess ? (IntPtr)1 : (IntPtr)0;
26 }
27 return (IntPtr)1;
28 }
29
30 private bool ExecuteShutdownWork()
31 {
32 Thread.Sleep(TimeSpan.FromSeconds(20));
33 //测试,默认返回操作失败
34 return false;
35 }
36
37 [DllImport("user32.dll")]
38 private static extern bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string reason);
39 [DllImport("user32.dll")]
40 private static extern bool ShutdownBlockReasonDestroy(IntPtr hWnd);
通过Hook循环windows窗口消息,WndProc接收到WM_QUERYENDSESSION时表示有关机调用,详细的可以查看官网文档:(WinUser.h) WM_QUERYENDSESSION消息 - Win32 apps | Microsoft Learn
WndProc返回1表示业务正常,0表示取消、阻止关机。
