tft每日頭條

 > 科技

 > 怎樣喚醒休眠狀态的電腦

怎樣喚醒休眠狀态的電腦

科技 更新时间:2024-10-06 04:28:01

最近碰到一個關于芯片測試過程中的問題,這顆芯片是用在筆記本端口上,筆記本客戶那邊會有一個壓力測試,就是頻繁的電腦電源狀态切換,S0(正常使用的開機狀态),S3(睡眠模式),S4(休眠模式)以及S5(關機模式)。

當然,主要是客戶在壓力測試過程中,發現了芯片會不正常的死鎖,客戶那邊将機台寄回來,那麼該如何複現呢?客戶那邊會有自己的一套壓力測試系統,不過會測試很多東西,不太方便給我們,而且每一次循環耗時比較久。那麼,能不能自己搭建一套控制電腦睡眠,休眠,關機以及喚醒的程序呢?

上面講的是一個應用背景,告訴大家這其實也是有需求的,隻是平時不太用而已,将其記錄下來:

首先,從電腦開機狀态S0切換到S3,S4甚至是S5,都是比較容易實現的,見下面代碼:

Application.SetSuspendState(PowerState.Suspend, false, false);//從S0進入S3 Application.SetSuspendState(PowerState.Hibernate,false,false);//從S0進入S4 Process.Start("shutdown","/s /t 0"); // 參數 /s 的意思是要關閉計算機 // 參數 /t 0 的意思是告訴計算機 0 秒之後執行命令 Process.Start("shutdown", "/r /t 0"); // 參數 /r 的意思是要重新啟動計算機

隻要調用上述語句即可實現從S0到其他的電源狀态,那麼反過來喚醒呢?

喚醒的難點在于:當處于S3,S4以及S5的狀态下,我的上位機程序是不會運行的,因此,在上位機軟件的定時喚醒也是沒法工作的。那麼筆記本客戶那邊是怎麼操作的呢?他們會通過底層的EC控制來顯示上述的功能,可是,我們是不知道底層EC的接口,而且,我們需要一個通用的程式,那要怎麼實現呢?

在筆記本的設計中,在S3,S4,S5通常不是所有的東西都會關掉,通常會有一個硬件定時器還在開着,如果我們能操作這個定時器,那是不是就可以實現我們想要的功能呢?

可以調用下面的兩個函數,即CreateWaitableTimer以及SetWaitableTimer,這兩個函數就可以控制電腦裡面開的硬件定時器,當然這個硬件定時器是CPU裡面的還是EC裡面的,我也不太清楚,沒研究過,如果有大神研究過,可以留言,我也學習學習。

[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, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);

另外,需要說明的一點是,使用這個定時器也是有條件的,你需要先設置筆記本,"Control Panel > Power Options > Change Plan Settings > Change Advanced Power Settings > Sleep > Allow Wake Timers", 使能定時器喚醒,還有就是,"Control Panel > Power Options > Change Plan Settings > Change Advanced Power Settings > Brad / Additional Settings > Require a password on wakeup",關閉喚醒需要密碼。

完成上面的設置,其實已經可以實現電腦從S3,S4,S5喚醒了,但在我使用的過程中,其實還碰到了一個問題,就是喚醒之後,屏幕不亮,你就會誤認為沒有喚醒,因此我增加了控制鼠标移動的命令,這樣,喚醒之後,屏幕就會亮起。

[DllImport("user32.dll")] public static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo); mouse_event(0x0001,0,1,0,UIntPtr.Zero); mouse_event(0x0001, 0, -1, 0, UIntPtr.Zero);

另外還有一點需要注意,就是筆記本從S0->S3/S4/S5->S0這個循環裡面,S0,S3/S4/S5這幾個狀态的停留時間一定要足夠,因為,每個筆記本的完全進入各個狀态的時間會不一樣,比如,我用我自己的筆記本,這幾個狀态的停留時間要至少20s,否則,筆記本還沒有完全進入就要退出,就會導緻,電腦把WaitableTimer關掉,而筆記本還沒有喚醒,導緻程式死鎖。而新的剛買的筆記本,隻需要設置10s即可完全進入。

廢話不多說,直接上代碼:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; namespace AutoSwitchGUI { public partial class AutoSwitchGUI : Form { [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, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume); [DllImport("kernel32.dll")] public static extern uint SetThreadExecutionState(uint esFlags); [DllImport("user32.dll")] public static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo); //public event EventHandler Woken; private BackgroundWorker bgWorker = new BackgroundWorker(); public struct auto_switch_gui_status_t { public bool test_status; public UInt64 test_times_cnt; public UInt64 test_times; public byte cur_state; public int s0_duration; public int s3_duration; } public auto_switch_gui_status_t auto_switch_status; public AutoSwitchGUI() { InitializeComponent(); bgWorker.DoWork = new DoWorkEventHandler(bgWorker_Dowork); bgWorker.RunWorkerCompleted = new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted); } 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 bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { mouse_event(0x0001,0,1,0,UIntPtr.Zero); mouse_event(0x0001, 0, -1, 0, UIntPtr.Zero); auto_switch_status.test_times_cnt ; TestTimes.Text = auto_switch_status.test_times_cnt.ToString(); SystemTimer.Interval = auto_switch_status.s0_duration * 1000; SystemTimer.Start(); } public void SetWakeUpTime(UInt64 time) { bgWorker.RunWorkerAsync(System.DateTime.Now.AddSeconds(time).ToFileTime()); } private void StartButton_Click(object sender, EventArgs e) { try { auto_switch_status.test_times = UInt64.Parse(SetTestTimes.Text); auto_switch_status.s0_duration = int.Parse(S0Duration.Text); auto_switch_status.s3_duration = int.Parse(S3Duration.Text); if (auto_switch_status.test_times > 0) { //SetThreadExecutionState(0x00000001 | 0x00000002 | 0x80000000 | 0x00000040); TestStatus.BackColor = Color.Green; auto_switch_status.test_status = true; TestTimes.Text = "0"; auto_switch_status.test_times_cnt = 0; SystemTimer.Interval = auto_switch_status.s0_duration*1000; auto_switch_status.cur_state = 0; SystemTimer.Start(); return; } } catch { } MessageBox.Show("Configuration Failed!"); } private void StopButton_Click(object sender, EventArgs e) { SystemTimer.Stop(); auto_switch_status.test_status = true; TestStatus.BackColor = Color.Red; } private void SystemTimer_Tick(object sender, EventArgs e) { if (auto_switch_status.cur_state == 0) { auto_switch_status.cur_state = 0; SystemTimer.Stop(); if (auto_switch_status.test_times_cnt >= auto_switch_status.test_times) { } else { SetWakeUpTime((UInt64)auto_switch_status.s3_duration); Application.SetSuspendState(PowerState.Suspend, false, false); //Application.SetSuspendState(PowerState.Hibernate, false, false); } } else if (auto_switch_status.cur_state == 1) { auto_switch_status.test_times_cnt ; TestTimes.Text = auto_switch_status.test_times_cnt.ToString(); auto_switch_status.cur_state = 0; SendKeys.Send(" "); MessageInfo.Text = "TEST1\r\n"; } } } }

另外聲明,關于SetWaitableTimer和CreateWaitableTimer我是參考如下鍊接的:

怎樣喚醒休眠狀态的電腦(C控制電腦睡眠)1

希望可以幫到大家,上面代碼在我自己的筆記本以及客戶的筆記本是可以适用的。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved