关于定时器回调函数的问题
delphi 设定一个定时器的函数如下:
function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: TFNTimerProc): UINT; stdcall;
其中回调函数的类型为TFNTimerProc,其实就是一个Pointer类型.
Windows api对于这个回调函数的类型是:
VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT_TR idEvent,DWORD dwTime);
所以传递一个符合这样类型的过程是没有问题的,如:
Procedure TimeProc(Wnd:HWND;MsgId:longint;TimerId:LongInt;DwTime:Longint);
begin
Form1.Memo1.Lines.Add(IntToStr(TimerHandle));
KillTimer(0,TimerHandle);
end;
TimerHandle:=SetTimer(0,0,1000,@TimeProc);
这样肯定是可以正确运行的
令我不解的是,我传递一个不符合该调用惯例的过程,也一样可以执行;虽然delphi的Settimer回调过程类型是一个Pointer类型,按照字面的理解,你可以传递任意类型的方法指针,但windows调用你这个回调函数总得符合定时器的惯例,才能正确执行的吧,但我试着传递一个不符合惯例的函数给他,
如以下:
Procedure TimeProc2(aParamer:Integer);Stdcall;
var
i:integer;
begin
i:=10+20;
Form1.Memo1.Lines.Add(IntToStr(i));
end;
TimerHandle:=SetTimer(0,0,1000,@TimeProc2);
这样设置以后,也能正确执行,并没有报错,只是结果有点问题.我不明白Windows怎么执行的,不会报错?
windows调用时,应该依照惯例,压入栈4个参数,然后跳到该函数执行,该函数执行完后,要清栈,看了一下汇编码该函数的退出码是 ret $0004,只有一个参数,清4个字节,压4个,清1个,不会造成栈的不平衡?
各位大神,能帮忙给个解释不?
[解决办法]
楼主真是有心人,一个很有意思的问题。按理说,堆栈错位,Windows 函数应该弹出一个错误返回地址。我也说不清,只能猜一下。大概是由于 Windows 程序是时钟事件启动的,不是由应用程序调用,而且这段程序特简单,从回调函数返回后就不再做什么,所以没引起严重后果。假如是由应用程序调用,也许问题就大了。
[解决办法]
SetTimer的函数原型如下
----------------------------------------------
C++
UINT_PTR WINAPI SetTimer(
_In_opt_ HWND hWnd,
_In_ UINT_PTR nIDEvent,
_In_ UINT uElapse,
_In_opt_ TIMERPROC lpTimerFunc
);
----------------------------------------------
TIMERPROC的函数原型如下
----------------------------------------------
C++
VOID CALLBACK TimerProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ UINT_PTR idEvent,
_In_ DWORD dwTime
);
----------------------------------------------
Delphi中SetTimer的回调函数式pointer类型的, 所以导致混乱
Delphi中SetTimer的第四个参数只要能转为pointer类型, 都会在设定的时钟内调用, 只要保证调用的东东内部不出错就行了.
SetTimer调用回调函数时, 提取回调函数的参数列表, 依次写入值后完成回调过程
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm11 = class(TForm)
btn1: TButton;
btn2: TButton;
tmr1: TTimer;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
{ Private declarations }
procedure TimerProc5(var Message: TWMTimer); message WM_TIMER;
public
{ Public declarations }
end;
var
Form11: TForm11;
i : integer = 0;
implementation
{$R *.dfm}
procedure TimerProc(hwnd:HWND;uMsg,idEvent:UINT;dwTime:DWORD); stdcall;
begin
inc(i);
Form11.Caption := IntToStr(i);
end;
procedure TimerProc2(hwnd:HWND;uMsg,idEvent:UINT);
begin
inc(i);
Form11.Caption := IntToStr(i);
end;
function TimerProc3 : Integer;
begin
Result := 0;
inc(i);
Form11.Caption := IntToStr(i);
end;
procedure TimerProc4(hwnd:HWND;uMsg,idEvent:UINT;dwTime:DWORD; iTest, iTest2 : Integer); stdcall;
begin
//iTest, iTest2的值无意义
inc(i);
Form11.Caption := IntToStr(i);
end;
procedure TForm11.TimerProc5(var Message: TWMTimer);
begin
inc(i);
Form11.Caption := IntToStr(i);
end;
procedure TForm11.btn1Click(Sender: TObject);
begin
// SetTimer(Handle,10,500,@TimerProc);
// SetTimer(Handle,10,500,@TimerProc2);
// SetTimer(Handle,10,500,@TimerProc3); //调用函数
// SetTimer(Handle,10,500,@TimerProc4);
SetTimer(Handle,10,500,nil); //调用TimerProc5
end;
procedure TForm11.btn2Click(Sender: TObject);
begin
KillTimer(Handle,10);
end;
end.