Developpez.com - C
X

Choisissez d'abord la catégorieensuite la rubrique :



API Windows en C

Les services NT.

Par CGi

Le 21 juin 2006




Introduction :

Dans ce chapitre, nous allons aborder les services NT.
Un service est une petite application qui travaille souvent en tache de fond. Les applications services sont enregistrées dans une base de données et gérées par une application le "Service Control Manager". Elles peuvent être lancées automatiquement au démarrage du système ou manuellement par une autre application ou un autre service.


Installation d'un service :

Avant d'être utilisé un service doit être installé. C'est à dire enregistré par le système. C'est le rôle de la fonction CreateService qui reçoit notamment comme paramètres le nom d'enregistrement du service, "MonService" dans l'exemple. Il est enregistré sous forme d'une chaîne de caractère. C'est ce nom qui nous servira à accéder ultérieurement à ce service. Nous avons comme autre paramètre le libellé du service et diverses constantes lui affectant certaines caractéristiques (voir aide API Win32). On peut remarquer que l'on fournie aussi comme paramètre une chaîne de caractère contenant le chemin et le nom de l'exécutable. C'est évidement nécessaire au système pour le localiser. Toutes ces données sont enregistrées dans le registre.


#include "Windows.h"
#include "Winsvc.h"

int main()
{   
    char strDir[1024];
    SC_HANDLE hSCManager,hService;
    SERVICE_DESCRIPTION SD;
    GetCurrentDirectory(1024,strDir);
    strcat(strDir,"\\MonService.exe");
    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    hService = CreateService(hSCManager, "MonService", "Mon Service",
       SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
                    SERVICE_ERROR_NORMAL, strDir, NULL, NULL, NULL, NULL, NULL);
    SD.lpDescription = "Ici la description de mon service.";
    ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &SD);
    CloseServiceHandle(hService);

    return 0;
}



Désinstallation d'un service :

Voyons brièvement sa désinstallation. Elle s'effectue avec la fonction DeleteService après avoir ouvert le service avec OpenService.

#include "Windows.h"
#include "Winsvc.h"

int main()
{
    SC_HANDLE hSCManager;
    SC_HANDLE hServ;
    hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    hServ=OpenService(hSCManager,"MonService",SERVICE_ALL_ACCESS);
    DeleteService(hServ);
    CloseServiceHandle(hServ);
    CloseServiceHandle(hSCManager);
    return 0;
}



Le service :

Au démarrage d'un service l'exécutable est lancé et sa fonction main exécutée. Dans cette fonction main nous devons remplir un tableau de structure SERVICE_TABLE_ENTRY. Une case du tableau par service (un exécutable peut contenir plusieurs services). Le premier champ de la structure contient la chaîne de caractères identifiant le service. Le deuxième contient un pointeur de fonction sur la fonction principale du service. La dernière structure du tableau doit avoir ses champs à NULL.

Voyons maintenant la fonction d'exécution du service, nommée "ServiceMain" dans l'exemple. Dans cette fonction nous remplissons la structure ServiceStatus de type SERVICE_STATUS. Cette structure prepare l'état que l'on veux donner au service pendant son exécution.
Nous devons aussi implémenter une autre fonction nommée "ServCtrlHandler" dans l'exemple, dont on fournira un pointeur à la fonction RegisterServiceCtrlHandler afin de l'enregistrer. Le Service Control Manager pourra alors lui envoyer des ordres, que cette fonction devra traiter.
Les changements d'état affectés en cours d'exécution dans la structure ServiceStatus doivent être validé par l'appel de la fonction SetServiceStatus. Son premier paramètre est un handle renvoyé par la fonction RegisterServiceCtrlHandler et le second est l'adresse de la structure ServiceStatus. Ensuite on entre dans une boucle qui s'exécute tant que le service est démarré. C'est dans cette boucle que l'on implémente les actions que l'on désire exécuter.

#include "Windows.h"
#include "Winsvc.h"

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hServiceStatus;
BOOL ServiceStarted=TRUE;
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void WINAPI ServCtrlHandler(DWORD Opcode);

int main()
{
    SERVICE_TABLE_ENTRY Table[] = {{"Service1",ServiceMain},{NULL,NULL}};
    StartServiceCtrlDispatcher(Table);
    return 0;
}
/******************************************************************************/

void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{ 
    ZeroMemory(&ServiceStatus, sizeof(SERVICE_STATUS));
    ServiceStatus.dwServiceType = SERVICE_WIN32;
    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

    hServiceStatus = RegisterServiceCtrlHandler("MonService", ServCtrlHandler);

    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint = 0;

    SetServiceStatus (hServiceStatus, &ServiceStatus);

    ServiceStarted=TRUE;
    while(ServiceStarted)
     {
       Sleep(5000);
       /* Ici la tache à éffectuer. */
     }
}
/******************************************************************************/

void WINAPI ServCtrlHandler(DWORD SCCode)
{
    switch(SCCode)
     {
      case SERVICE_CONTROL_CONTINUE:
          ServiceStatus.dwCurrentState = SERVICE_RUNNING;
          SetServiceStatus (hServiceStatus,&ServiceStatus);
          return;
      case SERVICE_CONTROL_PAUSE:
          ServiceStatus.dwCurrentState = SERVICE_PAUSED;
          SetServiceStatus (hServiceStatus,&ServiceStatus);
          return;
      case SERVICE_CONTROL_STOP:
          ServiceStatus.dwWin32ExitCode = 0;
          ServiceStatus.dwCurrentState = SERVICE_STOPPED;
          ServiceStatus.dwCheckPoint = 0;
          ServiceStatus.dwWaitHint = 0;
          SetServiceStatus (hServiceStatus,&ServiceStatus);
          ServiceStarted=FALSE;
          return;
     }
}



Démarrer un service :

Un service peut ce démarrer automatiquement ou manuellement selon sa configuration. Pour le démarrer manuellement par programme, il suffit ouvrir le service et de le démarrer avec la fonction StartService.

void StartService()
{
    SC_HANDLE SCMan;
    SCMan = OpenSCManager(NULL, NULL, GENERIC_EXECUTE) ;

    SC_HANDLE MonServ;
    MonServ = OpenService(SCMan, "MonService", SERVICE_START );

    StartService(MonServ, 0, NULL);

    CloseServiceHandle(MonServ);
    CloseServiceHandle(SCMan);
}



Arrêter un service :

Un service peut de même être arrêté par programme à l'aide de la fonction ControlService. A savoir que si des services dépendent de votre service, ils doivent être arrêtés avant l'arrêt de votre service.

void StopService()
{
    SERVICE_STATUS_PROCESS ssp;

    SC_HANDLE SCMan;
    SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) ;

    SC_HANDLE MonServ;
    MonServ = OpenService(SCMan, "MonService", SERVICE_STOP );

    ControlService( MonServ, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS) &ssp ) ;

    CloseServiceHandle(MonServ);
    CloseServiceHandle(SCMan);
}

J'ai omis pour faciliter la comphéantion de tester la validité des valeurs retournées par certaine des fonctions de cet exemple.
J'ai testé les compilations avec C++ Builder et DevC++.
N'hésitez pas à consulter la msdn pour de plus amples renseignements sur les services.

A vos PC.

CGi



Sommaire



C/C++
  Les pointeurs du C/C++.   Les listes chaînées.             Liste simple.             Liste triée.             Liste double.   Les arbres.   Les tas.   Le C orienté objets ?

  1 - La fenêtre principale.   2 - Contrôles et messages.   3 - Les commandes.   4 - Dialogue std.   5 - Contexte de périph.   6 - Dessiner.   7 - Les ressources.   8 - Dialogue perso.   9 - Dialogue comm.   10 - Les accélérateurs.

Assembleur
  Assembleur sous Visual C++.

C++ BUILDER
  Trucs et astuces.   Composant.   TRichEdit.   TDrawGrid.   Application MDI.   TThread.   wxWidgets.   Style Win XP.

  Première application.   Construire un menu.   Dessiner.   Sisers, Timers...   Dialogues standards.   Dialogues perso.

DotNet
  Composant C# Builder.   Contrôle WinForm.   Application MDI.

Java
  Applet java.





Copyright 2002-2016 CGi - Tous droits réservés CGi. Toutes reproduction, utilisation ou diffusion de ce document par quelque moyen que ce soit autre que pour un usage personnel doit faire l'objet d'une autorisation écrite de la part de l'auteur, propriétaire des droits intellectuels.
Les codes sources de ce document sont fournis en l'état. L'utilisateur les utilise à ses risques et périls, sans garantie d'aucune sorte de la part de l'auteur. L'auteur n'est responsable d'aucun dommage subi par l'utilisateur pouvant résulter de l'utilisation ou de la distribution des codes sources de ce document.
De la même façon, l'auteur n'est en aucun cas responsable d'une quelconque perte de revenus ou de profits, ou de données, ou de tous dommages directs ou indirects, susceptibles de survenir du fait de l'utilisation des codes sources de ce document, quand bien même l'auteur aurait été averti de la possibilité de tels dommages. L'utilisation des codes sources de ce document vaut acceptation par l'utilisateur des termes de la licence ci-dessus.

Contacter le responsable de la rubrique C