Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
ВнизНе срабатывает 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.
← →
Leonid Troyanovsky © (2010-04-20 14:24) [41]
> Б (20.04.10 14:01) [38]
> WM_QUIT: // Press close [x].
> begin
> PostQuitMessage(0);
> Exit;
Во-первых, WM_QUIT - это вовсе не "Press close [x]".
Во-вторых, PostQuitMessage посылает WM_QUIT.
В-третьих, ссылку, как надо я приводил 2 раза.
ТщательнЕй, надо, тщательнЕй.
--
Regards, LVT.
← →
Б (2010-04-20 14:29) [42]Кстати, на днях у меня сломалась мобила.
Поэтому пришлось воспользоваться этим будильником. ;)
← →
Б (2010-04-20 14:35) [43]
> Leonid Troyanovsky © (20.04.10 14:24) [41]
А ну правильно... там WM_CLOSE.
> В-третьих, ссылку, как надо я приводил 2 раза.
Тогда я не понимал, зачем вызывался PostMessage c WM_NULL.
Сейчас уже вроде вник. ;)
← →
Anatoly Podgoretsky © (2010-04-20 14:50) [44]> Б (20.04.2010 14:01:38) [38]
При нажатии SpeedButton3, никакой MessageBox не вызывается.
← →
Anatoly Podgoretsky © (2010-04-20 14:52) [45]> Б (20.04.2010 14:29:42) [42]
Что только не придумает русский программист, только бы не покупать будильник.
← →
Б (2010-04-20 15:09) [46]
> Anatoly Podgoretsky © (20.04.10 14:50) [44]
> При нажатии SpeedButton3, никакой MessageBox не вызывается.
Есть 2 кнопки OK и Cancel.
OK - это SpeedButton2. (Запускаем будильник)
Cancel - это SpeedButton3. (Посылаем сообщение об остановке будильника,
WakeUp.RunTimer завершиться и вызовится MsgBox)
> Что только не придумает русский программист, только бы не
> покупать будильник.
;)
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.093 c