Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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.039 c
1-1117542941
Леха
2005-05-31 16:35
2005.06.14
Присвоение значений Edit через цикл


3-1115179948
IBNovice
2005-05-04 08:12
2005.06.14
Помогите с запросом


1-1116821409
jcrush
2005-05-23 08:10
2005.06.14
Создание динамических обьектов и работа с ними, определить имена


4-1114423278
CrazyCrazyMax
2005-04-25 14:01
2005.06.14
шрифты в Windows


11-1099777588
Sewix
2004-11-07 00:46
2005.06.14
Какое событие изменение ширины столбцов в TKOLListView





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский