捕獲系統睡眠、喚醒通知事件

今天想寫個小程序記錄每天電腦實際工作時間,由此需要捕獲系統睡眠,喚醒的通知事件。查詢了一下可以通過api PowerRegisterSuspendResumeNotification實現這功能。

進一步搜索了下,stackoverflow上有現成的封裝代碼 , 就基於它的代碼簡單的改了下:

public class PowerEvent
{
	public static void Regist()
	{
		var registrationHandle = new IntPtr();
		var recipient = new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
		{
			Callback = DeviceNotifyCallback,
			Context  = IntPtr.Zero
		};

		var pRecipient = Marshal.AllocHGlobal(Marshal.SizeOf(recipient));
		Marshal.StructureToPtr(recipient, pRecipient, false);

		var result =
			PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, ref recipient, ref registrationHandle);

		if (result != 0)
			Console.WriteLine("Error registering for power notifications: " + Marshal.GetLastWin32Error());
		else
			Console.WriteLine("Successfully Registered for power notifications!");

		Console.ReadKey();
	}

	private static int DeviceNotifyCallback(IntPtr context, int type, IntPtr setting)
	{
		Console.WriteLine(
			$"\n\n{DateTime.Now}:   Device notify callback called: context: {context},type: {type}, setings: {setting}");

		switch (type)
		{
			case PBT_APMPOWERSTATUSCHANGE:
				Console.WriteLine("\tPower status has changed.");
				break;

			case PBT_APMRESUMEAUTOMATIC:
				Console.WriteLine(
					"\tOperation is resuming automatically from a low-power state.This message is sent every time the system resumes.");
				break;

			case PBT_APMRESUMESUSPEND:
				Console.WriteLine(
					"\tOperation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.");
				break;

			case PBT_APMSUSPEND:
				Console.WriteLine("\tSystem is suspending operation.");
				break;
			case PBT_POWERSETTINGCHANGE:
				Console.WriteLine("\tA power setting change event has been received. ");
				break;
			default:
				Console.WriteLine("unknown");
				break;
		}

		// do something here
		return 0;
	}

	[DllImport("Powrprof.dll", SetLastError = true)]
	static extern uint PowerRegisterSuspendResumeNotification(
		uint flags, ref DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS receipient, ref IntPtr registrationHandle);


	private const int WM_POWERBROADCAST        = 536; // (0x218)
	private const int PBT_APMPOWERSTATUSCHANGE = 10;  // (0xA) - Power status has changed.

	private const int
		PBT_APMRESUMEAUTOMATIC =
			18; // (0x12) - Operation is resuming automatically from a low-power state.This message is sent every time the system resumes.

	private const int
		PBT_APMRESUMESUSPEND =
			7; // (0x7) - Operation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.

	private const int PBT_APMSUSPEND         = 4;     // (0x4) - System is suspending operation.
	private const int PBT_POWERSETTINGCHANGE = 32787; // (0x8013) - A power setting change event has been received.
	private const int DEVICE_NOTIFY_CALLBACK = 2;

	/// <summary>
	/// OS callback delegate definition
	/// </summary>
	/// <param name="context">The context for the callback</param>
	/// <param name="type">The type of the callback...for power notifcation it's a PBT_ message</param>
	/// <param name="setting">A structure related to the notification, depends on type parameter</param>
	/// <returns></returns>
	delegate int DeviceNotifyCallbackRoutine(IntPtr context, int type, IntPtr setting);

	/// <summary>
	/// A callback definition
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	struct DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
	{
		public DeviceNotifyCallbackRoutine Callback;
		public IntPtr                      Context;
	}
}

參考文章: windows - C#, SystemEvents.PowerModeChanged event is not raised on sleep or resume - Stack Overflow

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章