Partager via


Service ServiceMain, fonction

Lorsqu’un programme de contrôle de service demande qu’un nouveau service s’exécute, le Gestionnaire de contrôle de service (SCM) démarre le service et envoie une demande de démarrage au répartiteur de contrôle. Le répartiteur de contrôle crée un thread pour exécuter la fonction ServiceMain pour le service. Pour obtenir un exemple, consultez Écriture d’une fonction ServiceMain.

La fonction ServiceMain doit effectuer les tâches suivantes :

  1. Initialisez toutes les variables globales.

  2. Appelez immédiatement la fonction RegisterServiceCtrlHandler pour inscrire immédiatement une fonction gestionnaire pour gérer les demandes de contrôle pour le service. La valeur de retour de RegisterServiceCtrlHandler est un handle d’état de service qui sera utilisé dans les appels pour notifier le SCM de l’état du service.

  3. Effectuer l’initialisation. Si le temps d’exécution du code d’initialisation est supposé être très court (moins d’une seconde), l’initialisation peut être effectuée directement dans ServiceMain.

    Si le temps d’initialisation doit être supérieur à une seconde, le service doit utiliser l’une des techniques d’initialisation suivantes :

    • Appelez la fonctionSetServiceStatuspour signaler SERVICE_RUNNING, mais n’acceptez aucun contrôle tant que l’initialisation n’est pas terminée. Pour ce faire, le service appelle SetServiceStatus avec dwCurrentState défini sur SERVICE_RUNNING et dwControlsAccepted défini sur 0 dans la structure SERVICE_STATUS. Cela garantit que le SCM n’envoie aucune demande de contrôle au service avant qu’il soit prêt et libère le SCM pour gérer d’autres services. Cette approche de l’initialisation est recommandée pour les performances, en particulier pour les services de démarrage automatique.

    • Signalez SERVICE_START_PENDING, n’acceptez aucun contrôle et spécifiez un indicateur d’attente. Si le code d’initialisation de votre service effectue des tâches qui sont censées prendre plus de temps que la valeur d’indicateur d’attente initiale, votre code doit appeler régulièrement la fonction SetServiceStatus (éventuellement avec un indicateur d’attente révisé) pour indiquer que la progression est effectuée. Veillez à appeler SetServiceStatus uniquement si l’initialisation progresse. Sinon, le SCM peut attendre que votre service entre dans l’état SERVICE_RUNNING en supposant que votre service progresse et empêche d’autres services de démarrer. N’appelez pas SetServiceStatus d’un thread distinct, sauf si vous êtes sûr que le thread effectuant l’initialisation est réellement en cours.

      Un service qui utilise cette approche peut également spécifier une valeur de point de contrôle et incrémenter périodiquement la valeur pendant une longue initialisation. Le programme qui a démarré le service peut appeler QueryServiceStatus ou QueryServiceStatusEx pour obtenir la dernière valeur de point de contrôle à partir du SCM et utiliser la valeur pour signaler la progression incrémentielle à l’utilisateur.

  4. Une fois l’initialisation terminée, appelez SetServiceStatus pour définir l’état du service sur SERVICE_RUNNING et spécifiez les contrôles que le service est prêt à accepter. Pour obtenir la liste des contrôles, consultez la structure SERVICE_STATUS.

  5. Effectuez les tâches de service ou, s’il n’y a pas de tâches en attente, retournez le contrôle à l’appelant. Toute modification de l’état du service justifie un appel à SetServiceStatus pour signaler de nouvelles informations d’état.

  6. Si une erreur se produit pendant l’initialisation ou l’exécution du service, le service doit appeler SetServiceStatus pour définir l’état du service sur SERVICE_STOP_PENDING si le nettoyage sera long. Une fois le nettoyage terminé, appelez SetServiceStatus pour définir l’état du service sur SERVICE_STOPPED du dernier thread à terminer. Veillez à définir les dwServiceSpecificExitCode et dwWin32ExitCode membres de la structure SERVICE_STATUS pour identifier l’erreur.

écrire une fonction ServiceMain