Blog ENI : Toute la veille numérique !
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée
  1. Livres et vidéos
  2. Delphi 10.3
  3. Création d’un service Windows
Extrait - Delphi 10.3 Programmation orientée objet en environnement Windows
Extraits du livre
Delphi 10.3 Programmation orientée objet en environnement Windows
9 avis
Revenir à la page d'achat du livre

Création d’un service Windows

Définition

Un service Windows est un programme qui fonctionne en arrière-plan. Son mode de fonctionnement est similaire à un daemon Unix. Par rapport à un programme positionné dans l’AutoRun, son avantage est qu’il ne nécessite pas qu’un utilisateur soit logué pour qu’il démarre.

D’un point de vue général, un service est dédié à des traitements qui ne nécessitent aucune interaction utilisateur. Avant Windows Vista, il était possible de faire interagir un service avec le bureau Windows si un utilisateur était logué mais depuis Windows Vista, Microsoft a décidé d’isoler l’exécution des services dans la session 0 où aucun utilisateur ne peut interagir. Il existe des astuces de codage pour contourner cette limitation si le développeur doit garder ce mode interactif dans un environnement supérieur à Windows Vista. Dans ce cas, il est conseillé de revoir le design de l’application pour garder l’exécution du service en session 0 en prévoyant une autre application de type form en session utilisateur qui pilote le service.

Dans les versions serveurs récentes de Windows (Windows Server 2016 ou ultérieure), la configuration de l’OS peut provoquer des erreurs système quand on essaye de créer une fenêtre...

Configuration

La configuration d’un service permet de définir son type d’exécution, le compte auquel il est associé et les dépendances éventuelles du service.

1. Configuration du type d’exécution

Il existe quatre types d’exécution :

  • Automatique : le service démarrera dès que le système d’exploitation sera initialisé.

  • Automatique (début différé) : similaire à Automatique, mais les services en début différé démarreront après les services en automatique.

  • Manuel : le service démarrera si un utilisateur ou un autre programme demande le démarrage du service.

  • Désactivé : le service ne peut pas être démarré.

2. Configuration du compte associé

L’exécution d’un service nécessite un contexte d’exécution. Comme il est possible qu’aucun utilisateur ne soit logué, un compte de l’ordinateur local ou même un compte de domaine sera associé au service. Ainsi, le service s’exécutera avec les mêmes droits que les droits du compte auquel il est rattaché, comme s’il s’agissait de cet utilisateur qui avait lancé manuellement le programme. 

Par défaut, quand un service est installé, son compte d’exécution...

Implémentation

Microsoft a fourni tout un développement Pack pour implémenter et utiliser un service à partir de Windows NT 3.51. Il s’agit du Service Control Manager qui expose un nombre important d’API. Delphi XE fournit tout un framework rendant l’utilisation de service beaucoup plus simple.

Ainsi, pour créer un service, utilisons le wizard fourni par Delphi en le faisant apparaître par File - New - Other et choisissons Windows Service dans l’arborescence Delphi - Windows comme dans la capture ci-dessous :

images/09EP01.png

Delphi génère un fichier dpr et un fichier source pascal.

Le fichier dpr se présente ainsi :

program ServiceExemple; 
 
uses 
 Vcl.SvcMgr, 
 UServiceExemple in 'UServiceExemple.pas' {Service1: TService}; 
 
{$R *.RES} 
 
begin 
 if not Application.DelayInitialize or Application.Installing then 
 Application.Initialize; 
 Application.CreateForm(TService1, Service1); 
 Application.Run; 
end. 

On remarque que le type de binaire est un programme (program). Lors de la sauvegarde, le nom ServiceExemple a été choisi. Le binaire qui sera généré sera ServiceExemple.exe, mais cela ne sera pas forcément le nom publié dans le gestionnaire de service.

On remarque aussi l’inclusion de l’unité Vcl.SvcMgr qui porte l’encapsulation des API Windows permettant de manipuler les services.

Le fichier source, quant à lui, se présente ainsi :

unit UServiceExemple; 
 
interface 
 
uses 
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 
Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs; 
 
type 
 TService1 = class(TService) 
 private 
 public 
   function GetServiceController: TServiceController; override; 
   { Déclarations publiques } 
 end; 
 
var 
 Service1: TService1; 
 
Implementation 
{$R *.dfm} 
 
procedure ServiceController(CtrlCode: DWord); stdcall; 
begin 
 Service1.Controller(CtrlCode); 
end; 
 
function TService1.GetServiceController: TServiceController; 
begin 
 Result := ServiceController; 
end; ...

Débogage de service Windows

1. Par fichier de log

Dans tous les cas de figure, il est nécessaire de munir son propre service d’un mécanisme de log dans un ou plusieurs fichiers tournants. Dans l’exemple ci-dessus, le log était dirigé dans la console par facilité, mais cette implémentation n’est pas pérenne car on ne peut pas revenir a posteriori sur un problème. L’intérêt de loguer dans un fichier est de pouvoir stocker de manière durable l’activité du programme.

Chaque ligne de log doit être munie d’un indicateur de temps et du ThreadId qui permet de tracer au plus fin l’activité de chaque thread du programme.

Ci-dessous est proposé un exemple de classe de log tournant. Le paramétrage est constitué par son chemin jusqu’à son nom racine, l’extension du fichier log (en général .log ou .txt), la taille maximale du fichier et son nombre maximal concurrent sur le disque dur.

unit ULog; 
 
interface 
 
uses Classes,System.IOUtils,SyncObjs; 
 
type TLog = class(TObject) 
 private 
   FFileName:string; 
   FFileExt:string; 
   FMaxFileCount: int64; 
   FMaxFileSize : int64; 
   FCurrentFileIndex:integer; 
   FCurrentCompleteFileName:string; 
   FLock:TCriticalSection; 
   FWriter:TStreamWriter; 
   FStream:TFileStream; 
   function GetCurrentFileSize:int64; 
   function DetectLogToComplete:integer;  
   procedure RotateFileName; 
   procedure OpenLog; 
   procedure CloseLog; 
 public 
   constructor Create(aFileName, 
aFileExtension:string; 
aFileSize,afilecount:int64); reintroduce; 
   destructor Destroy;override; 
   procedure WriteLog(aTextLine:string); 
end; 
  • Ci-dessus est écrite la définition de la classe. On remarque tous les paramètres de la classe, à savoir :

  • FFileName : le chemin et le nom du fichier sans l’extension (c:\tmp\mylog’). 

  • FFileExt : l’extension du fichier.

  • FMaxFileCount : le nombre maximum de fichiers présents sur le disque dur.

  • FMaxFileSize : la taille maximale du fichier...

Conclusion

Les règles d’implémentation des services Windows ont été abordées. Il est aussi nécessaire d’avoir quelques notions d’administration pour éviter certains pièges comme les accès à des répertoires protégés tel C:\Program Files (x86). Pour maintenir et déboguer un service, il est nécessaire de loguer au maximum l’activité du programme afin d’identifier au mieux les dysfonctionnements éventuels.