Форум: "WinAPI";
Текущий архив: 2005.06.14;
Скачать: [xml.tar.bz2];
ВнизФункции SeTimer, KillTimer Найти похожие ветки
← →
ChtoMe (2005-04-21 17:48) [0]У меня проблема с работой функций SetTimer и KillTimer. Проблема в следующем: в моей программе нету формы поэтому код, который не работает слудующий:
program Project1;
uses
windows,messages,sysutils,dialogs;
var
temer,cont:integer;
{$R *.res}
procedure getting(hnd:HWND;uMsg:UINT;tem:UINT;tickt:DWORD);
begin
inc(cont);
inputbox("1","","");
if cont>5 then killtimer(0,temer); //если судить по //документации, то вместо temer можно использовать tem, но толку //от этого мало
end;
begin
cont:=0;
temer:=settimer(0,0,100,@getting);
inputbox(bla-bla-bla","","");
end.
По моей задумке должен вылезти inputbox 5 раз после чего таймер должен убиться функцией killtimer, но inputbox у меня вылазеет гораздо больше чем 5 раз. Короче программа зацикливается.
Подскажите, может я чё-то не так делаю? И если у кого есть пример как правильно работать с таймером без формы скажите где взять плиз или скиньте на jeon@inbox.ru
← →
alpet © (2005-04-21 18:08) [1]Второй Параметр должен быть не нулевой.
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.
← →
alpet © (2005-04-21 18:08) [2]Второй Параметр должен быть не нулевой.
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.
← →
Digitman © (2005-04-21 18:09) [3]ты, чудо, вообще-то титал описание ф-ции SetTimer в стандартной справке ?
← →
alpet © (2005-04-21 18:11) [4]+ про соглашение stdcall как всегда забыл.
В C++:
VOID CALLBACK TimerProc(HWND hwnd,
UINT uMsg,
UINT_PTR idEvent,
DWORD dwTime
);
В Delphi должно быть как:
procedure (hwnd, uMsg, nEvent, dwTime: DWORD); stdcall;
begin
end;
← →
alpet © (2005-04-21 18:13) [5]alpet © (21.04.05 18:08) [2]
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.
Вернее наоборот, нулевой когда hWnd = 0. Сам ошибся.
← →
alpet © (2005-04-21 18:15) [6]Если уж совсем точно - то без разницы какой, если не указано окно, но есть callback фукнция.
← →
KosilkA © (2005-04-21 18:17) [7]
>
> ChtoMe (21.04.05 17:48)
може так...
procedure getting(hnd:HWND;uMsg:UINT;tem:UINT;tickt:DWORD);
begin
KillTimer(temer); inc(cont);
inputbox("1","","");
if cont>5 then killtimer(0,temer) else
temer:=SetTimer(0,0,100,@getting);
end;
← →
alpet © (2005-04-21 18:19) [8]KosilkA © (21.04.05 18:17) [7]
Очень смешно :-). Только не будет работать.
← →
KosilkA © (2005-04-21 18:20) [9]да и вообще, чего париться, если в uses стоит dialogs то не грех и forms добавить и таймер с палитры кинуть, все равно на весе уже не сэкономишь =))))
← →
KosilkA © (2005-04-21 18:20) [10]
> alpet © (21.04.05 18:19) [8]
а ты пробовал? =))
← →
alpet © (2005-04-21 18:28) [11]KosilkA © (21.04.05 18:20) [10]
а ты пробовал? =))
нет, и дисскусию прекращаем. Всего что не хватает ChtoMe - умения пользоваться отладчиком. Управление ветке if count > 5 ни когда не передается из-за вызова модального диалога.
← →
ChtoMe (2005-04-21 18:35) [12]Спасибо, так работает, но некоторые моменты не понятны. Зачем добавлять stdcall? Чем функция с stdcall отличается от простой?
И вот ещё не ясно:(hwnd, uMsg, nEvent, dwTime: DWORD);?
А где же тут тип передаваемыхь переменных? Ваще не врублюсь...
← →
KosilkA © (2005-04-21 18:36) [13]
> alpet © (21.04.05 18:28) [11]
прям таки никогда?
← →
ChtoMe (2005-04-21 18:39) [14]Кстати насчёт if count>5 - это я внатуре тупанул, что сначала вызывал это с inputbox!!!
И что такое stdcall?
← →
KosilkA © (2005-04-21 18:39) [15]
> ChtoMe (21.04.05 18:35) [12]
> Спасибо, так работает, но некоторые моменты не понятны.
> Зачем добавлять stdcall? Чем функция с stdcall отличается
> от простой?
>
> И вот ещё не ясно:(hwnd, uMsg, nEvent, dwTime: DWORD);?
> А где же тут тип передаваемыхь переменных? Ваще не врублюсь...
ты лучше задайся вопросом, правильно ли то , что у тебя вместо того чтобы по очереди, программа выплевывает сразу пять диалогов, нафига тебе такое нужно?=))
← →
alpet © (2005-04-21 18:41) [16]Зачем добавлять stdcall? Чем функция с stdcall отличается от простой?
Параметры передаются в стеке обратном порядке по отношению к PASCAL, и не в регистрах как в register.
Directive Parameter order Clean-up Passes parameters in registers?
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No
А где же тут тип передаваемыхь переменных? Ваще не врублюсь
А DWORD что такое, или ты к каждой переменной тип прописываешь?
← →
alpet © (2005-04-21 18:44) [17]KosilkA © (21.04.05 18:36) [13]
прям таки никогда?
До тех пор пока пользователь не закроет хотя бы один диалог, они будут появляться... до переполнения стека или исчерпания ресурса hwnd. В любом случае логика в коде нарушена.
← →
ChtoMe (2005-04-21 18:45) [18]Ясно... Большое спасибо.
← →
KosilkA © (2005-04-21 18:56) [19]
> alpet © (21.04.05 18:44) [17]
> KosilkA © (21.04.05 18:36) [13]
>
> прям таки никогда?
>
> До тех пор пока пользователь не закроет хотя бы один диалог,
> они будут появляться... до переполнения стека или исчерпания
> ресурса hwnd. В любом случае логика в коде нарушена.
а попробовать не судьба прежде чем так безапеляционно? =))
← →
KosilkA © (2005-04-21 19:11) [20]... и вообще, чо тут за пурга??? зачем таймер тут нужен???? Штоб пять диалогов показать? А в цикле нельзя штоли? блин, пора домой
← →
ChroMe © (2005-04-21 19:17) [21]Ещё появилась одна проблема...
После вызова SetTimer работа программы останавливается так как после этой строчки стоит end. Короче таймер не успевает выполниться не разу. Что с этим можно поделать? Чтобы программа не закрывалась. Пробовал sleep(), но не помогло. Я слышал, что программу можно сделать процессом, но как не знаю или подскажите другой вариант. И как потом закрыть программу, которая будет висеть как процесс? Вот код, который у меня получился в итоге:
procedure getting(hwnd, uMsg, nEvent, dwTime: DWORD);stdcall;
var
s:string;
f:textfile;
begin
inc(cont);
if cont>5 then killtimer(0,temer);
assignfile(f,"c:\2.txt");
rewrite(f);
str(cont,s);
writeln(f,s);
closefile(f);
end;
begin
cont:=0;
temer:=settimer(0,0,100,@getting);
end.
← →
alpet © (2005-04-21 19:18) [22]KosilkA © (21.04.05 18:56) [19]
а попробовать не судьба прежде чем так безапеляционно? =))
Попробуй лучше этот код:while Random (1000000) > 0 do;
ShowMessage ("ok");
Его выполнение будет не гарантированным, но тем не менее очень интересным.
... и вообще, чо тут за пурга??? зачем таймер тут нужен???? Штоб пять диалогов показать? А в цикле нельзя штоли? блин, пора домой
Не в цикле не катит, надо чтобы диалоги появлялись без закрытия. Пора ТЗ.
← →
ChroMe © (2005-04-21 19:21) [23]Нет таймер нужен для другого, просто пробую на чём получиться, а потом вставлю код, который мне нужен.
← →
alpet © (2005-04-21 19:29) [24]2 ChtoMo
Вообще зачем ты таймер создаешь для таких целей? Прямой вызов в цикле чем хуже?
И как может работать таймер без единого открытого окна принимающего WM_TIMER ?
← →
alpet © (2005-04-21 19:32) [25]Если окно не хочешь создавать попробуй так
....
var msg: tagMsg;
begin
cont:=0;
temer:=settimer(0,0,100,@getting);
while (cont < 5) and GetMessage (msg, 0, 0, 0) do
DispatchMessage (msg);
end.
← →
KosilkA © (2005-04-22 10:30) [26]
> alpet © (21.04.05 19:18) [22]
> KosilkA © (21.04.05 18:56) [19]
> а попробовать не судьба прежде чем так безапеляционно? =))
>
> Попробуй лучше этот код:
> while Random (1000000) > 0 do;
> ShowMessage ("ok");
> Его выполнение будет не гарантированным, но тем не менее
> очень интересным.
и чем же интересно выполнение данного кода ? Random"ом? Да,я потрясён
← →
alpet © (2005-04-22 10:47) [27]>и чем же интересно выполнение данного кода ? Random"ом? Да,я потрясён
А ты попробывал ? Под отладчиком ?
Короче хватит оффтопа, я хотел сказать что бессмыссленный код и анализировать бессмысленно.
← →
KosilkA © (2005-04-22 10:57) [28]> бессмыссленный код и анализировать бессмысленно
бессмысленно охаивать то, чего так и не удосужился попробовать
← →
Alexander Panov © (2005-04-22 11:01) [29]Так что же все-таки автор топика хочет сделать?
Зачем таймер?
Бессмысленно давать советы непонятно для чего.
← →
alpet © (2005-04-22 11:32) [30]2 KosilkA
[11] - относилось к [1], и тут все верно.
в [7] - всего одна ошибка и не в логике, а тексте - пробывать этот код опять же бессмыслено, если и так ясно как он себя поведет.
Автору сабжа, видимо хочется научится работать с таймером, но он похоже пока плохо представляет как этот таймер организуется и вообще весь механизм сообщений Windows.
← →
KosilkA © (2005-04-22 11:51) [31]
> alpet © (22.04.05 11:32) [30]
учитывая , что ты пишешь слово пробЫвать с буквой Ы, я снимаю с себя ответственность в отсутствии нуля в вызове KillTimer :o)
← →
Piter © (2005-04-22 12:02) [32]Вопрос: как создать таймер средствами Win32Api
Ответ: нужно воспользоваться функцией SetTimer, описанной в Windows.pas следующим образом:function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: TFNTimerProc): UINT; stdcall;hWnd
- указатель на окно, куда будут посылаться сообщения WM_TIMER при очередной итерации таймераnIDEvent
- задает идентификатор таймера, не должен быть ноль. Игнорируется системой, если hWnd равно нулюuElapse
- время в миллисекундах между итерациями таймераlpTimerFunc
- указатель на процедеру TimepProc, которая должна являться callback функцией и которая будет вызываться системой при каждой итерации таймера
Видно, что существую два пути задания таймера - или задать окноhWnd
, куда будут посылаться сообщенияWM_TIMER
каждыеuElapse
миллисекунд, или задать указатель на процедуруlpTimerFunc
, которая будет вызываться системой каждыеuElapse
миллисекунд.
1) Рассмотрим первый вариант:procedure TForm1.Button1Click(Sender: TObject);
begin
if SetTimer(Handle, 1, 1000, nil)=0 then
ShowMessage("Не удалось создать таймер!");
end;
При успешном создании таймера, функцияSetTimer
вернет индентификатор таймера, который мы сами и задали - 1.
Если таймер создать не удалось - функция вернет ноль.
Если таймер создан, то экземпляру TForm1 каждые 1000 миллисекунд (1 секунду) будет посылаться сообщениеWM_TIMER
. Естественно, нужно это сообщение обрабатывать. УTForm1
объявить метод:TForm1 = class(TForm)
...
procedure WMTImer(var Msg: TMessage); message WM_TIMER;
...
И реализовать:procedure TForm1.WMTImer(var Msg: TMessage);
begin
beep;
end;
Каждую секунду будем издавать звуковой сигнал.
Чтобы удалить таймер, нужно вызвать функциюKillTimer
, передав ейHandle
окна и идентификатор таймера (которые указывали при создании таймера) .KillTimer(Handle, 1);
Стоит заметить, что если в очереди потока стоит хотя бы одно необработанное сообщение от таймера - то новое сообщение от таймера в очередь помещаться не будет. Мicrosoft, наверное, это сделал специально, чтобы исключить забиение очереди необработанными сообщениями какого-то не в меру шустрого таймера по отношению к обработчикам остальных сообщений
2) теперь рассмотрим второй варинт, на основе процедуры TimerProc. Вызов будет такой:idTimer := SetTimer(0, 0, 1000, @TimerProc);
if idTimer=0 then
ShowMessage("Не удалось создать таймер!");
В качестве указателя на окно пишем ноль, во второй параметр пишем что хотим (все равно игнорируется), третий - время итераций, четвертый - указатель на процедуруTimerProc
, которая будет вызываться системой каждые 1000 миллисекунд. Где-то должна быть объявлена и реализована эта процедураTimerProc
(получается, что это callback процедура, значит соглашение о вызове должно быть stdcall, не забывайте):procedure TimerProc(wnd: HWND; Msg: UINT; idEvent: UINT; Time: DWORD); stdcall;
begin
beep;
end;
Гдеwnd
- указатель на окно, которое передали функцииSetTimer
(в нашем случае ноль);Msg
- номер сообщения (оно будет равноWM_TIMER
);idEvent
- идентификатор таймера (тоже значение, которое вернетSetTimer
и которое записано вidTimer
);Time
- время в миллисекундах, которое прошло с момента загрузки Windows на момент генерации этого события таймера (данное значение эквивалентно тому, что возвращает функцияGetTickCount
).
Делает этот код тоже самое, что и первый пример - издает сигнал каждую секунду. При этом никакие передаваемые аргументы я не анализирую. Хотя, например, можно создать два таймера и назначить им одинаковуюTimerProc
. А различать вызовы от одного и другого таймеров по значениюidEvent
.
Значение, возвращаемое функциейSetTimer
сохраняется в какую-нибудь переменнуюidTimer: UINT
. Это нужно, чтобы потом можно было удалить таймер, так как во втором примере id таймера назначется системой.
Стоит отметить, что функцияTimerProc
вызывается системой в контексте того потока, который вызвал функциюSetTimer
для установки таймера. Причем вызовTimerProc
происходит неявно при вызове приложением функцииDispatchMessage
, поэтому если приложение не делает выборки и диспетчеризации сообщений - то вызоваSetTimer
не будет.
Чтобы удалить таймер, надо просто вызвать функию KillTimer, передав ей Handle окна (который указывали при создании таймера) и идентификатор таймера (которое вернула система).KillTimer(0, idTimer);
3) Есть еще и третий вариант - не указывать ни handle окна, ни процедуру TimerProc:idTimer := SetTimer(0, 0, 1000, nil);
Тогда система просто будет посылать сообщениеWM_Timer
в очередь потока, который вызвалSetTimer
.
В главном потоке отловить такое сообщение можно назначив обработку Application.OnMessage:...
Application.OnMessage := OnAppMessage;
...
procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_TIMER then
begin
beep;
Handled := True;
end;
end;
При этом какой бы цикл выборки сообщений в потоке не был - нельзя допускать вызоваDispatchMessage
, так как ведь у этого сообщения Handle=0, а значит оно не будет диспетчеризировано. Поэтому доApplication.OnMessage
это сообщение "доходит", а вот доApplication.DefaultHandler
не дойдет.
Файл проекта с данными примерами можно загрузить ЗДЕСЬ
Отвечали: Piter, Ihor Osov"yak
← →
ChroMe © (2005-04-23 00:42) [33]Ребят всем спасибо... Мне нужно именно наичиться работать с таймером, чтобы не занимать компонентом-таймером лишние килобайты в своей проге.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2005.06.14;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.04 c