2014-12-30 2 views
3

Что-то я не понимаю о ожидаемых таймерах. Я искал в Интернете и читал спецификации на MSDN плюс все, что мог найти в stackoverflow (например, link), но мои таймеры срабатывают почти сразу после остановки ПК.Понимание ожидаемых таймеров

Чтобы сосредоточиться на проблеме, которую я написал небольшую тестовую программу, используя xe5 (64-бит) в Windows 7 и пытались дублировать проект здесь: http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation

Я думал, что проблема была, как я получить время, но Кажется, я не могу найти проблему.

Тест приложение выглядит следующим образом (очень простой):

enter image description here

Я объявляю тип резьбы следующим

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 минут после того, как система переходит в режим приостановки независимо от выбранного количества времени. Любые указания относительно того, что я делаю неправильно, будут оценены.

EDIT

Найдено этот интересный инструмент командной строки, давайте нам проверить waitable таймеры. Из команды вы можете «видеть» состояние ваших waitable таймеров, набрав:

powercfg -waketimers 

я могу использовать это, чтобы подтвердить, что мои таймеры быть установлены правильно. Я также могу использовать это, чтобы подтвердить, что мои таймеры все еще работают, когда ПК преждевременно просыпается.

Используя тот же инструмент, вы можете получить список устройств, которые способны разбудить спящего режима (мыши, клавиатуры, сети в моем случае):

powercfg -devicequery wake_armed 

На всех системах тестирования, команда «Powercfg - lastwake»возвращает после чего я не знаю, как расшифровать:

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

Я позволил как сон и спящий режим в Windows, и оба будут просыпаться через несколько секунд. Нет активности клавиатуры и мыши, и у нас нет устройств, отправляющих запросы WOL (wake-on-lan) на эти ПК.

Мне интересно, есть ли что-то особенное, что нужно делать при вызове 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; 
+0

Вы уверены, что таймер пробуждает систему. Что произойдет, если вы приостановите работу системы без установки таймера. Вы также не проверяете наличие ошибок, указанных в документации. Ищите ERROR_NOT_SUPPORTED, когда SetWaitableTimer успешно завершен. –

+0

Есть инструмент командной строки, называемый powercfg, который позволяет вам запрашивать частые таймеры и получать некоторую информацию. Из командной строки «powercfg -devicequery wake_armed» показывает, какие устройства могут разбудить ПК. У меня 5 систем; только один просыпается сам по себе (без таймера). – lowrider

+0

@DavidHeffernan благодарит за помощь. Поэтому я вызываю GetLastError перед WaitForSingleObject и сравниваю результат с ERROR_NOT_SUPPORTED. Правильно ли это? В моих тестах GetLastError не возвращает ERROR_NOT_SUPPORTED. – lowrider

ответ

3

Проблема не связанные с Дельфи или код в любом случае. Проблема была создана с помощью функции Windows 7 , которая позволяет использовать более магические пакеты, когда включен WOL. Принуждение Windows только для прослушивания магических пакетов решило проблему.

MS Ссылка: http://support.microsoft.com/kb/941145

Спасибо всем, кто пытался помочь, и особенно Дэвид Heffernan, который намекал на возможность того, что еще что-то просыпался ПК.

Смежные вопросы