根據 WaitableTimer 的主要功用, 現在再把它放在 "線程同步" 的話題中討論有點不合適了, 就要結束它.
//重新看看那個 APC 回調函數的格式:
procedure TimerAPCProc(
lpArgToCompletionRoutine: Pointer;
dwTimerLowValue, dwTimerHighValue: DWord
); stdcall;
TimerAPCProc 的後兩個參數其實是在傳遞一個值, 使用時要把它們合並為一個 TFileTime 類型的時間.
這個時間是 APC 函數被調用的時間, 稍稍修改上面一個例子看一下:
代碼文件:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
hTimer: THandle;
{APC 函數}
procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; dwTimerLowValue: DWord;
dwTimerHighValue: DWord); stdcall;
var
UTCFileTime,LocalFileTime: TFileTime;
SystemTime: TSystemTime;
DateTime: TDateTime;
begin
{把 dwTimerLowValue 與 dwTimerHighValue 和並為一個 TFileTime 格式的時間}
UTCFileTime.dwLowDateTime := dwTimerLowValue;
UTCFileTime.dwHighDateTime := dwTimerHighValue;
FileTimeToLocalFileTime(UTCFileTime, LocalFileTime); {從世界標准計時到本地時間}
FileTimeToSystemTime(LocalFileTime, SystemTime); {轉到系統格式時間}
DateTime := SystemTimeToDateTime(SystemTime); {再轉到 TDateTime}
Form1.Text := DateTimeToStr(DateTime);
SleepEx(INFINITE, True);
end;
{線程入口函數}
function MyThreadFun(p: Pointer): Integer; stdcall;
var
DueTime: Int64;
begin
DueTime := 0;
if SetWaitableTimer(hTimer, DueTime, 1000, @TimerAPCProc, nil, False) then
begin
SleepEx(INFINITE, True);
end;
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ID: DWord;
begin
if hTimer = 0 then hTimer := CreateWaitableTimer(nil, True, nil);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
CancelWaitableTimer(hTimer);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
CloseHandle(hTimer);
end;
end.
窗體文件:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClIEntHeight = 86
ClIEntWidth = 256
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 23
Top = 32
Width = 97
Height = 25
Caption = #21551#21160#23450#26102#22120
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 134
Top = 32
Width = 97
Height = 25
Caption = #21462#28040#23450#26102#22120
TabOrder = 1
OnClick = Button2Click
end
end
SetWaitableTimer 中回調函數後面的指針參數, 將被傳遞給 APC 函數的第一個參數;
作為指針它可以攜帶任何數據, 這裡讓它攜帶了一個坐標點(鼠標點擊窗體的位置), 下例效果圖:
代碼文件:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
procedure FormDestroy(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
hTimer: THandle;
pt: TPoint;
{APC 函數}
procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; dwTimerLowValue: DWord;
dwTimerHighValue: DWord); stdcall;
var
UTCFileTime,LocalFileTime: TFileTime;
SystemTime: TSystemTime;
DateTime: TDateTime;
pt2: TPoint;
begin
UTCFileTime.dwLowDateTime := dwTimerLowValue;
UTCFileTime.dwHighDateTime := dwTimerHighValue;
FileTimeToLocalFileTime(UTCFileTime, LocalFileTime);
FileTimeToSystemTime(LocalFileTime, SystemTime);
DateTime := SystemTimeToDateTime(SystemTime);
pt2 := PPoint(lpArgToCompletionRoutine)^; {接受指針參數}
Form1.Canvas.Lock;
Form1.Canvas.TextOut(pt2.X, pt2.Y, DateTimeToStr(DateTime));
Form1.Canvas.Unlock;
SleepEx(INFINITE, True);
end;
{線程入口函數}
function MyThreadFun(p: Pointer): Integer; stdcall;
var
DueTime: Int64;
begin
DueTime := 0;
{參數 @pt 在這裡是鼠標點擊窗體時的坐標結構的指針, 它將傳遞給 APC 函數的第一個參數}
if SetWaitableTimer(hTimer, DueTime, 1000, @TimerAPCProc, @pt, False) then
begin
SleepEx(INFINITE, True);
end;
Result := 0;
end;
{建立 WaitableTimer 對象和線程}
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
ID: DWord;
begin
pt := Point(X,Y); {在這裡個全局的坐標點賦值}
if hTimer = 0 then hTimer := CreateWaitableTimer(nil, True, nil);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
CloseHandle(hTimer);
end;
end.
窗體文件:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClIEntHeight = 135
ClIEntWidth = 195
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnMouseDown = FormMouseDown
PixelsPerInch = 96
TextHeight = 13
end