使用C#创建电脑定时唤醒程序

在现代计算机系统中,经常需要在特定时间唤醒电脑以执行某些任务。本文将介绍如何使用C#编程语言创建一个定时器,该定时器能够在指定的时间唤醒电脑。

电脑通常无法自行启动,但可以在待机或休眠状态下恢复。本文介绍的代码主要围绕两个系统定时器函数:

  • CreateWaitableTimer:创建一个可等待的定时器。
  • SetWaitableTimer:设置定时器的到期时间。

以下是这两个函数的声明:

[DllImport("kernel32.dll")] public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);

需要提供一个日期和时间,但是SetWaitableTimer要求一个长整型值。将使用DateTime.ToFileTime()函数将日期/时间从托管转换为系统表示。

核心代码

以下是程序的核心部分,调用两个API函数:

long waketime = (long)e.Argument; using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, this.GetType().Assembly.GetName().Name.ToString() + "Timer")) { if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true)) { using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset)) { wh.SafeWaitHandle = handle; wh.WaitOne(); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } }

在这段代码中,可以看到"e.Argument",这是因为以下代码块会暂停线程执行,直到定时器达到"唤醒时间"值:

using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset)) { wh.SafeWaitHandle = handle; wh.WaitOne(); }

为了避免阻塞UI线程,需要将这段代码放入一个单独的线程中,由BackgroundWorker对象控制,将唤醒时间作为参数传递给它。

类的定义

为了便于重用,创建了一个类,并提供了一个事件"Woken"。当后台线程退出时,该事件会被触发:

public event EventHandler Woken; void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (Woken != null) { Woken(this, new EventArgs()); } }

以下是完整的类定义:

using System; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.ComponentModel; using System.Threading; namespace WakeUPTimer { class WakeUP { [DllImport("kernel32.dll")] public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume); public event EventHandler Woken; private BackgroundWorker bgWorker = new BackgroundWorker(); public WakeUP() { bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork); bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted); } public void SetWakeUpTime(DateTime time) { bgWorker.RunWorkerAsync(time.ToFileTime()); } void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (Woken != null) { Woken(this, new EventArgs()); } } private void bgWorker_DoWork(object sender, DoWorkEventArgs e) { long waketime = (long)e.Argument; using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, this.GetType().Assembly.GetName().Name.ToString() + "Timer")) { if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true)) { using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset)) { wh.SafeWaitHandle = handle; wh.WaitOne(); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } } } }

使用代码

如果在表单上有一个按钮和一个日期时间选择器,可以这样编写代码:

private void button1_Click(object sender, EventArgs e) { WakeUP wup = new WakeUP(); wup.Woken += WakeUP_Woken; wup.SetWakeUpTime(dateTimePicker1.Value); } private void WakeUP_Woken(object sender, EventArgs e) { // Do something }

要使系统进入休眠状态:

Application.SetSuspendState(PowerState.Suspend, false, false);

重要提示:最后一个参数disableWakeEvent需要设置为false。

故障排除

  • 在"控制面板 > 电源选项 > 更改计划设置 > 更改高级电源设置 > 睡眠 > 允许唤醒定时器"中,所有项目都已启用。
  • 如果Windows帐户没有设置密码,请确保在"控制面板 > 电源选项 > 更改计划设置 > 更改高级电源设置 > 宽带 / 其他设置 > 唤醒时需要密码"中,所有项目都已禁用。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485