11
votes

Comment obtenir une application DELPHI (qui fonctionne) pour faire quelque chose à un moment / date particulier

Mon application est assise dans la barre d'état système quand elle n'est pas utilisée.

L'utilisateur peut configurer des événements à survenir à la planification particulière. Par exemple, ils peuvent appartenir à la tâche effectuée le lundi au vendredi à 17h ou tous les mercredis à 15h00 ou le 16 de chaque mois à 10h00.

Assumer que mon programme Delphi est toujours en cours d'exécution, il commence à démarrer, quelle est la meilleure façon de Delphi d'appuyer le déclenchement de ces événements planifiés.

Évidemment, un Timer peut être utilisé pour planifier des événements basés sur le temps écoulé, mais ils ne semblent pas adaptés à ce problème.

acclamations


5 commentaires

Avez-vous envisagé d'utiliser le planificateur de tâches intégré de Windows pour lancer votre programme avec un paramètre pour obtenir le démarrage de la tâche ou est-il important que la planification a lieu dans votre application?


Pourquoi considérer le temps écoulé? Avoir juste un seul feu de minuterie de temps en temps (une fois toutes les 10 secondes serait une résolution raisonnable). Une fois qu'il incendie, arrêtez temporairement la minuterie et parcourez votre liste d'événements planifiés. Vous connaissez l'heure et la journée actuelles, vous savez que chacun des événements planifiés a été licencié (si jamais) - il serait facile de tirer parti de chacun des événements devenus dus / en retard, et de redémarrer enfin votre minuterie. Je fais quelque chose de similaire à cela dans plusieurs programmes, et je pense que c'est votre voie la plus facile si vous voulez tout faire à Delphi.


@robsoft: Vous auriez dû faire cela une réponse à la place, ce que j'aurais voté. Avec la seule modification pour ne pas avoir le feu de la minuterie toutes les x secondes, mais de calculer dynamiquement l'intervalle à l'événement suivant.


Mon planificateur fait exactement ça. Il raccourcit la période d'attente comme elle s'approche de l'événement et utilise WaitforsingObject entre les deux.


@gghie - merci. Je m'attendais à beaucoup de gens de dire la même chose, seulement mieux, c'est pourquoi je ne me suis pas préoccupé de faire une réponse. Je vais savoir mieux la prochaine fois! La raison pour laquelle mes applications incendie régulièrement est simplement qu'il existe également d'autres activités régulières à la minuterie dans les programmes. Si ce n'était qu'un programme de lancement de quelques événements spécifiques à des heures prédéterminées, vous avez raison, vous pouvez simplement calculer de manière dynamique l'intervalle à l'événement suivant et avoir le feu de la minuterie pour cela.


6 Réponses :


8
votes

J'utiliserais l'API du planificateur de tâches Microsoft pour cela:

http://msdn.microsoft.com/fr -us / bibliothèque / AA383614 (vs.85) .aspx

Il y a des wrappers Delphi disponibles pour l'API si vous ne voulez pas faire le «travail sale», mais je ne sais pas s'il y a un gratuit. Vous pourriez avoir un coup d'oeil à


5 commentaires

Comment laisserez-vous le planificateur de tâches Windows déclencher l'exécution des tâches dans l'exécutable déjà exécutable?


Code de l'application de manière à ce qu'il n'autorise qu'une seule instance. Si un autre instance est lancé (que l'approche du planificateur de tâches tenterait de faire), cette nouvelle instance peut transférer les informations pertinentes à l'instance existante d'Alreadu via une forme d'IPC (par exemple à l'aide de SendMessage) avant de quitter. Il n'a probablement pas de sens d'exécuter de multiples instances de l'application, alors rien n'est vraiment perdu en ajoutant une telle limitation.


HM OK, mais il semble lourd et une solution sujette erronée. Je dirais que cela dépend vraiment du problème à la main. Le planificateur Windows peut être assez bon ou même une solution parfaite, mais dans certains cas, il est totalement inapproprié.


Bien personnellement, je diviserais ma demande en deux exécutables: une qui ne fait rien d'autre que d'exécuter les tâches que les utilisateurs peuvent définir (et cette application est appelée par le planificateur) et à laquelle mes utilisateurs peuvent ajouter de nouvelles tâches, ce serait celui L'OP a constamment couru dans son plateau. La suggestion de Michaels est également une bonne idée, mais imo trop compliqué à mettre en œuvre :-)


@Michael: cette solution commence à regarder vraiment compliqué, que je pense est un signe certain que le planificateur de tâches Windows n'est que la mauvaise approche.



1
votes

Vous avez besoin d'un composant de planification. Il y a Beaucoup de disponibilités , mais je ne peux pas sembler trouver gratuit . Vous pouvez toujours construire un vous-même, basé sur Timer, ou essayer d'accéder à API de planification des tâches.

Cependant, , ayant une minuterie qui exécute une tâche chaque minute pour vérifier si une tâche est due, est beaucoup plus simple


0 commentaires

17
votes

Vous pouvez utiliser mon CRON CONFORIANT Cromis Scheduler (link à archiver.org). Il soutient même certaines choses que Cron ne le fait pas. Événements basés sur les intervalles par exemple et à partir de / à la période. Je l'utilise dans beaucoup de mon logiciel et cela s'est avéré très utile. C'est gratuit, très léger, fonctionne dans des fils et est testé de la production. Si vous avez besoin d'aide supplémentaire, envoyez-moi un mail.

Les autres manières seraient:

  1. Utilisez l'API de planification Windows comme déjà suggéré. Mais cela peut changer entre OS-ES.
  2. Utilisez JCL qui a une unité de planificateur (composant dans la JVCL), mais j'ai trouvé que Un difficile à utiliser du code directement. C'est pourquoi j'ai écrit le mien.

5 commentaires

Je viens d'essayer cela et non seulement cela a-t-il gelé mon application de manière étrange (où même le débogueur n'a pas terminé l'application) mais a également laissé une fuite de mémoire méchante (et a dû redémarrer l'IDE à chaque fois que je l'ai couru).


Et il cycles de processeur porcine et même s'il fonctionne dans un fil secondaire pour une raison quelconque, il est enlaver mon fil principal. Et je l'ai fait fondamentalement rien que de montrer un message quand il déclenche. Juste mes deux cents. Ceci est un Delphi Xe2 fraîchement installé (et mis à jour) au moyen.


Pour le compte rendu, la fuite de mémoire était de ma faute, mais le reste des problèmes persistent toujours. CPU enlisé, le fil principal enlisé même si elle est utilisée dans un autre fil de travailleur et même de ne pas tirer des événements.


@Jerry, vous utilisez le type de signalisation STMESSAGE dans un fil sans pompe à message. Ce type de signalisation utilise PostMessage pour vous informer de l'événement et dans votre cas qui ne reçoit jamais de processus. Changez que pour STSYCHRONISE ou STHENED, ou créer une pompe à message dans le fil où vous avez créé le calendrier. Ou créer tous les horaires dans le fil principal.


Le site Web Cromis est un site de phishing maintenant. Quelqu'un semble avoir pris une sauvegarde du code et la mettre sur GitHub, mais je ne peux pas en garcer.



1
votes

Vous pourriez mettre en œuvre une sorte de communication inter processus dans votre programme et déclencher ces événements via ipc par un programme appelé à partir du service de planification de Windows. Cette approche présente l'avantage de ne pas avoir besoin d'écrire une interface utilisateur pour configurer le calendrier et que IPC pourrait s'avérer utile d'une autre manière.


0 commentaires

0
votes

Étant donné que votre application est en cours d'exécution, vous pouvez utiliser l'événement de ralenti pour voir si une date / heure prédéfinie s'est déjà écoulée et, le cas échéant, d'effectuer votre timing. Le seul effet secondaire de cette approche est que votre événement ne se déclenche pas si l'application est occupée, mais non plus une minuterie (pour que TTIMER fonctionne la file d'attente de message doit être traitée, ou l'application doit être "inactive" sauf si vous utilisez une minuterie filetée).

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;


1 commentaires

Notez que vous appuyer uniquement sur onidle est dangereux, car cela sera appelé qu'après le dernier message en file d'attente pour l'une des fenêtres créées par le fil VCL a été traitée. S'il n'y a pas de messages, aucun traitement inactif n'a lieu. Si l'application est minimisée ou n'a aucune fenêtre visible et il n'y a pas de messages diffusés cela pourrait essentiellement signifier jamais.



0
votes

Une autre option serait de créer une Ththread qui effectue la gestion de la minuterie: xxx

implémentation: xxx

qui peut alors être connecté jusqu'à la forme principale: xxx


2 commentaires

Mise en œuvre d'un thread pour un Ttimer? Ne crée pas de Timer un fil lui-même ?? Il n'y a donc aucun avantage par rapport à Onter ...


Seuls celui-ci ne fait pas des secondes, il ne se déclenche pas jusqu'à ce qu'une heure spécifique soit atteinte.