Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вызов функции по таймеру, Вызов функции(процедуры) по SetTimer 
V
    Опции темы
Lexicss
Дата 26.5.2007, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 16.8.2006
Где: Беларусь, Минск

Репутация: нет
Всего: 1



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

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;


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

--------------------
Бери от жизни всё.
PM MAIL WWW ICQ Skype   Вверх
Palladin
Дата 26.5.2007, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 932
Регистрация: 15.5.2007
Где: Беларусь г.Гомель

Репутация: 3
Всего: 17



Короче первое что пришло на ум то и пишу, вообще заводиш глобальную переменную к примеру x типа integer, и там же присваеваеш её начальное значение 0, после этого в условие таймера пишеш 
Код

if x=0 then 
 begin 
   SetTimer(0,0,5000,@MyFunc); 
   x:=x+1;
 end;


Покатит smile

Добавлено через 25 секунд
Тогда будет выполнятся лиш один разsmile

Добавлено через 1 минуту и 22 секунды
Так же я не вижу весь код, да и задачи твоей команды, но принцип тот же

Добавлено через 1 минуту и 53 секунды
Отпиши получилось или нетsmile


--------------------
Глуп тот кто полагается на истину авторитета, а не на авторитет истины
[color=red]KAV&KIS==Evil[/color]
PM MAIL   Вверх
Lexicss
Дата 26.5.2007, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 16.8.2006
Где: Беларусь, Минск

Репутация: нет
Всего: 1



Ну логика решения проблемы понятна, но всё же мне очень важно узнать почему функция вызывается дважды мгновенно(притом ещё и вылетаю в исключение). Это ж ведь ненормально.
А весь код и не нужен, он на самом деле громоздкий, а сама суть здесь изложена в этом коде, здесь такая же ситуация получается. 
Могу весь код выложить этой ситуации, дабы можно было его скопировать и проверить у себя.
Код

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.


--------------------
Бери от жизни всё.
PM MAIL WWW ICQ Skype   Вверх
Alexeis
Дата 26.5.2007, 01:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 109
Всего: 459



А чем компонент TTimer не угодил?


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Palladin
Дата 26.5.2007, 01:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 932
Регистрация: 15.5.2007
Где: Беларусь г.Гомель

Репутация: 3
Всего: 17



Хм, ну почему эт конечно хороший вопрос, ответа на него у мя нет, может быть функция settimer юзает какието функции Windows а в XP они несколько отличны от одноименной в 98 и др.
вообщем ответа у меня нет, решение есть и я его тееб отписалsmile

Добавлено через 1 минуту и 40 секунд
Да-да Алексей прав, юзай таймер в конце enabled в false да и все, но впринципе это лиш альтернатива моего метода, хотя скорее наоборотsmile


--------------------
Глуп тот кто полагается на истину авторитета, а не на авторитет истины
[color=red]KAV&KIS==Evil[/color]
PM MAIL   Вверх
Alexeis
Дата 26.5.2007, 01:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 109
Всего: 459



Цитата(Lexicss @  26.5.2007,  00:40 Найти цитируемый пост)
Ещё одна особенность, если процедуру MyFunc вызывать с соглашение stdcall, то тоже всё нормально. 

  Конечно все калбэк функции по дефлоту должны быть stdcall.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Lexicss
Дата 26.5.2007, 01:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 16.8.2006
Где: Беларусь, Минск

Репутация: нет
Всего: 1



Цитата
А чем компонент TTimer не угодил? 

Дело в том что программу писал не я, я дорабатываю, следует оставлять всё так как было задумано разработчиком. Притом в 98-ой всегда всё было нормально, а как перешли на 2000-ую вот такая хрень вылезла. 
Цитата
Конечно все калбэк функции по дефлоту должны быть stdcall. 

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

Я, наверное, задаю слишком много вопросов. Просто моей задачей стоит не  решить конкретную ситуацию і забыть о ней, а именно разобраться почему так получается. Возможно, разобравшись в этом  я(да и не тока я) смогу решить и другие проблемы, где есть такое же, но жучки ещё не дали о себе знать.
Но всё равно спасибо за советы. Если кто-то что-то ещё знает об этом, пишите.

Поделюсь ещё своими наблюдениями.
Если изменить код, подавать в MyFunc не 4, а 3(например) параметра, то тогда всё нормально, работает без всяких повторных вызовов и исключений, и stdcall не нужен. Разбирая эти две ситуации в ассемблерном коде обнаружил - (в 4-х параметровой smile ) стэк как бы смещён на 4 байта, и когда вызывается команда ret(выход из MyFunc), то берётся из него не тот адрес, а как раз попадается ячейка с адресом начала этой функции(поэтому она и запускается снова), в 3-х параметровой - всё нормально, при вызове ret извлекается совершенно другой "некий" адрес и программа продолжает свою нормальную работу. Т.е. такое чувство, что при генерации машинного кода в 4-х параметровой функции пропущена одна команда push.

Это сообщение отредактировал(а) Lexicss - 26.5.2007, 01:48
--------------------
Бери от жизни всё.
PM MAIL WWW ICQ Skype   Вверх
MetalFan
Дата 26.5.2007, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



а зачем извраты такие? 
все системные callback-функции, как уже говорилось, должны быть с директивой stdcall.

Цитата(Lexicss @  26.5.2007,  01:46 Найти цитируемый пост)
почему в 98-ой всё работает нормально без stdcall

наверняка это просто случайность.

выскажу свои аргументы... 
вот выдержки из хелпа:
Цитата(DelphiHelp)


  • The register and pascal conventions pass parameters from left to right; that is, the left most parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last. The cdecl, stdcall, and safecall conventions pass parameters from right to left.

  • The register convention uses up to three CPU registers to pass parameters, while the other conventions pass all parameters on the stack.


The default register convention is the most efficient, since it usually avoids creation of a stack frame. (Access methods for published properties must use register.) The cdecl convention is useful when you call functions from shared libraries written in C or C++, while stdcall and safecall are recommended, in general, for calls to external code. On Windows, the operating system APIs are stdcall and safecall. Other operating systems generally use cdecl. (Note that stdcall is more efficient than cdecl.)

из чего делаем следующие выводы:
по умолчанию в делфи используется способ передачи до трех параметров через регистры процессора (директива register). параметры передаются слева направо.
в системе по умолчанию используется способ передачи, при котором параметры передаются через стэк, порядок параметров справа налево.
соотв. при обозначении в твоей функции трех параметров и без указания stdcall. внутрь попадает абсолютно ничего не значащие значения регистров. а если указано 4 параметра, то последний извлекается из стэка... чем его видимо и рушит...


Это сообщение отредактировал(а) MetalFan - 26.5.2007, 09:18


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Lexicss
Дата 27.5.2007, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 16.8.2006
Где: Беларусь, Минск

Репутация: нет
Всего: 1



MetalFan, спасибо. 
Вопрос почти решён. Остатётся только непонятка, почему работает в 98-ой без stdcall???  smile 
Притом программа работает уже давно(более 5 лет).
--------------------
Бери от жизни всё.
PM MAIL WWW ICQ Skype   Вверх
Yanis
Дата 27.5.2007, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2937
Регистрация: 9.2.2004
Где: Москва

Репутация: 72
Всего: 111



Цитата(Lexicss @  27.5.2007,  11:15 Найти цитируемый пост)
Остатётся только непонятка, почему работает в 98-ой без stdcall???

Это так же как и с 98-м -- куча кода, но почему он работает непонятно smile 


--------------------
user posted image *щёлк*
PM MAIL WWW ICQ   Вверх
Lexicss
Дата 28.5.2007, 22:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 16.8.2006
Где: Беларусь, Минск

Репутация: нет
Всего: 1



Как я понял из вышеизложенных постов: Моя процедура MyFunc является callback API-шной и следовательно нуждается в директиве  stdcall. Если я понял что-то не так - поправьте, пожалуйста. 
Но всё же остаётся открытым вопрос, почему в Windows 98 эта функция работатет нормально без stdcall, хоть в ней и больше 3-х параметров? Может ещё какие будут варианты объяснения кроме случайности? Если кто что толкового подскажет, буду признателен. ;)
--------------------
Бери от жизни всё.
PM MAIL WWW ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0564 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.