Wydaje się, że w wersjach systemu Windows późniejszych niż Windows 7 (niezweryfikowany, ale z najnowszego doświadczenia z Windows Server 2012 R2) Menedżer kontroli usług (SCM) jest bardziej rygorystyczny.
Podczas gdy w Windows 7 po prostu spawnuje inny proces, teraz sprawdza, czy proces usługi jest nadal w pobliżu i może zwrócić ERROR_SERVICE_MARKED_FOR_DELETE (1072) dla każdego kolejnego wywołania CreateService / DeleteService, nawet jeśli usługa wydaje się być zatrzymana.
Mówię tutaj o kodzie API systemu Windows, ale chcę jasno opisać, co się dzieje, więc ta sekwencja może prowadzić do wspomnianego błędu:
SC_HANDLE hScm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
SC_HANDLE hSvc = OpenService(hScm, L"Stub service", SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
SERVICE_STATUS ss;
ControlService(hSvc, SERVICE_CONTROL_STOP, &ss);
// ... wait for service to report its SERVICE_STOPPED state
DeleteService(hSvc);
CloseServiceHandle(hSvc);
hSvc = nullptr;
// any further calls to CreateService/DeleteService will fail
// if service process is still around
Powód, dla którego proces serwisowy jest nadal dostępny po tym, jak już zgłosił swój stan SERVICE_STOPPED, nie jest zaskakujący. Jest to zwykły proces, którego główny wątek „utknął” w wywołaniu StartServiceCtrlDispatcher
interfejsu API, więc najpierw reaguje na akcję zatrzymania sterowania, a następnie musi wykonać pozostałą sekwencję kodu.
To trochę niefortunne, że SCM / OS nie radzi sobie z tym poprawnie. Programowe rozwiązanie jest dość proste i dokładne: uzyskaj uchwyt procesu wykonywalnego usługi przed zatrzymaniem usługi, a następnie poczekaj, aż ten uchwyt zostanie zasygnalizowany.
Jeśli podchodzisz do problemu z punktu widzenia administracji systemu, rozwiązaniem jest również poczekanie, aż proces serwisowy całkowicie zniknie.