API Windows en C

Les services NT.

CGi

Les services NT. ♪

- Titre : API Windows en C

- Auteur : CGi

- Parution : 21 juin 2006

- Mise à jour : 4 janvier 2013

- Licence : Copyright ® 2006 CGi. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Installation d'un service

- III. Désinstallation d'un service

- IV. Le service

- V. Démarrer un service

- VI. Arrêter un service

I - Introduction

Dans ce chapitre, nous allons aborder les services NT.

Un service est une petite application qui travaille souvent en tâche 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.

II - 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 fournit aussi comme paramètre une chaîne de caractères contenant le chemin et le nom de l'exécutable. C'est évidemment nécessaire au système pour le localiser. Toutes ces données sont enregistrées dans le registre.

1. #include "Windows.h"

2. #include "Winsvc.h"

4. int main()

5. {

6. char strDir[1024];

7. SC_HANDLE hSCManager,hService;

8. SERVICE_DESCRIPTION SD;

9. GetCurrentDirectory(1024,strDir);

10. strcat(strDir,"\\MonService.exe");

11. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

12. hService = CreateService(hSCManager, "MonService", "Mon Service",

13. SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,

14. SERVICE_ERROR_NORMAL, strDir, NULL, NULL, NULL, NULL, NULL);

15. SD.lpDescription = "Ici la description de mon service.";

16. ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &SD);

17. CloseServiceHandle(hService);

19. return 0;

20. }

III - 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.

1. #include "Windows.h"

2. #include "Winsvc.h"

4. int main()

5. {

6. SC_HANDLE hSCManager;

7. SC_HANDLE hServ;

8. hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

9. hServ=OpenService(hSCManager,"MonService",SERVICE_ALL_ACCESS);

10. DeleteService(hServ);

11. CloseServiceHandle(hServ);

12. CloseServiceHandle(hSCManager);

13. return 0;

14. }

IV - 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 prépare l'état que l'on veut 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és 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.

1. #include "Windows.h"

2. #include "Winsvc.h"

4. SERVICE_STATUS ServiceStatus;

5. SERVICE_STATUS_HANDLE hServiceStatus;

6. BOOL ServiceStarted=TRUE;

7. void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);

8. void WINAPI ServCtrlHandler(DWORD Opcode);

10. int main()

11. {

12. SERVICE_TABLE_ENTRY Table[] = {{"Service1",ServiceMain},{NULL,NULL}};

13. StartServiceCtrlDispatcher(Table);

14. return 0;

15. }

16. /******************************************************************************/

18. void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)

19. {

20. ZeroMemory(&ServiceStatus, sizeof(SERVICE_STATUS));

21. ServiceStatus.dwServiceType = SERVICE_WIN32;

22. ServiceStatus.dwCurrentState = SERVICE_START_PENDING;

23. ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

25. hServiceStatus = RegisterServiceCtrlHandler("MonService", ServCtrlHandler);

27. ServiceStatus.dwCurrentState = SERVICE_RUNNING;

28. ServiceStatus.dwCheckPoint = 0;

29. ServiceStatus.dwWaitHint = 0;

31. SetServiceStatus (hServiceStatus, &ServiceStatus);

33. ServiceStarted=TRUE;

34. while(ServiceStarted)

35. {

36. Sleep(5000);

37. /* Ici la tâche à effectuer. */

38. }

39. }

40. /******************************************************************************/

42. void WINAPI ServCtrlHandler(DWORD SCCode)

43. {

44. switch(SCCode)

45. {

46. case SERVICE_CONTROL_CONTINUE:

47. ServiceStatus.dwCurrentState = SERVICE_RUNNING;

48. SetServiceStatus (hServiceStatus,&ServiceStatus);

49. return;

50. case SERVICE_CONTROL_PAUSE:

51. ServiceStatus.dwCurrentState = SERVICE_PAUSED;

52. SetServiceStatus (hServiceStatus,&ServiceStatus);

53. return;

54. case SERVICE_CONTROL_STOP:

55. ServiceStatus.dwWin32ExitCode = 0;

56. ServiceStatus.dwCurrentState = SERVICE_STOPPED;

57. ServiceStatus.dwCheckPoint = 0;

58. ServiceStatus.dwWaitHint = 0;

59. SetServiceStatus (hServiceStatus,&ServiceStatus);

60. ServiceStarted=FALSE;

61. return;

62. }

63. }

V - Démarrer un service

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

1. void StartService()

2. {

3. SC_HANDLE SCMan;

4. SCMan = OpenSCManager(NULL, NULL, GENERIC_EXECUTE) ;

6. SC_HANDLE MonServ;

7. MonServ = OpenService(SCMan, "MonService", SERVICE_START );

9. StartService(MonServ, 0, NULL);

11. CloseServiceHandle(MonServ);

12. CloseServiceHandle(SCMan);

13. }

VI - Arrêter un service

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

1. void StopService()

2. {

3. SERVICE_STATUS_PROCESS ssp;

5. SC_HANDLE SCMan;

6. SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) ;

8. SC_HANDLE MonServ;

9. MonServ = OpenService(SCMan, "MonService", SERVICE_STOP );

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

13. CloseServiceHandle(MonServ);

14. CloseServiceHandle(SCMan);

15. }

J'ai omis pour faciliter la comphéantion de tester la validité des valeurs retournées par certaines 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.

À vos PC.

CGi

Retour au sommaire.