【问题标题】:Understanding waitable timers了解等待计时器
【发布时间】:2015-02-26 23:26:20
【问题描述】:

关于可等待计时器,我有些不明白。我在网上搜索并阅读了 MSDN 上的规范以及我在 stackoverflow 上可以找到的任何内容(例如 link),但我的计时器几乎在 PC 暂停后立即启动。

为了解决这个问题,我在 Windows 7 中使用 XE5(64 位)编写了一个小型测试应用程序,并尝试复制此处找到的项目:http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation

我认为问题在于我获得时间的方式,但我似乎找不到问题。

测试应用看起来像这样(非常简单):

我声明线程类型如下

type
   TWakeupThread    = class(TThread)
   private
     FTime:         LARGE_INTEGER;
  protected
     procedure      Execute; override;
  public
     constructor    Create(Time: LARGE_INTEGER);
  end;

...

constructor TWakeupThread.Create(Time: LARGE_INTEGER);
begin
  inherited Create(False);
  FreeOnTerminate:=True;
  FTime:=Time;
end;


procedure TWakeupThread.Execute;
var
   hTimer:     THandle;
begin
  // Create a waitable timer.
  hTimer:=CreateWaitableTimer(nil, True, 'WakeupThread');
  if (hTimer <> 0) then
  begin
     //CancelWaitableTimer(hTimer);
     if (SetWaitableTimer(hTimer, FTime.QuadPart, 0, nil, nil, True)) then
     begin
        WaitForSingleObject(hTimer, INFINITE);
     end;
     CloseHandle(hTimer);
  end;
end;

现在,当单击“设置计时器”按钮时,我会以这种方式计算文件时间并创建线程。

procedure TForm1.btnSetTimerClick(Sender: TObject);
var
   iUTCTime : LARGE_INTEGER;
   SysTime  : _SystemTime;
   FTime    : _FileTime;
   hHandle  : THandle;
   dt       : TDateTime;
begin
   ReplaceDate(dt,uiDate.DateTime);
   ReplaceTime(dt,uiTime.DateTime);
   DateTimeToSystemTime(dt, SysTime);
   SystemTimeToFileTime(SysTime, FTime);
   LocalFileTimeToFileTime(FTime, FTime);
   iUTCTime.LowPart := FTime.dwLowDateTime;
   iUTCTime.HighPart := FTime.dwHighDateTime;
   TWakeupThread.Create(iUTCTime);
end;

这不起作用。无论选择多少时间,计时器似乎在系统进入挂起模式后不到 2 分钟就会触发。任何关于我做错了什么的指针都将不胜感激。

编辑

找到了这个有趣的命令行工具,让我们检查可等待的计时器。在命令中,您可以通过键入以下内容“查看”可等待计时器的状态:

powercfg -waketimers

我可以使用它来确认我的计时器设置是否正确。我还可以使用它来确认当 PC 过早唤醒时我的计时器仍在运行。

使用相同的工具,您可以获得能够从休眠中唤醒的设备列表(在我的例子中是鼠标、键盘、网络):

powercfg -devicequery wake_armed

在所有测试的系统上,命令“powercfg -lastwake”返回以下我不知道如何破译的内容:

Wake History Count - 1
Wake History [0]
   Wake Source Count - 0

我在 Windows 中启用了睡眠和休眠,几秒钟后两者都会唤醒。没有键盘/鼠标活动,我们也没有设备向这些 PC 发送 WOL(局域网唤醒)请求。

我想知道调用 SetSuspendState 时是否需要做一些特别的事情;这是我的代码:

function SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent: Boolean): Boolean;
//Hibernate = False : system suspends
//Hibernate = True : system hibernates
begin
  if not Assigned(_SetSuspendState) then
     @_SetSuspendState := LinkAPI('POWRPROF.dll', 'SetSuspendState');
  if Assigned(_SetSuspendState) then
     Result := _SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent)
  else
     Result := False;
end;
function LinkAPI(const module, functionname: string): Pointer;
var
   hLib: HMODULE;
begin
     hLib := GetModuleHandle(PChar(module));
     if hLib =0 then
        hLib := LoadLibrary(PChar(module));
     if hLib <> 0 then
        Result := getProcAddress(hLib, PChar(functionname))
     else
        Result := nil;
end;
procedure TForm1.btnSuspendClick(Sender: TObject);
begin
     SetSuspendState(True, False, False);
end;

【问题讨论】:

  • 您确定计时器正在唤醒系统吗?如果在不设置计时器的情况下挂起系统会发生什么。您也不会按照文档的说明检查错误。 SetWaitableTimer 成功时查找 ERROR_NOT_SUPPORTED。
  • 有一个名为 powercfg 的命令行工具可以让您查询可唤醒的计时器并获取一些信息。从命令提示符“powercfg -devicequery wake_armed”显示哪些设备可以唤醒 PC。我有 5 个系统;只有一个自己醒来(没有计时器)。
  • @DavidHeffernan 感谢您的帮助。所以我在 WaitForSingleObject 之前调用 GetLastError 并将结果与​​ ERROR_NOT_SUPPORTED 进行比较。这是正确的方法吗?在我的测试中,GetLastError 不返回 ERROR_NOT_SUPPORTED。
  • @KenWhite 尝试了这个建议,但它并没有什么不同,只是当我关闭它时应用程序现在会产生错误......
  • @DavidHeffernan - 我认为你是对的;其他东西正在唤醒电脑。通过key/mouse/net的排除过程,我发现只有在连接了网线的情况下,电脑才会立即唤醒。尝试了两个开关=相同的行为。拔下网络电缆后,代码按预期运行。奇怪的是,我在 5 台电脑上观察到了这一点,只有两台共享一个公共平台。需要查看网络适配器的驱动程序/配置。

标签: delphi timer windows-7


【解决方案1】:

问题与 delphi 或任何方式的代码无关。该问题是由 Windows 7 的一项功能造成的,该功能在启用 WOL 时启用的不仅仅是魔术包。强制 Windows 只监听魔术包解决了这个问题。

MS 链接:http://support.microsoft.com/kb/941145

感谢所有试图提供帮助的人,尤其是 David Heffernan,他暗示可能有其他东西正在唤醒 PC。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-13
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 2012-12-17
    • 1970-01-01
    • 2010-11-22
    相关资源
    最近更新 更多