Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.03.12;
Скачать: [xml.tar.bz2];

Вниз

TimerProc дважды   Найти похожие ветки 

 
Дубинка   (2006-02-24 15:18) [0]

Глупый наверное вопрос. Я создаю таймер:
id := SetTimer(0, 0, 1000, @TimerProc);

Однако эта процедура:
procedure TimerProc(wnd: HWND; uMsg: Integer; idEvent: Integer; dwTime: DWORD);
begin
{.....}
end;
вызывается через каждую секунду два раза подряд. причем в первом случае
idEvent = 0, а во втором wnd = 0, мне интересно, как от этого избавиться...
Вроде бы надо Dispatch"ить сообщение, только не знаю как это сделать.


 
umbra ©   (2006-02-24 15:24) [1]

при вызове SetTimer в первом параметре стоит указывать окно, к которому таймер относится
id := SetTimer(hwnd, 0, 1000, @TimerProc);


 
Дубинка   (2006-02-24 15:27) [2]

бывает так что нет окна. К примеру, если функция вызывается из dll смысл в создании окла не то что нулевой, а вообще отрицательный. Да и в справке указано:
hWnd [in] Handle to the window to be associated with the timer. This window must be owned by the calling thread. If this parameter is NULL, no window is associated with the timer and the nIDEvent parameter is ignored.
То бишь может быть нулем.


 
umbra ©   (2006-02-24 15:50) [3]

так не надо ничего создавать. Из ДЛЛ функцию вызывает какое-то приложение, у которого есть окно. Вот его hwnd и надо передавать в SetTimer. Процесс диспетчеризации сообщения WM_TIMER и заключается в том, что указывается хендл окна, которому это сообщение нужно.


 
Дубинка   (2006-02-24 17:04) [4]

ладно, указал я хэндл какого-то окна, все равно два раза вызывается.


 
begin...end ©   (2006-02-24 17:06) [5]

> Дубинка   (24.02.06 15:18)

> вызывается через каждую секунду два раза подряд.

Полный код можно увидеть?

> в первом случае
> idEvent = 0, а во втором wnd = 0


На параметры можно пока не обращать внимание, т.к. у TimerProc не указано нужное соглашение о вызове (stdcall). Исправьте.

> Вроде бы надо Dispatch"ить сообщение, только не знаю как
> это сделать.


А в каком потоке таймер устанавливается? В главном потоке-то цикл выборки сообщений обычно уже есть :)

Вообще, если таймер создаётся без указания окна, то при "срабатывании" таймера происходит следующее:

1. В очередь потока, создавшего таймер, ставится сообщение WM_TIMER.
2. Если в потоке работает цикл выборки сообщений (GetMessage), и в этом цикле вызывается DispatchMessage, это сообщение выбирается из очереди и передаётся в DefWindowProc.
3. DefWindowProc вызывает указанную при создании таймера callback-функцию.

Т.е. разница между созданием таймера с указанием окна и без оного -- в том, что в первом случае WM_TIMER будет приходить в оконную процедуру указанного окна, а во втором случае -- в дефолтную оконную процедуру. И в обоих случаях, конечно, нужен цикл диспетчеризации сообщений.


 
Дубинка   (2006-02-24 17:23) [6]

На параметры можно пока не обращать внимание, т.к. у TimerProc не указано нужное соглашение о вызове (stdcall). Исправьте.

Точно! А я даже и не обратил внимания. Не будете любезны объяснить мне? Я кажется отдаленно понимаю. Вроде по умолчанию стоит register, и параметры передаются слева направо, а должны наоборот. Только почему из-за этого функция дважды вызывается?


 
Дубинка   (2006-02-24 17:25) [7]

Если оставить значимую часть в коде, остается это:

library gccore;

uses SysUtils, Windows;

var i: Integer;

procedure TimerProc(wnd: HWND; uMsg, idEvent: Integer; dwTime: DWORD);stdcall
begin
 Inc(i);
 TextOut(GetDC(0), 0,0, Pchar(inttostr(i)), 3);
end;

begin
 SetTimer(0, 0, 1000, @TimerProc);
end.

И где здесь должен быть цикл обработки сообщений?


 
umbra ©   (2006-02-24 17:51) [8]


> И где здесь должен быть цикл обработки сообщений?
>


в приведенном Вами коде - нигде. библиотека не работает сама по себе. ее использует какое-то приложение.


 
begin...end ©   (2006-02-24 17:59) [9]

> Дубинка   (24.02.06 17:23) [6]

Да, по умолчанию стоит register. Это означает, что перед вызовом подпрограммы первые три параметра передаются через регистры процессора, а оставшиеся -- через стек (причём вначале в стек помещается самый "левый" из оставшихся параметров, затем -- следующий, и т.д.). Это соглашение означает также и то, что подпрограмма сама должна удалять из стека переданные ей параметры.

А если указано stdcall, то ВСЕ параметры передаются через стек (причём справа налево: сначала последний, потом предпоследий, и т.д.). И в этом случае тоже за очистку стека отвечает сама подпрограмма.

Система, рассчитывая на то, что функция объявлена с соглашением stdcall, перед вызовом TimerProc передаёт все четыре параметра через стек, и надеется, что он будет правильно очищен вызываемой процедурой. Но TimerProc была объявлена с соглашением register, и она удалит из стека только один параметр, т.к. её код сгенерирован в расчёте на то, что первые три параметра ей переданы через регистры. В результате стек балансируется неправильно, а это может повлечь за собой самые разнообразные чудеса.

> Дубинка   (24.02.06 17:25) [7]

Здесь -- не нужен. Цикл уже есть (в том потоке, в контексте которого вызывается SetTimer), иначе вызова TimerProc не происходило бы.


 
umbra ©   (2006-02-24 18:41) [10]

по логике, если TimerProc вызывается дважды, значит на сообщение WM_TIMER реагируют дважды. Один раз реагирует сам сама TimerProc, а второй - какая-то оконная процедура.


 
begin...end ©   (2006-02-24 20:23) [11]

Сорри, насчёт DefWindowProc в [5] -- эт я фигню какую-то сморозил. Меня чего-то MSDN с толку сбила: "When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER". DefWindowProc, вроде, ни при чём -- callback вызывает сама DispatchMessage.

Уж простите дурака :)


 
Дубинка   (2006-02-24 20:27) [12]

Все. Мне все понятно. Благодарю!



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

Форум: "Начинающим";
Текущий архив: 2006.03.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.48 MB
Время: 0.02 c
8-1126694605
Kair+
2005-09-14 14:43
2006.03.12
Захват видео с помощью DSPack


1-1139233538
parovoZZ
2006-02-06 16:45
2006.03.12
Файл во временную папку


1-1138970225
ORMADA
2006-02-03 15:37
2006.03.12
Pascal Script (Rem Object)


15-1139897064
parovoZZ
2006-02-14 09:04
2006.03.12
GPRS и PPP - протокол


4-1135118283
Delphi_is_cool
2005-12-21 01:38
2006.03.12
Как добавить строку





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский