Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.08.27;
Скачать: CL | DM;

Вниз

Не срабатывает SetWaitableTimer.   Найти похожие ветки 

 
Б   (2010-04-15 12:18) [0]

Здрасти!

Почему не срабатывает SetWaitableTimer?
Будильник должен включиться ровно через 1 минуту после запуска.


Var
 HTIMER  : LongWord;
 TimeSys : TSystemTime;
 TimeFile: TFileTime;

Procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; dwTimerLowValue, dwTimerHighValue: DWORD); stdcall;
begin
 MessageBox(0, "Wake Up!", "!", MB_OK or MB_ICONERROR);
End;

Procedure XRunTimer(Hour, Minute: word);
begin
 HTIMER:= CreateWaitableTimer(nil, False, nil);
 If (HTIMER = 0) then
 begin
   MessageBox(0, "No create timer!", "!", MB_OK or MB_ICONERROR);
   Exit;
 end;

 GetLocalTime(TimeSys);                 // Текущая дата и время.
 TimeSys.wMinute:= TimeSys.wMinute + 1; // Должен сработать через 1 минуту.
 (*
 With TimeSys do
 begin
   wHour  := Hour;
   wMinute:= Minute;
 end;
 *)

 Win32Check(SystemTimeToFileTime(TimeSys, TimeFile));
 Win32Check(SetWaitableTimer(HTIMER, INT64(TimeFile), 0, @TimerAPCProc, nil, False));
End;

procedure TForm1.FormCreate(Sender: TObject);
begin
 XRunTimer(StrToInt(Edit1.Text), StrToInt(Edit2.Text));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 CloseHandle(HTIMER);
end;



 
Anatoly Podgoretsky ©   (2010-04-15 12:31) [1]

> Б  (15.04.2010 12:18:00)  [0]

Где обработка ошибки, а не это позорное "MessageBox(0, "No create timer!","


 
Б   (2010-04-15 12:35) [2]

А какая тут разница?
RaiseLastOSError или MessageBox.


 
Leonid Troyanovsky ©   (2010-04-15 12:47) [3]


> Б   (15.04.10 12:18)  

> Почему не срабатывает SetWaitableTimer?
> Будильник должен включиться ровно через 1 минуту после запуска.

http://rsdn.ru/forum/delphi/804841.1.aspx

--
Regards, LVT.


 
Б   (2010-04-15 13:00) [4]


> Leonid Troyanovsky ©   (15.04.10 12:47) [3]

Спасибо за пример.

Только я не понял, почему мой пример не работает без SleepEx.
С ним приложение зависает.
Как этого избежать?


 
Anatoly Podgoretsky ©   (2010-04-15 13:13) [5]

> Б  (15.04.2010 12:35:02)  [2]

За RaiseLastOSError тебе сисадмины будут ноги целовать, а за твое самоувереное морду бить.


 
Leonid Troyanovsky ©   (2010-04-15 13:14) [6]


> Б   (15.04.10 13:00) [4]

> Только я не понял, почему мой пример не работает без SleepEx.

http://msdn.microsoft.com/en-us/library/ms686898(VS.85).aspx

--
Regards, LVT.


 
Вариант   (2010-04-15 13:15) [7]


> Б   (15.04.10 13:00) [4]


> Только я не понял, почему мой пример не работает без SleepEx

Потому, что TimerAPCProc - это APCProc.


> С ним приложение зависает.
> Как этого избежать?


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


 
Б   (2010-04-15 16:19) [8]


> Anatoly Podgoretsky ©   (15.04.10 13:13) [5]
> > Б  (15.04.2010 12:35:02)  [2]
>
> За RaiseLastOSError тебе сисадмины будут ноги целовать,
> а за твое самоувереное морду бить.


Пока обойдусь без фетишистов.

> Вариант   (15.04.10 13:15) [7]
> Используй обычный таймер в главном потоке - это тебе будет проще, чем другие варианты, которые конечно тоже существуют.

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

> Leonid Troyanovsky ©   (15.04.10 13:14) [6]  

Поток виснет от этого.


 
Игорь Шевченко ©   (2010-04-15 16:45) [9]


> которая могла бы включаться даже из состояние спящего режима.


Гы


 
Б   (2010-04-15 16:50) [10]

> Гы

Или ждущий режим?
Или параметр fResume не для того?


 
Б   (2010-04-15 17:16) [11]

Ура!
Проверил, врубается из ждущего режима и проигрывает добавленную .mp3-ху. ;)


 
Б   (2010-04-15 17:34) [12]

Как теперь избавиться от зависания?

Создание потока? Application.ProcessMessages?


 
Сергей М. ©   (2010-04-15 17:55) [13]

Кури MsgWaitForMultipleObjectsEx()


 
Б   (2010-04-15 18:56) [14]

Замутно всё как-то...
Вроде бы сделал, обработку мессаг от зависания.

Как правильно её вызывать?



If SetWaitableTimer(HTIMER, TimeFile, 0, @TimerAPCProc, nil, True) then
   begin
     If (GetLastError = ERROR_NOT_SUPPORTED) then
     begin
       MessageBox(0, "Resume - no supported!", "!", MB_OK or MB_ICONERROR);

     end;

     Repeat
       Case MsgWaitForMultipleObjectsEx(1, HTIMER, INFINITE, QS_ALLPOSTMESSAGE, 0) of
         WAIT_OBJECT_0    : Break;                           // Finish.
         WAIT_OBJECT_0 + 1: Application.ProcessMessages;     // Process messages.
         else                                                // Error.
           RaiseLastOSError;
       end;
     Until False;

     SleepEx(INFINITE, True);
   end else
     RaiseLastOSError;



 
Leonid Troyanovsky ©   (2010-04-15 19:20) [15]


> Б   (15.04.10 18:56) [14]

> Как правильно её вызывать?

http://rsdn.ru/forum/delphi/500558.1.aspx

Ex оставлено в качестве домашнего задания.
Кста, для WaitableTimer TimerAPCProc не обязательна.

--
Regards, LVT.


 
Б   (2010-04-15 19:38) [16]

Заменил QS_ALLPOSTMESSAGE на QS_ALLINPUT и всё заработало наконец-то. ;)


 
Б   (2010-04-15 19:56) [17]

Программа не хочет закрываться крестиком.


 
Б   (2010-04-15 20:49) [18]


> Кста, для WaitableTimer TimerAPCProc не обязательна.


Тогда где ставить обработчик срабатывания будильника?


 
Leonid Troyanovsky ©   (2010-04-15 21:42) [19]


> Б   (15.04.10 20:49) [18]

> Тогда где ставить обработчик срабатывания будильника?

http://msdn.microsoft.com/en-us/library/ms687008

> Программа не хочет закрываться крестиком.

[15]

 Application.ProcessMessages;
 if Application.Terminated then
   Exit;

--
Regards, LVT.


 
Б   (2010-04-16 09:40) [20]


> Leonid Troyanovsky ©   (15.04.10 21:42) [19]


Да, лучше использовать WaitForSingleObject, т.к. объект ожидания 1.
Переделал так, но всё программа виснет:


If SetWaitableTimer(HTIMER, TimeFile, 0, nil, nil, True) then
   begin
     If (GetLastError = ERROR_NOT_SUPPORTED) then
     begin
       MessageBox(0, "Resume - no supported!", "!", MB_OK or MB_ICONERROR);

     end;
 
    Repeat
      Application.ProcessMessages;
      If Application.Terminated then Break;

      If (WaitForSingleObject(HTIMER, INFINITE) = WAIT_OBJECT_0) then
      begin
        Audio.Play(WakeUp.FAudID);
        MessageBox(0, PCHAR("Wake Up! - " + TimeToStr(Time)), "!", MB_OK or MB_ICONINFORMATION);
        Break;
      end else
      begin
        RaiseLastOSError;
        Break;
      end;
    Until False;


 
Сергей М. ©   (2010-04-16 10:13) [21]


> программа виснет


Конечно она виснет)
Ты же заставил ее "висеть" вызвав ф-цию ожидания, не реагирующую на оконные сообщения)


 
Leonid Troyanovsky ©   (2010-04-16 10:18) [22]


> Б   (16.04.10 09:40) [20]

http://rsdn.ru/forum/delphi/500558.1.aspx

--
Regards, LVT.


 
Б   (2010-04-16 11:08) [23]


> Сергей М. ©   (16.04.10 10:13) [21]


Если указать не INFINITE, а к примеру 10, то функция по идее должна
возвратить управление, выйти в начало Repeat, где произойдёт обработка мессаг окна
и попробовать снова.
Но происходит RaiseLastOSError.

> Leonid Troyanovsky ©   (16.04.10 10:18) [22]

Не, лучше вернуть к прежнему способу с APC-proc.

Почитал тут: http://www.compress.ru/Archive/CP/2001/9/38/index.htm
, чтобы GUI реагировал на нажатия и окно перерисовывалось нужно использовать как ни крути MsgWaitForMultipleObjectsEx.


 
Б   (2010-04-16 11:23) [24]

Тем более, с MsgWaitForMultipleObjectsEx
можно сделать поддержку нескольких таймеров и сделать
подобие планировщика задач.


 
Б   (2010-04-16 17:48) [25]

Остался 1 вопрос.

На вход функции запуска будильника принимается одна переменная типа TDateTime.
Как правильно передать ей дату и время?

WakeUp.RunTimer(Now + GetTime);  // Для примера текущая дата и время.


 
Anatoly Podgoretsky ©   (2010-04-16 18:56) [26]

> Б  (16.04.2010 17:48:25)  [25]

GetTime убери


 
Б   (2010-04-16 22:44) [27]

Забыл, что Now возвращает текущую дату и время, а не одну дату.

Почему не работает?:


// DateTimePicker"ы - настраиваются пользователем.
// У DateTimePicker2.Kind = dtkTime.
WakeUp.RunTimer(DateTimePicker1.Date + DateTimePicker2.Time);


 
Игорь Шевченко ©   (2010-04-16 23:00) [28]


> Почему не работает?:


не хочет


 
Б   (2010-04-16 23:09) [29]


> Игорь Шевченко ©   (16.04.10 23:00) [28]


Неожиданный ответ для вас. ;D

Вот так конвектирую время:


Var
 TimeFile: Int64;
 TimeSys : TSystemTime;
begin  
  DateTimeToSystemTime(WakeUpTime, TimeSys);
  Win32Check(SystemTimeToFileTime(TimeSys, TFILETIME(TimeFile)));



 
Leonid Troyanovsky ©   (2010-04-17 10:40) [30]


> Б   (16.04.10 11:08) [23]

> Не, лучше вернуть к прежнему способу с APC-proc.

Для гуевого приложения лучше вернуться к SetTimer.

--
Regards, LVT.


 
Б   (2010-04-17 13:05) [31]


> Leonid Troyanovsky ©   (17.04.10 10:40) [30]


SetTimer не будет срабатывать из ждущего режима, теряется весь смысл будильника.

В Caption выдаётся установленная дата и время.
Но будильник не срабатывает. В чём дело?


DateTimePicker1.Time:= DateTimePicker2.Time;

Caption:= DateTimeToStr(DateTimePicker1.Date);
WakeUp.RunTimer(DateTimePicker1.Date);


 
Б   (2010-04-17 21:34) [32]

Удалено модератором


 
Б   (2010-04-20 12:21) [33]

Остался последний вопрос:
Как прервать вызов MsgWaitForMultipleObjectsEx?


 
Leonid Troyanovsky ©   (2010-04-20 13:10) [34]


> Б   (20.04.10 12:21) [33]

> Как прервать вызов MsgWaitForMultipleObjectsEx?

PostMessage, QueueUserAPC.

--
Regards, LVT.


 
Сергей М. ©   (2010-04-20 13:10) [35]

Из другого потока уничтожить объект синхронизации или послать ожидающему потоку любое сообщение, например, WM_NULL


 
Вариант   (2010-04-20 13:37) [36]


> Сергей М. ©   (20.04.10 13:10) [35]


> Из другого потока уничтожить объект синхронизации

Не факт. Я бы не стал на это рассчитывать.  Поведение функции ожидания события (Msg)WaitForXXX  при CloseHandle (если это имелось ввиду под уничтожением) может быть не определенным в общем случае.


 
Leonid Troyanovsky ©   (2010-04-20 13:56) [37]


> Сергей М. ©   (20.04.10 13:10) [35]

> ожидающему потоку любое сообщение

Про "послать потоку" ИШ ссылался недавно:
http://transl-gunsmoker.blogspot.com/2010/04/blog-post_05.html

Ну, а про уничтожение
http://msdn.microsoft.com/en-us/library/ms687069(VS.85).aspx ;)

--
Regards, LVT.


 
Б   (2010-04-20 14:01) [38]

Начал делать через PostMessage.


Const
 WM_WAIT_STOP = WM_NULL + 1;

. . . . .

WAIT_OBJECT_0 + 1:                           // Process messages.
           begin
             If PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
             Case Msg.Message of
                WM_QUIT:                                // Press close [x].
                begin
                  PostQuitMessage(0);
                  Exit;
                end;
                WM_WAIT_STOP: Exit;
                else begin
                  TranslateMessage(Msg);
                  DispatchMessage(Msg);
                end
             end;
           end;

. . . . .

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
 If WakeUp.RunTimer(DateTimePicker1.Time, OpenDialog1.FileName) then
 begin
    MessageBox(0, PCHAR(" Дождались! ;)"), "!", MB_OK or MB_ICONINFORMATION)
   // RaiseLastOSError;

 end;

procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
  PostMessage(Handle, WM_WAIT_STOP, 0, 0);
end;



При нажатии SpeedButton3, будильник не вызывается,
но и не показывается MessageBox, говорящий о завершении ожидания.
Почему?


 
Б   (2010-04-20 14:02) [39]

Поправка: Не WM_WAIT_STOP, а WM_NULL.


 
Б   (2010-04-20 14:12) [40]

Решил.
Надо было при ловле WM_NULL возвращать ещё и Result = True.



Страницы: 1 2 вся ветка

Текущий архив: 2010.08.27;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.184 c
15-1264835850
TUser
2010-01-30 10:17
2010.08.27
"экономика"


15-1268248494
кот
2010-03-10 22:14
2010.08.27
как прочитать ПЗУ через параллельный порт


15-1267270379
Kerk
2010-02-27 14:32
2010.08.27
Про работу


3-1243871707
Trifle
2009-06-01 19:55
2010.08.27
forced writes on/off


2-1270990762
nikih22
2010-04-11 16:59
2010.08.27
Получить набор байтов с 48 ПИКСЕЛЕЙ