本次专门研究下 SetWaitableTimer 的第二个参数(起始时间).
它有正值、负值、0值三种情况, 前面已用过 0值.
先学习负值(相对时间), 也就是从当前算起隔多长时间开始执行.
这个相对时间是以 1/100 纳秒为单位的, 譬如赋值 3*10000000 相当于 3 秒.
1 s(秒) = 1,000 ms(毫秒); 1 s(秒) = 1,000,000 µs(微妙); 1 s(秒) = 1,000,000,000 ns(纳秒); 1 s(秒) = 1,000,000,000,000 ps(皮秒);
本例效果图:

代码文件:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} var f: Integer; hWaitableTimer: THandle; function MyThreadFun(p: Pointer): DWORD; stdcall; var i,y: Integer; begin Inc(f); y := 20 * f; if WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 then begin for i := 0 to 1000 do begin Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock; Sleep(1); end; end; Result := 0; end; procedure TForm1.Button1Click(Sender: TObject); var ThreadID: DWORD; DueTime: Int64; begin hWaitableTimer := CreateWaitableTimer(nil, True, nil); DueTime := -3*10000000; {3秒钟后执行} SetWaitableTimer(hWaitableTimer, DueTime, 0, nil, nil, False); Repaint; f := 0; CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); end; procedure TForm1.FormDestroy(Sender: TObject); begin CloseHandle(hWaitableTimer); end; end.
窗体文件:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 116 ClientWidth = 179 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 96 Top = 83 Width = 75 Height = 25 Caption = 'Button1' TabOrder = 0 OnClick = Button1Click end end
当我们需要一个绝对时间时, 譬如 2009-2-18 13:10:5, 函数需要的 Int64 值应该是个 TFileTime 格式的时间.
先看三种相关时间类型(TFileTime、TSystemTime、TDateTime)的定义:
TFileTime(又名 FILETIME 或 _FILETIME) _FILETIME = record dwLowDateTime: DWORD; dwHighDateTime: DWORD; end; TSystemTime(又名 SYSTEMTIME 或 _SYSTEMTIME) _SYSTEMTIME = record wYear: Word; wMonth: Word; wDayOfWeek: Word; wDay: Word; wHour: Word; wMinute: Word; wSecond: Word; wMilliseconds: Word; end; TDateTime = type Double; //TFileTime 相当于一个 Int64, 一般要通过给 TSystemTime 或 TDateTime 赋值, 然后转换过去. //在例子中我是通过下面过程转过去的: StrToDateTime -> DateTimeToSystemTime -> SystemTimeToFileTime -> LocalFileTimeToFileTime
下面程序指定在 2009年2月18号下午1点10分5秒时运行三个线程(窗体同上, 我已找了个合适的时间测试成功).
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} var f: Integer; hWaitableTimer: THandle; function MyThreadFun(p: Pointer): DWORD; stdcall; var i,y: Integer; begin Inc(f); y := 20 * f; if WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 then begin for i := 0 to 1000 do begin Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock; Sleep(1); end; end; Result := 0; end; procedure TForm1.Button1Click(Sender: TObject); const strTime = '2009-2-18 13:10:5'; var ThreadID: DWORD; DueTime: Int64; st: TSystemTime; ft,UTC: TFileTime; dt: TDateTime; begin DateTimeToSystemTime(StrToDateTime(strTime), st); {从 TDateTime 到 TSystemTime} SystemTimeToFileTime(st, ft); {从 TSystemTime 到 TFileTime} LocalFileTimeToFileTime(ft, UTC); {从本地时间到国际标准时间 UTC} DueTime := Int64(UTC); {函数需要的是 Int64} hWaitableTimer := CreateWaitableTimer(nil, True, nil); SetWaitableTimer(hWaitableTimer, DueTime, 0, nil, nil, False); Repaint; f := 0; CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); end; procedure TForm1.FormDestroy(Sender: TObject); begin CloseHandle(hWaitableTimer); end; end.
接下来该是 WaitableTimer 对象的回调函数了.
分类:
Delphi 与 多线程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2008-02-16 Delphi 的绘图功能[5] - 获取 Canvas 对象
2008-02-16 Delphi 的绘图功能[4] - 圆弧类图形
2008-02-16 Delphi 的绘图功能[3] - 矩形类图形
2008-02-16 Delphi 的绘图功能[2] - 入门
2008-02-16 Delphi 的绘图功能[1] - TCanvas 的类成员
2008-02-16 Graphics 单元中的类
2008-02-16 WinAPI: SetTimer、KillTimer - 创建与移除高性能定时器