MMHTimer.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:14k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49(0)351-8037944               =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/index.html               =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 07.10.98 - 21:01:39 $                                        =}
  24. {========================================================================}
  25. unit MMHTimer;
  26. {$I COMPILER.INC}
  27. {$C FIXED PRELOAD PERMANENT}
  28. {.$DEFINE _MMDEBUG}
  29. interface
  30. uses
  31. {$IFDEF WIN32}
  32.   Windows,
  33. {$ELSE}
  34.   WinTypes,
  35.   WinProcs,
  36. {$ENDIF}
  37.   SysUtils,
  38.   Messages,
  39.   Classes,
  40.   Graphics,
  41.   Controls,
  42.   Forms,
  43.   Dialogs,
  44.   MMSystem,
  45.   MMUtils,
  46.   MMString,
  47.   MMObj;
  48. type
  49.   EMMHiTimerError = class(Exception);
  50.   {$IFDEF WIN32}
  51.   TMMHiTimer      = class;
  52.   {-- TMMTimerThread ---------------------------------------------------}
  53.   TMMTimerThread  = class(TMMThreadEx)
  54.   private
  55.      HiTimer    : TMMHiTimer;
  56.      Terminating: Boolean;
  57.      procedure Execute; override;
  58.   end;
  59.   {$ENDIF}
  60.   {-- TMMHiTimer -------------------------------------------------------}
  61.   TMMHiTimer = class(TMMNonVisualComponent)
  62.   private
  63.   {$IFDEF WIN32}
  64.     FPriority         : TThreadPriority;
  65.     FTimerThread      : TMMTimerThread;
  66.     FTimerEvent       : THandle;
  67.     FGeneralEvent     : THandle;
  68.     FSynchronize      : Boolean;
  69.     FThreadCreated    : Boolean;
  70.     FWaitForTerminate : Boolean;
  71.     FMainThreadWaiting: Boolean;
  72.   {$ENDIF}
  73.     FEnabled          : Boolean;
  74.     FInterval         : integer;
  75.     FMessageCount     : integer;
  76.     FHandle           : THandle;
  77.     FTimerID          : integer;
  78.     FCallbackMode     : TMMCBMode;
  79.     FOnTimer          : TNotifyEvent;
  80.     procedure SetCallBackMode(aValue: TMMCBMode);
  81.     procedure SetEnabled(aValue: Boolean);
  82.     procedure SetInterval(aValue: integer);
  83.     procedure SetOnTimer(aValue: TNotifyEvent);
  84.     function  GetTimerCaps: TTimeCaps;
  85.     procedure UpdateTimer;
  86.     procedure WndProc(var Msg: TMessage);
  87.     {$IFDEF WIN32}
  88.     procedure SetPriority(aValue: TThreadPriority);
  89.     {$ENDIF}
  90.     procedure DoTimer;
  91.   protected
  92.     procedure Timer; dynamic;
  93.   public
  94.     constructor Create(AOwner:TComponent); override;
  95.     destructor  Destroy; override;
  96.     {$IFDEF WIN32}
  97.     procedure SynchronizeVCL(VCLProc: TThreadMethod);
  98.     {$ENDIF}
  99.     procedure ChangeDesigning(aValue: Boolean); override;
  100.   published
  101.     property CallBackMode: TMMCBMode read FCallBackMode write SetCallBackMode default cmWindow;
  102.     property Enabled: Boolean read FEnabled write SetEnabled default True;
  103.     property Interval: integer read FInterval write SetInterval default 1000;
  104.     property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
  105.     {$IFDEF WIN32}
  106.     property Priority: TThreadPriority read FPriority write SetPriority default tpNormal;
  107.     property Synchronize: Boolean read FSynchronize write FSynchronize default True;
  108.     property WaitForTerminate: Boolean read FWaitForTerminate write FWaitForTerminate default False;
  109.     {$ENDIF}
  110.   end;
  111. implementation
  112. Uses
  113.     Consts
  114.     {$IFDEF _MMDEBUG}
  115.     ,MMDebug
  116.     {$ENDIF};
  117. {$IFDEF _MMDEBUG}
  118. {-------------------------------------------------------------------------}
  119. procedure Debug(Level: integer; s: String);
  120. begin
  121.    if (s <> ' ') then s := 'HiTimer: '+s;
  122.    DB_WriteStrLn(Level,s);
  123. end;
  124. {$ENDIF}
  125. {-- TimeCallBack -------------------------------------------------------}
  126. procedure TimeCallBack(uTimerID, uMessage: UINT; dwUser, dw1, dw2: Longint);
  127. export;{$IFDEF WIN32}stdcall;{$ENDIF}
  128. begin
  129.    if (dwUser <> 0) then
  130.    with TMMHiTimer(dwUser) do
  131.    {$IFDEF WIN32}
  132.    try
  133.    {$ELSE}
  134.    begin
  135.    {$ENDIF}
  136.       case FCallBackMode of
  137.          cmWindow  : if (FMessageCount < 10) then
  138.                      begin
  139.                         inc(FMessageCount);
  140.                         PostMessage(FHandle,MM_TIMER,uTimerID,0);
  141.                      end;
  142.          cmCallBack: DoTimer;
  143.          {$IFDEF WIN32}
  144.          cmThread  : SetEvent(FTimerEvent);
  145.          {$ENDIF}
  146.       end;
  147.    {$IFDEF WIN32}
  148.    except
  149.       Application.HandleException(nil);
  150.    {$ENDIF}
  151.    end;
  152. end;
  153. {$IFDEF WIN32}
  154. {== TMMTimerThread =====================================================}
  155. procedure TMMTimerThread.Execute;
  156. var
  157.    h: THandle;
  158. begin
  159.    if (HiTimer <> nil) then
  160.    try
  161.       Priority := HiTimer.FPriority;
  162.       { Ready to go, set the general event }
  163.       SetEvent(HiTimer.FGeneralEvent);
  164.       {$IFDEF _MMDEBUG}
  165.       Debug(0,'Timer ThreadProc started...');
  166.       {$ENDIF}
  167.       while not Terminated and not Terminating and (HiTimer <> nil) do
  168.       begin
  169.          WaitForSingleObject(HiTimer.FTimerEvent,INFINITE);
  170.          if not Terminated and not Terminating and (HiTimer <> nil) then
  171.             HiTimer.DoTimer;
  172.       end;
  173.       if (HiTimer <> nil) then
  174.       begin
  175.          h := HiTimer.FGeneralEvent;
  176.          HiTimer.FTimerThread := nil;
  177.          HiTimer := nil;
  178.          SetEvent(h);
  179.       end;
  180.    except
  181.       Application.HandleException(Self);
  182.    end;
  183.    {$IFDEF _MMDEBUG}
  184.    Debug(0,'Timer ThreadProc terminated...');
  185.    {$ENDIF}
  186. end;
  187. {$ENDIF}
  188. {== TMMHiTimer =========================================================}
  189. procedure TMMHiTimer.WndProc(var Msg: TMessage);
  190. begin
  191.    with Msg do
  192.    if (Msg = MM_TIMER) and (wParam = FTimerID) then
  193.    try
  194.       try
  195.          Timer;
  196.       finally
  197.          dec(FMessageCount);
  198.       end;
  199.    except
  200.       Application.HandleException(Self);
  201.    end
  202.    else Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  203. end;
  204. {-- TMMHiTimer -----------------------------------------------------------}
  205. constructor TMMHiTimer.Create(aOwner: TComponent);
  206. begin
  207.    inherited Create(aOwner);
  208.    FEnabled := True;
  209.    FInterval := 1000;
  210.    FTimerID  := 0;
  211.    FHandle := 0;
  212.    FMessageCount := 0;
  213.    FCallBackMode := cmWindow;
  214. {$IFDEF WIN32}
  215.    FPriority := tpNormal;
  216.    FSynchronize := True;
  217.    FThreadCreated := False;
  218.    FWaitForTerminate := False;
  219.    FMainThreadWaiting := False;
  220. {$ENDIF}
  221.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  222.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  223. end;
  224. {-- TMMHiTimer -----------------------------------------------------------}
  225. destructor TMMHiTimer.Destroy;
  226. begin
  227.    FOnTimer := nil;
  228.    FEnabled := False;
  229.    UpdateTimer;
  230.    inherited destroy;
  231. end;
  232. {-- TMMHiTimer -----------------------------------------------------------}
  233. procedure TMMHiTimer.ChangeDesigning(aValue: Boolean);
  234. begin
  235.    inherited;
  236.    UpdateTimer;
  237. end;
  238. {-- TMMHiTimer -----------------------------------------------------------}
  239. Procedure TMMHiTimer.SetCallBackMode(aValue: TMMCBMode);
  240. begin
  241.    if (aValue <> FCallBackMode) then
  242.    begin
  243.       if (aValue = cmCallBack) then
  244.       begin
  245.          {$IFDEF WIN32}
  246.          if not _WIN95_ then
  247.          {$ENDIF}
  248.          begin
  249.             Application.MessageBox('"CallBacks" are called at interrupt time !'#10#13+
  250.                                    'This is currently only supported under Windows 95',
  251.                                    'TMMHiTimer', MB_OK);
  252.             exit;
  253.          end;
  254.       end;
  255.       FCallBackMode := aValue;
  256.       UpdateTimer;
  257.    end;
  258. end;
  259. {-- TMMHiTimer -----------------------------------------------------------}
  260. procedure TMMHiTimer.SetEnabled(aValue: Boolean);
  261. begin
  262.    if (aValue <> FEnabled) then
  263.    begin
  264.      FEnabled := aValue;
  265.      UpdateTimer;
  266.    end;
  267.    {$IFDEF WIN32}
  268.    {$IFDEF TRIAL}
  269.    {$DEFINE _HACK2}
  270.    {$I MMHACK.INC}
  271.    {$ENDIF}
  272.    {$ENDIF}
  273. end;
  274. {-- TMMHiTimer -----------------------------------------------------------}
  275. procedure TMMHiTimer.SetInterval(aValue: integer);
  276. begin
  277.    if (aValue <> FInterval) then
  278.    begin
  279.       FInterval := aValue;
  280.       UpdateTimer;
  281.    end;
  282. end;
  283. {-- TMMHiTimer -----------------------------------------------------------}
  284. procedure TMMHiTimer.SetOnTimer(aValue: TNotifyEvent);
  285. begin
  286.    FOnTimer := aValue;
  287.    UpdateTimer;
  288. end;
  289. {-- TMMHiTimer -----------------------------------------------------------}
  290. function TMMHiTimer.GetTimerCaps: TTimeCaps;
  291. var
  292.    Temp:TTimeCaps;
  293. begin
  294.    TimeGetDevCaps(@Temp, sizeof(Temp));
  295.    Result := Temp;
  296.    {$IFDEF WIN32}
  297.    {$IFDEF TRIAL}
  298.    {$DEFINE _HACK2}
  299.    {$I MMHACK.INC}
  300.    {$ENDIF}
  301.    {$ENDIF}
  302. end;
  303. {-- TMMHiTimer -----------------------------------------------------------}
  304. procedure TMMHiTimer.UpdateTimer;
  305. var
  306. {$IFNDEF WIN32}
  307.    TimeCB: TTimeCallBack;
  308. {$ENDIF}
  309.    Msg: TMsg;
  310. begin
  311.    if (csDesigning in ComponentState) then exit;
  312.    {$IFDEF WIN32}
  313.    if FThreadCreated then
  314.    begin
  315.       {$IFDEF _MMDEBUG}
  316.       Debug(0,'Shot down Thread...');
  317.       {$ENDIF}
  318.       FTimerThread.Terminating := True;
  319.       { in case it is suspended remove all before terminate }
  320.       while FTimerThread.Suspended do FTimerThread.Resume;
  321.       FTimerThread.Terminate;
  322.       { force the thread to wake }
  323.       SetEvent(FTimerEvent);
  324.       { ...and wait for it to die }
  325.       if FWaitForTerminate and not FMainThreadWaiting then
  326.          WaitForSingleObject(FGeneralEvent, 5000);
  327.       if (FTimerThread <> nil) then
  328.           FTimerThread.HiTimer := nil;
  329.       { free the events }
  330.       CloseHandle(FGeneralEvent);
  331.       CloseHandle(FTimerEvent);
  332.       FThreadCreated := False;
  333.       {$IFDEF _MMDEBUG}
  334.       Debug(0,'Thread now stopped...');
  335.       {$ENDIF}
  336.    end;
  337.    {$ENDIF}
  338.    {$IFDEF WIN32}
  339.    {$IFDEF TRIAL}
  340.    {$DEFINE _HACK3}
  341.    {$I MMHACK.INC}
  342.    {$ENDIF}
  343.    {$ENDIF}
  344.    if (FTimerID <> 0) then
  345.    begin
  346.       TimeKillEvent(FTimerID);
  347.       FTimerID := 0;
  348.       if (FHandle <> 0) then
  349.       begin
  350.          { remove pending messages }
  351.          while PeekMessage(Msg, FHandle, MM_TIMER, MM_TIMER, PM_REMOVE) do;
  352.          DeallocateHWnd(FHandle);
  353.          FHandle := 0;
  354.          FMessageCount := 0;
  355.       end;
  356.       TimeEndPeriod(GetTimerCaps.wPeriodMin);
  357.    end;
  358.    if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
  359.    begin
  360.       case FCallBackMode of
  361.          cmWindow: FHandle := AllocateHWnd(WndProc);
  362.          {$IFDEF WIN32}
  363.          cmThread:
  364.          begin
  365.             {$IFDEF _MMDEBUG}
  366.             Debug(0,'Try to start Thread...');
  367.             {$ENDIF}
  368.             FGeneralEvent := CreateEvent(nil, False, False, nil);
  369.             FTimerEvent := CreateEvent(nil,False,False,nil);
  370.             FTimerThread := TMMTimerThread.Create(True);
  371.             if (FTimerThread = nil) then
  372.                raise EMMHiTimerError.Create('HiTimer:'#10#13+LoadResStr(IDS_THREADERROR));
  373.             FTimerThread.HiTimer := Self;
  374.             FTimerThread.FreeOnTerminate := True;
  375.             FTimerThread.Terminating := False;
  376.             FThreadCreated := True;
  377.             FTimerThread.Resume;
  378.             { Wait for it to start... }
  379.             if WaitForSingleObject(FGeneralEvent, 5000) <> WAIT_OBJECT_0 then
  380.                raise EMMHiTimerError.Create('HiTimer:'#10#13+LoadResStr(IDS_THREADERROR));
  381.             {$IFDEF _MMDEBUG}
  382.             Debug(0,'Thread started...');
  383.             {$ENDIF}
  384.          end
  385.          {$ENDIF}
  386.       end;
  387.       {$IFDEF WIN32}
  388.       TimeBeginPeriod(GetTimerCaps.wPeriodMin);
  389.       FTimerID := TimeSetEvent(FInterval, 0, @TimeCallBack, Longint(Self), TIME_PERIODIC);
  390.       {$ELSE}
  391.       TimeCB := TimeCallBack;
  392.       TimeBeginPeriod(GetTimerCaps.wPeriodMin);
  393.       FTimerID := TimeSetEvent(FInterval, 0, TimeCB, Longint(Self), TIME_PERIODIC);
  394.       {$ENDIF}
  395.       if (FTimerID = 0) then
  396.          raise EOutOfResources.Create({$IFDEF DELPHI3}SNoTimers{$ELSE}LoadStr(SNoTimers){$ENDIF});
  397.    end;
  398. end;
  399. {$IFDEF WIN32}
  400. {-- TMMHiTimer -----------------------------------------------------------}
  401. procedure TMMHiTimer.SetPriority(aValue: TThreadPriority);
  402. begin
  403.    if aValue <> FPriority then
  404.    begin
  405.       FPriority := aValue;
  406.       if FThreadCreated then
  407.       begin
  408.          FTimerThread.Priority := FPriority;
  409.       end;
  410.    end;
  411. end;
  412. {-- TMMHiTimer -----------------------------------------------------------}
  413. procedure TMMHiTimer.SynchronizeVCL(VCLProc: TThreadMethod);
  414. begin
  415.    if (FCallBackMode = cmThread) and FThreadCreated then
  416.    begin
  417.       FMainThreadWaiting := True;
  418.       FTimerThread.Synchronize(VCLProc);
  419.       FMainThreadWaiting := False;
  420.    end;
  421. end;
  422. {$ENDIF}
  423. {-- TMMHiTimer -----------------------------------------------------------}
  424. procedure TMMHiTimer.DoTimer;
  425. begin
  426.    {$IFDEF WIN32}
  427.    if (FCallBackMode = cmThread) and FSynchronize then
  428.       SynchronizeVCL(Timer)
  429.    else
  430.    {$ENDIF}
  431.       Timer;
  432. end;
  433. {-- TMMHiTimer -----------------------------------------------------------}
  434. procedure TMMHiTimer.Timer;
  435. begin
  436.    if Assigned(FOnTimer) and FEnabled then FOnTimer(Self);
  437. end;
  438. end.