![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
будильник на API [D7, WinXP]
Dmitry_177 © (2006-10-20 12:26:00)Хочу сделать будильник на API, используя функции CreateWaitableTimer и SystemTimeToFileTime. Т.к. в них нельзя задать определенное время, например в 18:00 чтобы прозвенел, нужно при установке таймера посчитать разницу между 18:00 и системным временем, и поставить этот интервал, чтобы через такой момент времени сработал будильник... Помогите пожалуйста с реализацией
const
HOUR = 18;
var
hTimer: THandle;
sysTime: TSystemTime;
...
hTimer := CreateWaitableTimer(nil, false, nil);
GetLocalTime(sysTime); // получили системное время
HOUR - sysTime.wHour; // как получить разницу? Подскажите пожалуйста...
SetWaitableTimer(hTimer, ..., 0, nil, nil, false);
Leonid Troyanovsky (2006-10-23 20:46:00) [21]
> Dmitry_177 (23.10.06 20:40) [18]
> Кстати мне тут подсказали вот такой код, интересно его
> лучше использовать или
А чего, очень даже прозрачно
> ft2.dwHighDateTime:=ft2.dwHighDateTime+201;
> ft2.dwLowDateTime:=ft2.dwLowDateTime+ 711573504;
Может в этом и есть сермяжная правда.
Вообще-то, после 4 дней обучения это ты нам должен докладывать,
как лучше работать с системным временем.
--
Regards, LVT.
Dmitry_177 (2006-10-23 20:40:00) [22]Просто я никогда не работал с системным временем на API... Думал что тут надо все делать в ручную, т.е. проверять день (не последний ли он в текущем месяце и году) и т.д. Кстати мне тут подсказали вот такой код, интересно его лучше использовать или нет?
var
sysTime: SYSTEMTIME;
ft2: FILETIME;
begin
{ TODO -oUser -cConsole Main : Insert code here }
GetLocalTime(sysTime);
if sysTime.wHour >= 18 then
begin
//sysTime.wDay := sysTime.wDay + 1;
SystemTimeToFileTime(sysTime,ft2);
ft2.dwHighDateTime:=ft2.dwHighDateTime+201;
ft2.dwLowDateTime:=ft2.dwLowDateTime+ 711573504;
FileTimeToSystemTime(ft2,sysTime);
end;
sysTime.wHour := 18;
sysTime.wMinute := 0;
sysTime.wSecond := 0;
end.
Leonid Troyanovsky (2006-10-23 18:55:00) [23]
> Dmitry_177 (22.10.06 18:55) [16]
> т.е. так?
Огласи, плиз, причины неуверенности.
Хотя, конечно, мне ближе >=.
--
Regards, LVT.
Dmitry_177 (2006-10-22 18:55:00) [24]т.е. так?
GetLocalTime(sysTime);
if sysTime.wHour > 18 then
sysTime.wDay := sysTime.wDay + 1;
sysTime.wHour := 18;
sysTime.wMinute := 0;
sysTime.wSecond := 0;
Leonid Troyanovsky (2006-10-22 18:28:00) [25]
> Dmitry_177 (22.10.06 18:15) [14]
> сегодня 18 часов уже было... Вот как прибавить к дате один
> день, с учетом того, что если день будет последним в текущем
> месяце, то 1-ый день будет следующего месяца, так же и с
> годом, если последний день года, т.е. 31 декабря...
DateX := Date + 1;
--
Regards, LVT.
Dmitry_177 (2006-10-22 18:15:00) [26]Спасибо, вы очень добры.. Если будет такая ситуация, ставим мы будильник на 18:00, а время будет уже больше 18:00, часов (19, 20, 21, 22, 23 например).. так вот день в sysTime, будет сегодняшний, а сработать таймер должен завтра, т.к. сегодня 18 часов уже было... Вот как прибавить к дате один день, с учетом того, что если день будет последним в текущем месяце, то 1-ый день будет следующего месяца, так же и с годом, если последний день года, т.е. 31 декабря...
GanibalLector (2006-10-22 13:31:00) [27]
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Exec: TButton;
procedure ExecClick(Sender: TObject);
private
procedure Success( var Msg:TMessage); message WM_USER+1;
{ Private declarations }
public
{ Public declarations }
end;
type
TMyMode = packed record
hTimer,
hMain:HWND;
end;
PMyMode = ^TMyMode;
var
Form1: TForm1;
implementation
{$R *.DFM}
function WaitThread(Param: PMyMode): DWord;
begin
WaitForSingleObject(Param.hTimer,INFINITE);
CloseHandle(Param.hTimer);
PostMessage(Param.hMain,WM_USER+1,0,0);
Dispose(Param);
Result:=0;
end;
procedure TForm1.ExecClick(Sender: TObject);
var sysTime: TSystemTime;
fTime: TFileTime;
ThreadID:DWord;
Obj:PMyMode;
begin
New(Obj);
Obj^.hTimer:=CreateWaitableTimer(nil, false, nil);
Obj^.hMain:=Handle;
//
GetLocalTime(sysTime);
sysTime.wHour := 12;
sysTime.wMinute := 31;
sysTime.wSecond := 0;
SystemTimeToFileTime(sysTime, fTime);
LocalFileTimeToFileTime(fTime, fTime);
SetWaitableTimer(Obj^.hTimer,TLargeInteger(fTime),0,nil,nil,False);
//
CloseHandle(BeginThread(nil, 0, @WaitThread, Obj, 0,ThreadID));
MessageBox(0, 'Time installed!', 'Time', MB_OK);
end;
procedure TForm1.Success(var Msg: TMessage);
begin // вот тут и обращайся в VCL-контролам, формам и т.д.
Windows.Beep(800,200);
ShowMessage('Timer');
end;
end.
Leonid Troyanovsky (2006-10-22 10:21:00) [28]
> Dmitry_177 (22.10.06 05:10) [11]
> А вот так правильно будет? оба хендла (hTimer и hThread)
> закрываю в функции
Для закрытия хендлов есть одно правило: закрывать их в тот
момент, когда они стали более не нужны. Запускаемому потоку
собственный хендл не требуется ( в случае нужды он может
использовать GetCurrentThread). Т.к. первичный поток далее
нигде не использует hThread, то правильное место для закрытия -
сразу после CreateThread.
Кроме того, необходимо помнить, что глобальные переменные - зло.
Поэтому, idThread стоило бы переместить в ButtonClick (она, все равно,
нигде более не используется). Переменную hTimer также стоит
сделать локальной, а в функцию потока передать как параметр
CreateThread (.., @WaitThread, Pointer(hTimer), ..).
Что касается закрытия хендлов при завершении приложения,
то здесь нет особых причин для беспокойства - они в любом случае
будут закрыты системой.
Хотя, если подобное происходит не с главной формой, то появляются
дополнительные трудности, для преодоления которых проще
воспользоваться классом TThread.
--
Regards, LVT.
Dmitry_177 (2006-10-22 05:10:00) [29]А вот так правильно будет? оба хендла (hTimer и hThread) закрываю в функции WaitThreadпосле WaitForSingleObject. А если выключить программу (нажав на крестик) до срабатывания таймера, удалятся эти хендлы или их лучше в событии разрушения формы их удалять?
var
hTimer: THandle;
hThread: THandle;
idThread: DWORD;
function WaitThread(Param: Pointer): DWORD; stdcall;
begin
WaitForSingleObject(hTimer, INFINITE);
CloseHandle(hTimer); -> Правильно ли тут будет удалять хендл hTimer?
CloseHandle(hThread); -> Правильно ли тут будет удалять хендл hThread?
MessageBox(0, 'Time!!!!!!!', 'Time', MB_OK);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
sysTime: TSystemTime;
fTime: TFileTime;
begin
hTimer := CreateWaitableTimer(nil, false, nil);
GetLocalTime(sysTime);
sysTime.wHour := 18;
sysTime.wMinute := 0;
sysTime.wSecond := 0;
SystemTimeToFileTime(sysTime, fTime);
LocalFileTimeToFileTime(fTime, fTime);
SetWaitableTimer(hTimer, TLargeInteger(fTime), 0, nil, nil, false);
hThread := CreateThread(nil, 0, @WaitThread, nil, 0, idThread);
MessageBox(0, 'Time installed!', 'Time', MB_OK);
end;
Leonid Troyanovsky (2006-10-21 17:21:00) [30]
> Dmitry_177 (21.10.06 17:00) [7]
> Посмотрите пожалуйста код, правильно ли он реализован? Вроде
> все работает, но правильно ли я закрываю хендл hTimer, а
> когда закрывать хендл hThread не знаю...
Когда hTimer стал не нужен, тогда и закрывай.
Например, после WaitForSingleObject, т.е. в коде потока.
Аналогично - hThread, например, на месте ошибочного
CloseHandle(hTimer).
Кста, win32 функции исключений не генерируют, см. Win32Check.
Вообще-то, функция потока - это, все же, функция:
function WaitThread(p: Pointer): DWORD; stdcall;
И использовать там такие вещи, как ShowMessage - заказано.
Если уж приспичило - MessageBox.
--
Regards, LVT.
GanibalLector (2006-10-21 17:15:00) [31]
var
hTimer: THandle;
hThread: THandle;
sysTime: TSystemTime;
fTime: TFileTime;
idThread: DWORD;
Я гляжу ты любитель глобальных переменных ;)
GanibalLector (2006-10-21 17:13:00) [32]>когда закрывать хендл hThread
А сразу и закрывай...накой он тебе???
CloseHandle( CreateThread(nil, 0, @WaitThread, nil, 0, idThread));
> правильно ли я закрываю хендл hTimer
Хм...вопрос конечно интересный ;) Знаешь ли,есть только ОДНА ф-ция позволяющая закрывать обьекты ядра CloseHandle.
Далее...когда ее закрывать - это уже дело твое. Но,ОДНОЗНАЧНО не раньше, чем WaitForSingleObject.
Dmitry_177 (2006-10-21 17:00:00) [33]Посмотрите пожалуйста код, правильно ли он реализован? Вроде все работает, но правильно ли я закрываю хендл hTimer, а когда закрывать хендл hThread не знаю... Подскажите пожалуйста...
var
hTimer: THandle;
hThread: THandle;
sysTime: TSystemTime;
fTime: TFileTime;
idThread: DWORD;
procedure WaitThread; stdcall;
begin
WaitForSingleObject(hTimer, INFINITE);
ShowMessage('Time!!!!!!!');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
hTimer := CreateWaitableTimer(nil, false, nil);
try
GetLocalTime(sysTime);
sysTime.wHour := 18;
sysTime.wMinute := 0;
sysTime.wSecond := 0;
SystemTimeToFileTime(sysTime, fTime);
LocalFileTimeToFileTime(fTime, fTime);
SetWaitableTimer(hTimer, TLargeInteger(fTime), 0, nil, nil, false);
hThread := CreateThread(nil, 0, @WaitThread, nil, 0, idThread);
ShowMessage('Time installed!');
finally
CloseHandle(hTimer);
end;
end;
Leonid Troyanovsky (2006-10-21 12:07:00) [34]
> Dmitry_177 (20.10.06 16:10) [5]
> а вот так нельзя сделать?
> sysTime.wHour := 18;
У SystemTime есть еще и wYear & etc.
> SystemTimeToFileTime(sysTime, fTime);
+
LocalFileTimeToFileTime(fTime, fTime);
> толи callback функция должна быть, толи поток создать толи
> еще что?
Поток, конечно, д.б.
Например, он может WaitForSingleObject(hTimer, INFINITE)
--
Regards, LVT.
Dmitry_177 (2006-10-20 16:10:00) [35]а вот так нельзя сделать?
var
hTimer: THandle;
sysTime: TSystemTime;
begin
hTimer := CreateWaitableTimer(nil, false, nil);
sysTime.wHour := 18;
sysTime.wMinute := 0;
sysTime.wSecond := 0;
SystemTimeToFileTime(sysTime, fTime);
SetWaitableTimer(hTimer, fTime, 0, nil, nil, false);
end;
только если честно не очень понятно как он должен сработать? толи callback функция должна быть, толи поток создать толи еще что?
Leonid Troyanovsky (2006-10-20 14:33:00) [36]
> Dmitry_177 (20.10.06 13:50) [2]
> А как его задать? что-то мне не очень понятно...
var
st: TSystemTime;
ft: TFileTime;
h: THandle;
..
DateTimeToSystemTime(Now, st);
st.wHour := ..;
SystemTimeToFileTime(st, ft);
LocalFileTimeToFileTime(ft, ft);
h := CreateWaitableTimer(nil, True, nil);
win32Check(SetWaitableTimer(h, Int64(ft), 0, ..));
--
Regards, LVT.
Sapersky (2006-10-20 14:18:00) [37]Сам же написал: SystemTimeToFileTime
Dmitry_177 (2006-10-20 13:50:00) [38]А как его задать? что-то мне не очень понятно...
Sapersky (2006-10-20 12:56:00) [39]Из справки по SetWaitableTimer, параметр pDueTime:
Positive values indicate absolute time. Negative values indicate relative time.
Т.е. определённое время задать можно.