Partager via


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 une fonction Handler afin de gérer les demandes de contrôle pour le service. La valeur de retour de RegisterServiceCtrlHandler est un handle de service status qui sera utilisé dans les appels pour notifier le SCM du service status.

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

    Si la durée d’initialisation est censée être supérieure à une seconde, le service doit utiliser l’une des techniques d’initialisation suivantes :

    • Appelez la fonction SetServiceStatus pour 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 ne 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 devraient prendre plus de temps que la valeur d’indicateur d’attente initiale, votre code doit appeler la fonction SetServiceStatus régulièrement (éventuellement avec un indicateur d’attente révisé) pour indiquer que la progression est en cours. 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 bloquer le démarrage d’autres services. N’appelez pas SetServiceStatus à partir d’un thread distinct, sauf si vous êtes sûr que le thread qui effectue l’initialisation progresse vraiment.

      Un service qui utilise cette approche peut également spécifier une valeur de point de case activée et incrémenter la valeur régulièrement pendant une initialisation longue. Le programme qui a démarré le service peut appeler QueryServiceStatus ou QueryServiceStatusEx pour obtenir la dernière valeur case activée point 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écifier 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 status.

  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 est long. Une fois le nettoyage terminé, appelez SetServiceStatus pour définir l’état du service sur SERVICE_STOPPED à partir du dernier thread à terminer. Veillez à définir les membres dwServiceSpecificExitCode et dwWin32ExitCode de la structure SERVICE_STATUS pour identifier l’erreur.

Écriture d’une fonction ServiceMain