How to get a delphi application (that's running) to do something at a particular time/date

前端 未结 6 1152
伪装坚强ぢ
伪装坚强ぢ 2020-12-13 11:07

My application sits in the system tray when it\'s not being used.

The user can configure events to occur at particular schedule. For example they may way the task p

相关标签:
6条回答
  • 2020-12-13 11:35

    You can use my CRON compliant Cromis Scheduler. It even supports some things that cron does not. Interval based events for instance and from / to timeframe. I use it in a lot of my software and it has proven itself quite useful. It is free, very lightweight, works in threads and is production tested. If you need any further help just mail me.

    The other ways would be:

    1. Use windows scheduling API as already suggested. But this may change between OS-es.
    2. Use JCL that has a scheduler unit (component in the JVCL), but I found that one hard to use from code directly. That is why I wrote my own.
    0 讨论(0)
  • 2020-12-13 11:46

    You need a scheduling component. There are many available, however I can't seem to find any free one. You can always build one yourself, based on TTimer, or try to access theTask Scheduling API.

    However, having a timer that executes a task every minute to check if a task is due, is much simpler.

    0 讨论(0)
  • 2020-12-13 11:48

    I would use the Microsoft Task Scheduler API for that:

    http://msdn.microsoft.com/en-us/library/aa383614(VS.85).aspx

    There are Delphi Wrappers available for the API if you don't want to do the "dirty work", but I don't know if there's a free one. You might have a look at

    • http://www.sicomponents.com/taskscheduler.html
    • http://www.torry.ru/pages.php?id=296

    If you don't want to use the Microsoft Scheduler, there are things like the CronJob Component available here: http://www.appcontrols.com/components.html. It's shareware, too, but is easy to implement (just an onAlert event).

    0 讨论(0)
  • 2020-12-13 11:48

    Another option would be to create a TThread which performs the management of the timer:

    type
      TestThreadMsg = class(tThread)
      private
        fTargetDate : tDateTime;
        fMsg : Cardinal;
      protected
        procedure Execute; override;
        procedure NotifyApp;
      public
        constructor Create( TargetDate : TDateTime; Msg:Cardinal);
      end;
    

    implementation:

    constructor TestThreadMsg.Create(TargetDate: TDateTime; Msg: Cardinal);
    begin
      inherited Create(True);
      FreeOnTerminate := true;
      fTargetDate := TargetDate;
      fMsg := Msg;
      Suspended := false;
    end;
    
    procedure TestThreadMsg.Execute;
    begin
      Repeat
        if Terminated then exit;
        if Now >= fTargetDate then
          begin
            Synchronize(NotifyApp);
            exit;
          end;
        Sleep(1000); // sleep for 1 second, resoultion = seconds
      Until false;
    end;
    
    procedure TestThreadMsg.NotifyApp;
    begin
      SendMessage(Application.MainForm.Handle,fMsg,0,0);
    end;
    

    Which can then be hooked up to the main form:

    const
      WM_TestTime = WM_USER + 1;
    
    TForm1 = Class(TForm)
      :
      procedure FormCreate(Sender: TObject);
      procedure WMTestTime(var Msg:tMessage); message WM_TestTime;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TestThreadMsg.Create(IncSecond(Now,5),WM_TestTime);
    end;
    
    procedure TForm1.WMTestTime(var Msg: tMessage);
    begin
      ShowMessage('Event from Thread');
    end;
    
    0 讨论(0)
  • 2020-12-13 12:00

    Since your application is running, you can use the idle event to see if a preset date/time has already elapsed and if so then to perform your timing. The only side effect of this approach is that your event won't fire if the application is busy, but then neither would a timer (for the TTimer to work the message queue needs to be processed, or the application needs to be "Idle" unless you use a threaded timer).

    uses
      ...,DateUtils; // contains IncMinute
    
    type
      TForm1 = Class(TForm)
        :
        procedure FormCreate(Sender: TObject);
      private 
        fTargetDate : tDateTime;
        procedure AppIdle(Sender: TObject; var Done: Boolean);
      end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      fTargetDate := 0.0;
      Application.OnIdle := AppIdle;
      fTargetDate := IncMinute(Now,2);
    end;
    
    procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
    begin
      if (fTargetDate <> 0.0) and (Now >= fTargetDate) then
        begin
          fTargetDate := 0.0;
          ShowMessage('started');
        end;
     end;
    

    EDIT If you have multiple times you need to run something, place in an ordered list by date/time and then only track the NEXT time something will run. As something is run, it is removed for the list (or rescheduled back into the list and the list re-sorted).

    0 讨论(0)
  • 2020-12-13 12:02

    You could implement some kind of inter process communication in your program and trigger these events via ipc by a program called from the Windows scheduling service. This approach has the advantage that you don't need to write a user interface to set up the schedule and also that ipc might prove useful in other ways.

    0 讨论(0)
提交回复
热议问题