Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вызов функции по таймеру [D5, Win95/98, WinXP]


lexicss ©   (2007-05-29 11:01:00) 

Привет, народ! Вот тут упёрся в одну проблемку, может вы поможете разобрать и решить.
Работаю на Delphi 5 и вот наткнулся на такую ситуацию. Есть у меня одна функция и мне её надо вызвать спустя какой-то интервал времени, делаю это с помощью SetTimer. В чём странность? Так вот: в 98-ой винде работает всё нормально. В XP функция таймера срабатывает дважды, а в 2000-ой мало того что срабатывает функция дважды, так после второго завершения программа вылетает с исключением "Access violation", притом не важно что выполняется в функции(процедуре) вызываемой по таймеру.
Приведу приметивнейший пример


unit Main;
interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;
var
 Form1: TForm1;
procedure MyFunc(hWnd: THandle; uMsg: DWord; idEvent: DWord; dwTime: DWord);
implementation
{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
 SetTimer(0,0,5000,@MyFunc);
end;
procedure MyFunc(hWnd: THandle; uMsg: DWord; idEvent: DWord; dwTime: DWord);
begin
 if dwTime = 0
 then beep;
end;
end.

Проведя некоторые исследования, я заметил такую особенность, если число параметров в вызываемой функции не превышает 3, то такой ситуации не возникает(из ассемблерного кода видно, что если в функции большех трёх параметров, то 4-ый и последующие уже передаются не через регистры, а через стэк). Ещё одна особенность, если процедуру MyFunc вызывать с соглашение stdcall, то тоже всё нормально.
Очень важно узнать почему так? Может здесь какая-то несовместимость Delphi 5 и Windows 2000(и выше)?
И как тогда выкручиваться при использовании SetTimer в Delphi 5, так как программа должна быть универсальной и работать как под 98-ой, как под 2000-ой и др одинаково?

Как я понял : Моя процедура MyFunc является callback API-шной и следовательно нуждается в директиве stdcall. Если я понял что-то не так - поправьте, пожалуйста.
Но всё же остаётся открытым вопрос, почему в Windows 98 эта функция работатет нормально без stdcall, хоть в ней и больше 3-х параметров? Может ещё какие будут варианты объяснения кроме случайности? Если кто что толкового подскажет, буду признателен.


lexicss   (2007-05-30 14:04:00) [1]

Вот тока всё же странно чего стэк не рушется в 98-ой и работает нормально без stdcall?
Спасибо, народ. Вы мне помогли.


VPBar   (2007-05-29 11:18:00) [2]

//Очень важно узнать почему так?
Если параметров меньше 3 то функция передает мусор в регистрах но не портит стэк. Если больше 3 то портит стек и из-за этого вылетает ошибка (адрес возврата на стеке ведь тоже хранится, и может быть запорчен).
// Может здесь какая-то несовместимость Delphi 5 и Windows 2000(и выше)?
Никаких несовместимостей.
//И как тогда выкручиваться
Не надо выкручиваться делай правильно - ставь нужное соглашение о вызове (stdcall в данном случае)


MBo   (2007-05-29 11:10:00) [3]

>Очень важно узнать почему так?
Потому, что таймерная функция должна точно соответствовать прототипу по числу и типам параметров, и соглашение о вызове для этого прототипа именно stdcall. Так что незачем искать приключений...


Сергей М.   (2007-05-29 11:09:00) [4]


> Моя процедура MyFunc является callback API-шной и следовательно
> нуждается в директиве stdcall


Да, нуждается.


> почему в Windows 98 эта функция работатет нормально


Просто тебе повезло.


Наверх

Титульная страница Поиск, карта сайта Написать письмо