Skip Navigation Links
Accueil
Java Standard EditionExpand Java Standard Edition
Java EE 5Expand Java EE 5
Visual Basic .Net 2005Expand Visual Basic .Net 2005
Visual C++ .Net 2005Expand Visual C++ .Net 2005
Visual C# .Net 2005Expand Visual C# .Net 2005
Cours ASP .Net 2.0Expand Cours ASP .Net 2.0
PostgresqlExpand Postgresql
LinuxExpand Linux
Visual Studio 2008Expand Visual Studio 2008
ASP 3.0 ClassiqueExpand ASP 3.0 Classique
Cours Javascript - DOM - DHTMLExpand Cours Javascript - DOM - DHTML
Cours AjaxExpand Cours Ajax
VBAExpand VBA
AssembleurExpand Assembleur
PerlExpand Perl
MembresExpand Membres
L'auteur du site
Nouveautés sur le site
Contacts
Plan du site
Accueil > Visual C# .Net 2005 > III Les services Windows
____________________________________________________________________________________________________
Connexion

III) LES SERVICES WINDOWS

III.1) Généralités

III.2) Création d'un service Windows

III.3) La classe Service1

III.4) La classe Program

III.5) Installation d'un service Windows

III.6) Ajouter la classe ProjectInstaller

III.7) Création du programme d'installation

III.8) Génération et utilisation de l'installation

III.9) Installation en ligne de commande

III.1) GENERALITES

  Les services Windows sont des applications particulières. On les appelait auparavant "services NT". Ce sont des programmes qui tournent en tâche de fond, et qui exécutent une certaine tâche. Les services Windows peuvent démarrer soit au démarrage de l'ordinateur, soit à la demande. Cette notion de service Windows répond à un besoin. En effet, dans certains cas, on peut avoir besoin d'un programme qui marche en arrière-plan et qui nous rend un certain service.
  Il existe un gestionnaire des services windows, accessible par Démarrer->Panneau de configuration->Performances et maintenance->Outils d'administration->Services . On peut aussi l'avoir par Démarrer -> Exécuter -> services.msc .  Cet interface s'appelle le gestionnaire de contrôle des services. Grâce à ce gestionnaire, on peut effectuer les tâches courantes sur les services: avoir la liste des services Windows, leur description, leur état( démarré, arrêté ), leur mode de démarrage( automatique, manuel, ...).
  Windows XP possède ses propres services Windows pour ses besoins personnels. Ainsi le service "Mises à jour automatiques" de Windows, comme l'indique sa description, se charge d'activer le téléchargement et l'installation des mises à jour Windows. Vous saviez bien que ces mises à jour de Windows étaient effectuées par un programme en arrière-plan, car elles avaient lieu en même temps que vous travailliez! Et bien, c'est ce service qui fait cela! Cela vous montre bien que ce concept de "service windows" est nécessaire pour certains besoins.
  Un service Windows ne possède pas d'interface utilisateur. Il n'est pas fait pour cela. Cet absence d'interface correspond bien à une utilisation sur un serveur. Car les services windows sont souvent utiles sur un serveur( mais pas uniquement).
Si vous désirez écrire un résultat, vous pouvez le faire dans  le journal des événements Windows( nous en reparlerons, ceci est très utile, et très couramment utilisé. C'est un moyen pour votre service de communiquer). Votre service peut également envoyer un mail à l'administrateur.
  Il est possible de créer vos propres services en c# .net. Nous allons voir comment procéder.

III.2) Création d'un service Windows


  Dans Visual Studio 2005, allez dans File -> New -> Project . Dérouler le noeud C#( sinon on n'a pas accès aux services Windows). Dans le noeud C#, choisir la branche "Windows". Puis choisir "Windows Service" dans les modèles proposés. Nous allons donc créer un nouveau projet, correspondant à notre service Windows. Comme nous ne disposions pas de solution, une nouvelle solution sera également créée. Mais nous aurions très bien pu ajouter notre projet à une solution existante. Appelons notre projet "WindowsService1".

  Parmi les dossiers créés, nous constatons un dossier "Properties", et un dossier "References". Ces 2 dossiers nous sont familiers par les applications Windows. "Properties" contient uniquement le classique "AssemblyInfo.cs", contenant les informations à propos du projet. Le dossier "References" contient les .dll utilisées par le projet.
En-dehors de ces 2 dossiers qui nous intéressent moins, nous avons un fichier Program.cs, qui contient la méthode main, point d'entrée de l'application. C'est une méthode static, qui appartient à une classe appelée "Program".

Ce qui nous concerne surtout, c'est le fichier Service1.cs.

III.3) La classe Service1

  Dans le fichier "Service1.cs" figure la classe Service1( appelée Service1 par défaut). Cette classe dérive de la classe ServiceBase( System.ServiceProcess.ServiceBase). ServiceProcess est un espace de nom. ServiceBase est la classe qui représente les services Windows. Pourquoi ne pas créer directement un objet de la classe ServiceBase? C'est parce qu'on va avoir besoin de redéfinir certaines méthodes de la classe ServiceBase. Et on pourra également définir notre propre constructeur.

  Nous allons voir plus précisément ces méthodes qui nous concernent, ainsi que le constructeur.

III.3.1) La méthode OnStart

  Parmi les méthodes générées automatiquement figure la méthode OnStart.

III.3.1.a) DEFINITION: le mot-clé "override":


  J'en profite pour vous définir le mot-clé "override".
  Nous remarquons "override" après le "protected". "override" signifie en Anglais: "ne pas tenir compte de", et c'est exactement cela: on indique qu'on redéfinit cette méthode de la classe de base. La méthode redéfinie doit avoir la même signature que la méthode de la classe de base.
  On ne peut faire "override" sur une méthode que si c'est une méthode virtual ou abstract, ou elle-même override. Ce qui est logique: il faut que le concepteur de la classe de base ait prévu qu'on puisse la rééecrire. "Abstract" signifie que le contenu de la méthode n'a pas été écrit du tout, alors que pour "virtual" le contenu de la méthode est écrit, mais on précise que cette méthode peut être redéfinie par une classe dérivée. On se doute bien que les concepteurs de la classe ServiceBase ne pouvaient pas écrire la méthode OnStart, car elle dépend de chaque service. Donc ils l'ont écrite en abstract, ou virtual.

  La méthode OnStart est la méthode qui sera appelée lors du démarrage de votre service Windows. Placez-y le code que vous souhaitez voir exécuter lors du démarrage du service.

III.3.2) La méthode OnStop


  La méthode OnStop, elle aussi en override, et la méthode qui sera appelée à l'arrêt du service. A vous donc d'y placer ce que vous désirez.

III.3.3) Le constructeur de la classe service1


  Le constructeur de la classe service1 contient un appel à la méthode InitializeComponent( ). Cette méthode se trouve dans le fichier "Service1.Designer.cs", qui contient une partie de la définition de la classe Service1.

III.3.3.a) DEFINITION: le mot-clé "partial"


  Profitons-en pour définir le mot-clé "partial".
  Il peut être intéressant de découper une définition de classe dans deux ou plusieurs fichiers, afin d'en faciliter la lecture. On peut faire cette séparation d'après le sens de ce qu'on met dans une partie ou dans l'autre. On pourra, par exemple, mettre les éléments secondaires dans un fichier à part, afin de clarifier la classe. Le mot-clé partial veut uniquement dire qu'on ne définit pas la classe dans sa totalité, mais juste une partie de la classe. Le reste de la classe se trouve dans un ou plusieurs autres fichiers. Dans notre cas, la classe Service1 est découpée en deux: une partie( la plus importante et la plus significative) dans le fichier Service1, et l'autre partie dans le fichier Service1.Designer.cs . Le mot clé "partial" figure dans chacune des deux définitions de classe.

  Le fichier Service1.Designer.cs possède notamment la méthode InitializeComponent( ). Dans cette méthode d'initialisation, nous trouvons:

this.ServiceName = "Service1";
Ici on définit la propriété name du service Windows. Nommez le comme vous voulez, mettons par exemple this.ServiceName = "NomService";
C'est de cette façon que Windows désignera votre service quand il vous en parlera ( par exemple dans l'observateur d'évènement lors du démarrage ou de l'arrêt). Nous verrons l'observateur d'évènement bientôt.

III.4) La classe program


Le fichier program.cs contient la classe program . Cette classe program contient un seul élément: une méthode main. Cette méthode est déclarée static ( elle peut par conséquent être appelée directement, sans avoir d'objet de la classe program). Ce main est le point d'entrée de l'application. Nous savons bien que toute application a besoin d'un point d'entrée, sinon l'ordinateur ne saurait pas où elle commence.

  Dans ce main, on aurait pu faire:

//on aurait pu faire
ServiceBase monService;
monService = new Service1( );
ServiceBase.Run(monService);

Dans le code ci-dessus, on crée d'abord un objet de notre classe Service1.
Puis on appelle la méthode statique Run, de la classe ServiceBase.
Cette méthode est nécessaire pour commencer l'exécution du service. Elle charge en mémoire le code des méthodes du service( même si on aurait pu croire que théoriquement ce code était déjà dans l'objet, car la méthode OnStart est une méthode de l'objet. Mais dans la pratique, le code est chargé au moment du Run, car c'est à ce moment qu'on en aura besoin. Le code des méthodes ne figure pas dans chaque objet en réalité, car ce serait une répétition inutile).
Après avoir chargé le code, la méthode Run appelle la méthode OnStart de monService.

Pourquoi ce main est-il indispensable, et pourquoi ne pas appeler directement la méthode OnStart, au lieu d'appeler le main? Et bien, tout simplement parce que l'objet monService n'avait pas encore été créé! Donc on ne pouvait pas appeler sa méthode OnStart!

  Revenons au code généré automatiquement par Visual Studio. Il est un peu différent du mien. Car le cas du démarrage de plusieurs services est prévu; moi je ne me suis occupé que du cas d'un unique service. En effet, la méthode Run a une surchage autorisant le démarrage de plusieurs services. Il suffit de lui passer un tableau d'objet de la classe ServiceBase. Il faut ainsi lui donner un ServiceBase[].

ServicesToRun = new ServiceBase[] { new Service1() };

Cette ligne crée un tableau de services. Et elle initialise ce tableau avec un seul élément: avec un objet de la classe Service1. Le new Service1 crée le service. L'objet créé est rangé dans le tableau de services, à l'indice 0. La méthode Run va lancer chacun des services du tableau qu'on lui passe en paramètre.

  On remarquera que notre application peut exécuter plusieurs services en parallèle. Par conséquent, on en conclut que chaque service sera lancé dans un nouveau thread. Mais tous ces services( du tableau ServicesToRun) appartiendront bien sûr à la même application.

III.5) Installation d'un service Windows


  Nous avons appris comment créer un service, mais pour pouvoir utiliser un service, il faut l'avoir installé auparavant dans Windows XP. Pourquoi cette installation? Parce que le système d'exploitation a besoin qu'on lui déclare les services windows, afin par exemple de pouvoir vous en afficher la liste. L'installation a lieu une fois pour toute, comme lorsque vous installez une nouvelle application avec un programme d'installation. D'ailleurs l'installation se fera avec le classique Windows Installer, car Visual Studio vous aura créé des fichiers pour Windows Installer.

  Comment générer ces fichiers pour Windows Installer? C'est ce que nous allons voir.

III.6) Ajouter la classe ProjectInstaller


  Un service Windows doit contenir, dans son projet, une classe ProjectInstaller qui hérite de la classe Installer. Cette classe contient les informations utiles sur le service, afin de permettre à "celui"( cela peut être un installeur Windows installer) qui voudra l'installer d'avoir les données( sur le service) dont il a besoin pour l'installer. Au moment où le service sera "déclaré" à Windows( pour que, par exemple, on puisse le voir dans la liste des services affichée par le gestionnaire de contrôle des services), "celui" qui l'installera ira chercher dans cette classe les informations( sur le service) lui étant nécessaires. Voilà ce que j'entends ici par "installer", et cela n'a rien à voir avec la création d'un programme d'installation. Cette classe permet uniquement de définir les caractéristiques de notre service. Ces caractéristiques du service sont les suivantes. Par exemple: le type de démarrage( automatique, manuel), le nom du service, la machine sur laquelle s'exécute le service, etc. La classe ProjectInstaller est uniquement, finallement, un complément à la définition de notre service faite par la classe ServiceBase. Dans la classe ProjectInstaller, on y mettra plutôt toutes les informations sur le service qui ont rapport avec son installation. C'est uniquement un découpage en deux objets( Service1 et ProjectInstaller), au lieu d'en faire un seul, par souci de faire une belle programmation objet. Mais les concepteurs des classes auraient pu regrouper ces deux classes en une seule grande classe "Service".

  Comment ajouter cette classe? Cela est très simple. Il suffit d'aller dans la vue design de votre service( le fichier service1.cs). Puis vous effectuez un clic droit, et vous choisissez "Add installer". Cela vous crée un fichier ProjectInstaller1.cs, qui contient une classe ProjectInstaller( héritant de la classe Installer). Cette classe contient deux attributs privés, qui sont serviceInstaller1 et serviceProcessInstaller1. Ces deux composants sont d'ailleurs visibles dans la vue design de ProjectInstaller1. Ces deux attributs apparaissent dans le fichier ProjectInstaller1.Designer.cs. Ce sont respectivement des objets de la classe ServiceProcessInstaller et de la classe ServiceInstaller. ServiceInstaller permet de définir des caractéristiques du service  lui-même( son type de démarrage, etc), afin de pouvoir "l'installer" au mieux. ServiceProcessInstaller fait de même, mais il définit lui des caractéristiques en rapport avec le processus du service, comme la machine sur laquelle le processus va tourner. Là aussi, c'est un découpage (en deux classes) qui a été choisi par souci de faire une belle( et pratique) programmation orientée objet.
  Nous allons définir dans le design( mais on peut le faire par code), les propriétés ServiceName et StartType de ServiceInstaller1

ServiceInstaller1.ServiceName => "NomService"
ServiceInstaller1.StartType => manual

  Nous allons définir les propriétés suivantes de ServiceProcessInstaller1:

ServiceProcessInstaller1.Account = LocalSystem

III.7) Création du programme d'installation


  Nous devons maintenant créer un programme d'installation. Un exécutable qui installera notre service dans le système d'exploitation. Ce programme d'installation ressemblera à n'importe quel programme d'installation d'application, et sera un programme compatible avec l'installeur Windows Installer. Une fois installé, votre application sera d'ailleurs visible dans la liste des applications de Panneau de configuration -> Ajout/Suppression de programmes. Et vous pourrez aussi le supprimer à partir de cette liste, comme n'importe quelle application.

  La marche à suivre est de créer un projet de configuration, qui sera un nouveau projet qui s'ajoutera à notre solution( le 2eme projet de notre solution).
  Pour créer un projet de configuration, faites File -> Add -> New Project . Puis dérouler le noeud Other Project Types. Puis cliquer sur "setup et deployment". Il faut alors choisir le type "Setup Project". Mettez "SetupService" comme nom de projet. Un nouveau projet est ajouté à la solution "WindowsService1".

  En faisant un clic droit sur le nom du projet, nous avons un menu contextuel qui s'ouvre. Il nous donne diverses possibilités. Nous allons choisir "Actions personnalisées"( "Customs Actions"), accessible par "View" puis "Customs Actions".
Quatre petits dossiers s'affichent dans le design: "Install", "Commit", "Rollback", "Uninstall". Nous avons alors la possibilité de choisir une action personnalisée à propos notamment de l'installation et de la désinstallation. Faites un clic droit sur "Install", choisissez "Custom actions". Puis double-cliquez sur "Application folder"( dossier d'application), ou sélectionnez le dans la liste déroulante. Puis cliquez sur "Add output',  et sur "Primary output"( sortie principale), qui est la sortie principale de l'application, c'est à dire le .exe du projet "WindowsService1". Nous venons simplement de dire que l'installation à faire sera l'installation du .exe du projet ServiceWindows1 ! Nous avons donc personnalisé l'installation, d'où le terme "action personnalisée".

  Faites de même pour "Uninstall": clic droit "custom actions", puis "Application folder", puis "Add output", et après "Primary output".
  Dans le design, sous "Install" se trouve affiché "Primary output from Windows Service1". Et sous "Uninstall" se trouve affiché "Primary output from Windows Service1". Ceci est bien ce que l'on voulait. Cela veut simplement signifier qu'on déclare que lors de l'installation, on souhaite installer l'exécutable généré pour le projet Windows Service1. C'est juste une déclaration de ce qu'on veut installer! Pareil pour la désinstallation: on a juste déclaré qu'on veut désinstaller le .exe du projet Windows Service1, lors de l'action de désinstallation.

III.8) Génération et utilisation de l'installation


  Il ne reste plus qu'à générer chaque projet( build). D'abord le projet ServiceWindows1( par un clic droit sur le nom du projet dans l'explorateur de solutions, puis "build"). Puis générez le projet "SetupService".

  Une fois généré, le projet ServiceWindows1 donne un exécutable: "ServiceWindows1.exe". Et le projet "SetupService" donne "SetupService.msi", et également "SetupService.exe". "SetupService.msi" est strictement identique (en résultat) à SetupService.exe. Donc vous devez lancer soit l'un, soit l'autre pour installer le service. La différence c'est que setup.exe n'a pas besoin du logiciel Windows Installer pour fonctionner, au contraire de SetupService.msi .

Remarques: - si vous modifiez ServiceWindows1, et que vous le générez après, il est nécessaire de générer aussi SetupService, même s'il n'a pas été modifié. En effet, rappelez vous, le projet SetupService se sert de la sortie principale du projet ServiceWindows1. Et, de plus, c'est quand même un programme d'installation de votre exécutable: il sera donc adapté à votre exécutable.
  Vérifiez, en cas de problème à l'installation( si on vous demande un nom d'utilisateur et un mot de passe), que la propriété Account du ServiceProcessInstaller1 est bien à "LocalSystem", et pas à "user".

III.9) Installation en ligne de commande


  Il est possible d'installer les services autrement que par Windows Installer. On peut en effet ne pas créer le deuxième projet "SetupService", et juste créer le projet "ServiceWindows1". L'installation se fera dans une console DOS, grâce à l'utilitaire InstallUtil.exe du framework.

  InstallUtil.exe se trouve dans c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727( en dernier c'est votre version de framework).

Ouvrez donc une console DOS par Accessoires->Invite de commandes, ou par Exécuter->cmd .
Puis tapez:
InstallUtil.exe "c:\(...votre chemin...)\ServiceWindows1.exe(nom de votre exécutable)" 
Ceci installera votre service.

  Pour le désinstaller, il suffit d'ajouter l'option /u :

InstallUtil.exe /u "c:\(...votre chemin...)\ServiceWindows1.exe(nom de votre exécutable)" .

  Avec cette méthode, l'application n'est pas visible dans la liste des programmes de Ajout/Suppression de programmes. Mais votre service figurera bien sûr dans le gestionnaire de contrôle des services.
 
RETOUR HAUT