Как получить приложение delphi (что работает), чтобы что-то сделать в определенное время/дату

Мое приложение находится в системном трее, когда оно не используется.

Пользователь может настраивать события для определенного графика. Например, они могут выполнить задание в пн-пт в 17:00 или каждую среду в 15:00 или 16-го числа каждого месяца в 10 утра.

Предполагая, что моя программа delphi всегда работает, она запускается при загрузке, что является лучшим способом в delphi для поддержки запуска этих запланированных событий.

Очевидно, что TTimer может использоваться для планирования событий на основе прошедшего времени, но они не подходят для этой проблемы.

Приветствия

Ответ 1

Вы можете использовать CRON Cromis Scheduler. Он даже поддерживает некоторые вещи, которые cron не делает. События на основе интервала, например, и от/до таймфрейма. Я использую его во многих своих программах, и он оказался весьма полезным. Он бесплатный, очень легкий, работает в потоках и протестирован на производстве. Если вам нужна дополнительная помощь, просто напишите мне.

Другие способы:

  • Использовать API планирования Windows, как уже было предложено. Но это может измениться между OS-es.
  • Используйте JCL, у которого есть блок планировщика (компонент в JVCL), но я обнаружил, что один из них трудно использовать из кода. Вот почему я написал свои собственные.

Ответ 2

Я бы использовал API планировщика заданий Microsoft для этого:

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

Для API доступны инструменты Delphi Wrappers, если вы не хотите выполнять "грязную работу", но я не знаю, есть ли бесплатная. Вы можете взглянуть на

Если вы не хотите использовать Microsoft Scheduler, здесь есть такие компоненты, как CronJob Component: http://www.appcontrols.com/components.html. Это условно-бесплатное программное обеспечение, но его легко реализовать (просто событие onAlert).

Ответ 3

Вам нужен компонент планирования. Есть много доступных, однако я не могу найти никакой свободной. Вы всегда можете создать его самостоятельно на основе TTimer или попытаться получить доступ к API планирования задач.

Однако, имея таймер, выполняющий задачу каждую минуту, чтобы проверить, требуется ли задание, проще намного.

Ответ 4

Вы могли бы реализовать некоторую межпроцессную связь в своей программе и запускать эти события через ipc с помощью программы, вызванной службой планирования Windows. Этот подход имеет то преимущество, что вам не нужно писать пользовательский интерфейс для настройки расписания, а также то, что ipc может оказаться полезным другим способом.

Ответ 5

Поскольку ваше приложение запущено, вы можете использовать событие idle, чтобы узнать, прошло ли заданная дата/время и если да, то для выполнения вашего времени. Единственным побочным эффектом этого подхода является то, что ваше событие не срабатывает, если приложение занято, но тогда ни один таймер (для работы TTimer очередь сообщений не требуется, или приложение должно быть "Idle" ) если вы не используете поточный таймер).

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;

РЕДАКТИРОВАТЬ Если у вас есть несколько раз, вам нужно что-то запускать, поместить в упорядоченный список по дате/времени, а затем отслеживать только время NEXT. Когда что-то запущено, оно удаляется для списка (или перенаправляется обратно в список, а список повторно сортируется).

Ответ 6

Другой вариант - создать TThread, который выполняет управление таймером:

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

реализация:

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;

который затем можно подключить к основной форме:

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;