下班前常忘記簽退?想寫一個小程式,在 Windows 關機或登出時跳出提醒視窗,確認是否已完成簽退。這篇文章分享如何使用 Microsoft.Win32.SystemEvents.SessionEnding 事件實作這個需求,並討論兩個已知缺點與可能的改進方向。
SystemEvents.SessionEnding 是一個靜態事件,當使用者登出、關機或重新開機時觸發。需注意:
-=),否則會造成記憶體洩漏。using System;
using System.Windows.Forms;
using Microsoft.Win32;
namespace ShutdownReminder
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
FormShutdown formShutdown = new FormShutdown();
// 訂閱 SessionEnding 事件
SystemEvents.SessionEnding += new SessionEndingEventHandler(formShutdown.SystemEvents_SessionEnding);
Application.Run(formShutdown);
}
}
}
using System;
using System.Windows.Forms;
using Microsoft.Win32;
namespace ShutdownReminder
{
public partial class FormShutdown : Form
{
const string MESSAGE_TXT = "您簽退了嗎?";
const string MESSAGE_TITLE = "提示";
public FormShutdown()
{
InitializeComponent();
}
// 事件處理函式
internal void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
DialogResult result = MessageBox.Show(MESSAGE_TXT, MESSAGE_TITLE, MessageBoxButtons.YesNo);
// 若使用者選「否」,取消關機/登出
e.Cancel = (result == DialogResult.No);
}
private void FormShutdown_Load(object sender, EventArgs e)
{
// 將視窗移至螢幕右上角(不干擾操作)
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - 200, 0);
}
// 表單關閉時移除事件訂閱,防止記憶體洩漏
protected override void OnClosed(EventArgs e)
{
SystemEvents.SessionEnding -= new SessionEndingEventHandler(this.SystemEvents_SessionEnding);
base.OnClosed(e);
}
}
}
SessionEnding 僅涵蓋登出、關機、重開機,不包含睡眠/休眠狀態轉換。針對上述缺點,社群常見的替代方案包括:
Win32_OperatingSystem 的關機事件,可在服務或主控台應用程式中運作,且不需載入 WinForms 組件,記憶體佔用較低。ServiceBase.CanHandleSessionChangeEvent 處理 Session 變更,支援更多事件類型(含鎖定/解鎖、遠端連線等)。SystemEvents.SessionEnding 提供最簡單的方式在 WinForms 應用程式中攔截關機流程,適合快速原型或內部小工具。若需部署正式環境、支援休眠事件或追求極低資源佔用,建議改用 WMI 或 Windows Service 架構。