1、怎么把TWaitableTimer的Self传给TimerAPCProc?这种做法对吗:
SetWaitableTimer(FHandle, DueTime, 1000, @TimerAPCProc,Pointer(self), False)procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; dwTimerLowValue: DWORD;
  dwTimerHighValue: DWORD); stdcall;
var
  WT :TWaitableTimer;
begin
  WT := TWaitableTimer(lpArgToCompletionRoutine^);
  ……红色的部分传递Self。2、程序运行到下述红色语句时出错:Project Projcet1.exe raised exception 
class EAccessViolation with message 'Access violation at address 004A6E40 in
module 'Project1.exe', Write of address 004A68CC'.procedure TWaitableTimer.SetElapsedTime(const Value: TDateTime);
begin
  gLock.Enter;
  try
    FElapsedTime := Value;
  finally
    gLock.Leave;
  end;
end;3、当剩余时间为0时,如何终止定时器?这样处理行吗?
procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; 
  dwTimerLowValue: DWORD; dwTimerHighValue: DWORD); stdcall;

var
  WT :TWaitableTimer;
begin
  WT := TWaitableTimer(lpArgToCompletionRoutine^);
  with WT do
  begin
    if FRemainingTime>0 then
      ……
    else
      CancelTimer;

  end;
 
  SleepEx(INFINITE, True);
end;
源程序如下:unit WaitTimer;interfaceuses
  SysUtils, Classes, Windows, SyncObjs, StdCtrls;type
  TWaitableTimer = class(TThread)
  private
    FHandle: THandle;
    FStartTime: TDateTime;
    FShowRT: Boolean;
    FETParent: TStaticText;
    FTotalTimes: TDateTime;
    FElapsedTime: TDateTime;
    FRemainingTime: TDateTime;
    FRTParent: TStaticText;    procedure SetHandle;
    procedure SetShowRT(const Value: Boolean);
    procedure SetStartTime;
    procedure SetETParent(const Value: TStaticText);
    function GetShowRT: Boolean;
    procedure SetTimer(const ETSender,RTSender: TObject);
    procedure SetRTParent(const Value: TStaticText);
    procedure SetRTCaption(const Value: string);
  public
    constructor Create(const ETSender,RTSender: TObject; 
      const AName: String = '');
    destructor Destroy(); override;
    procedure Execute; override;
    function CancelTimer: Boolean;
    function Time2String(aTime: TDateTime): string;
    procedure SetTotalTimes(const Value: TDateTime);
    procedure SetElapsedTime(const Value: TDateTime);
    procedure SetRemainingTime(const Value: TDateTime);
    function GetTotalTimes: TDateTime;
  Protected
    property Handle: THandle read FHandle;
    property StartTime: TDateTime read FStartTime;
    property TotalTimes: TDateTime read GetTotalTimes write SetTotalTimes;
    property ElapsedTime: TDateTime read FElapsedTime write SetElapsedTime;
    property RemainingTime: TDateTime read FRemainingTime 
      write SetRemainingTime;
    property ETParent: TStaticText read FETParent write SetETParent;
    property RTParent: TStaticText read FRTParent write SetRTParent;
    property ShowRT: Boolean read GetShowRT write SetShowRT;
  end;implementation{ TWaitableTimer }
var
    gLock: TCriticalSection;procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer; 
  dwTimerLowValue: DWORD;dwTimerHighValue: DWORD); stdcall;
var
  WT :TWaitableTimer;
begin
  WT := TWaitableTimer(lpArgToCompletionRoutine^);
  with WT do
  begin
    if FRemainingTime>0 then
    begin
      SetElapsedTime(Now - StartTime);
      FETParent.Caption := Time2String(FElapsedTime);      if GetShowRT then
      begin
        SetRemainingTime(GetTotalTimes - FElapsedTime);
        SetRTCaption(Time2String(FRemainingTime));
      end;
    end
    else
      CancelTimer;
  end;  SleepEx(INFINITE, True);
end;function TWaitableTimer.CancelTimer: Boolean;
begin
  Result := CancelWaitableTimer(FHandle);
end;constructor TWaitableTimer.Create(const ETSender, RTSender: TObject; 
  const AName: String);
begin
  gLock := TCriticalSection.Create;  SetTimer(ETSender,RTSender);  inherited Create(False);
end;destructor TWaitableTimer.Destroy;
begin
  CloseHandle(FHandle);
  gLock.Destroy;  inherited;
end;procedure TWaitableTimer.Execute;
var
  DueTime: int64;
begin
  inherited;  DueTime := 0;  if SetWaitableTimer(
      FHandle, DueTime, 1000, @TimerAPCProc, Pointer(self),False
  ) then
  begin
    SleepEx(INFINITE, True);
  end;
end;function TWaitableTimer.GetShowRT: Boolean;
begin
  result := False;  gLock.Enter;
  try
    result := FShowRT;
  finally
    gLock.Leave;
  end;
end;function TWaitableTimer.GetTotalTimes: TDateTime;
begin
  result := 0;  gLock.Enter;
  try
    result := FTotalTimes;
  finally
    gLock.Leave;
  end;
end;procedure TWaitableTimer.SetElapsedTime(const Value: TDateTime);
begin
  gLock.Enter;
  try
    FElapsedTime := Value;
  finally
    gLock.Leave;
  end;
end;procedure TWaitableTimer.SetHandle;
begin
  if FHandle = 0 then
    FHandle := CreateWaitableTimer(nil, True, nil);
end;procedure TWaitableTimer.SetRemainingTime(const Value: TDateTime);
begin
  gLock.Enter;
  try
    FRemainingTime := Value;
  finally
    gLock.Leave;
  end;
end;procedure TWaitableTimer.SetRTCaption(const Value: string);
begin
  if ShowRT then
    RTParent.Caption := Value
  else
    RTParent.Caption := '计算中……';
end;procedure TWaitableTimer.SetRTParent(const Value: TStaticText);
begin
  FRTParent := Value;
end;procedure TWaitableTimer.SetShowRT(const Value: Boolean);
begin
  gLock.Enter;
  try
    FShowRT := Value;
  finally
    gLock.Leave;
  end;
end;procedure TWaitableTimer.SetStartTime;
begin
  FStartTime := Now;
end;procedure TWaitableTimer.SetTimer(const ETSender, RTSender: TObject);
begin
  SetHandle;
  SetStartTime;
  SetTotalTimes(0);
  SetElapsedTime(0);
  SetRemainingTime(0);
  if ETSender is TStaticText then
    SetETParent(TStaticText(ETSender));
  if RTSender is TStaticText then
    SetRTParent(TStaticText(RTSender));
  SetRTCaption('');
  SetShowRT(False);
end;procedure TWaitableTimer.SetETParent(const Value: TStaticText);
begin
  FETParent := Value;
end;procedure TWaitableTimer.SetTotalTimes(const Value: TDateTime);
begin
  gLock.Enter;
  try
    FTotalTimes := Value;
    if FTotalTimes<>0 then
      SetShowRT(True);
  finally
    gLock.Leave;
  end;
end;function TWaitableTimer.Time2String(aTime: TDateTime): string;
begin
  DateTimeToString(result,'hh:nn:ss',aTime);
end;
end.调用如下:
unit Unit3;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WaitTimer;type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    StaticText1: TStaticText;
    StaticText2: TStaticText;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation
{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var
  WT: TWaitableTimer;
  i: integer;
  t1,t2: Int64;
begin
  randomize; 
  WT := TWaitableTimer.Create(StaticText1,StaticText2);
  t1 := GetTickCount;
  for I := 0 to 1000 do
  begin
    Label1.Caption := inttostr(i);
    Application.ProcessMessages;
    Sleep(random(10));
    t2 := (GetTickCount - t1) * (1000 - i);
    WT.SetTotalTimes(t2);
  end;
  WT.Free;
end;end.