关于定时器回调函数的问题

骑猪听涛 2013-01-31 01:17:25
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个,不会造成栈的不平衡?

各位大神,能帮忙给个解释不?
...全文
983 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
simonhehe 2013-01-31
  • 打赏
  • 举报
回复
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.
静_海 2013-01-31
  • 打赏
  • 举报
回复
楼主真是有心人,一个很有意思的问题。按理说,堆栈错位,Windows 函数应该弹出一个错误返回地址。我也说不清,只能猜一下。大概是由于 Windows 程序是时钟事件启动的,不是由应用程序调用,而且这段程序特简单,从回调函数返回后就不再做什么,所以没引起严重后果。假如是由应用程序调用,也许问题就大了。
骑猪听涛 2013-01-31
  • 打赏
  • 举报
回复
哪位高人给指点一下哦

1,184

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧