简体   繁体   中英

Wait for a service to completely Stop / Start before continuing

Ok so... Simple enough. I've actually already gotten this to work for the most part. There are times, however, when the service hasn't actually stopped though the program seems to disagree. The program simply stops a service, copies files from one place to another, then starts a service. The service has a lock on the files being copied so it has to stop.

internal void StopTheService()
    {
        Logger.Log("Stopping the service.");
        lock (myLock) {
            var sc = new ServiceController() { ServiceName = nameOfService, MachineName = nameOfServerWithService };
            sc.Stop();
            sc.WaitForStatus(ServiceControllerStatus.Stopped);
        }
        Logger.Log("Service stopped."); 
    }

internal void StartTheService()
    {
        Logger.Log("Starting the service.");
        lock (myLock) {
            var sc = new ServiceController() { ServiceName = nameOfService, MachineName = nameOfServerWithService };
            sc.Start();
            sc.WaitForStatus(ServiceControllerStatus.Running);
        }
        Logger.Log("Service Started.");
    }

This code works for the most part but issue is that when it thinks the service has stopped and moves on to the next step, the copy, it fails. I can wait for it to stop / start in a while loop like:

while(count<5){
    sc.WaitForStatus(ServiceControllerStatus.Stopped);
    count = count+1;
}

But I think that might fail as well. Everything I've found doesn't on the net doesn't exactly answer my question though my query may be incorrect. The application running this code is a multithreaded environment (hence the lock). If I rerun the application after failing, it works. The error it returns is your typical "file open in another process" error that you get when you try to open another file. Please note that this is a remote environment which has the services and files I'm accessing and yes I do have admin rights so UAC is not the issue.

So the question: How can I be certain that the service has stopped or started completly before continuing? I'm open to almost any solution.

In Response to duplicate Question:

The thing that sets this apart is that it's a remote system that I am accessing in order to perform this work. The question noted as the duplicated question doesn't specify or show a remote scenario. I will test it however and should it succeed I will post it as an answer. However until then it is not a duplicate.

Two solutions:

A. Update the service code to refresh its status on start/end to database or file. Your program reads the status.

B. Your program checks whether the service threads till exist.

Ok so, the answer to duplicated question was the correct answer for the most part. The code on that answer (stackoverflow.com/a/1597244/60188) is mostly correct except for the remote machine parts.

public void StopServiceAndWaitForExit()
    {

        using (var controller = new ServiceController(nameOfService, nameOfServerWithService))
        {
            var ssp = new SERVICE_STATUS_PROCESS();
            int ignored;

            if (!QueryServiceStatusEx(controller.ServiceHandle.DangerousGetHandle(), SC_STATUS_PROCESS_INFO, ref ssp, Marshal.SizeOf(ssp), out ignored))
                throw new Exception("Couldn't obtain service process information.");

            if (ssp.dwServiceType != SERVICE_WIN32_OWN_PROCESS)
                throw new Exception("Can't wait for the service's hosting process to exit because there may be multiple services in the process (dwServiceType is not SERVICE_WIN32_OWN_PROCESS");

            if ((ssp.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS) != 0)
                throw new Exception("Can't wait for the service's hosting process to exit because the hosting process is a critical system process that will not exit (SERVICE_RUNS_IN_SYSTEM_PROCESS flag set)");

            if (ssp.dwProcessId == 0)
                throw new Exception("Can't wait for the service's hosting process to exit because the process ID is not known.");

            using (Process process = Process.GetProcessById(ssp.dwProcessId, nameOfServerWithService))
            {
                var threadData = new ProcessWaitForExitData();

                threadData.Process = process;

                var processWaitForExitThread = new Thread(ProcessWaitForExitThreadProc);

                processWaitForExitThread.IsBackground = Thread.CurrentThread.IsBackground;
                processWaitForExitThread.Start(threadData);

                controller.Stop();

                lock (threadData.Sync)
                    while (!threadData.HasExited)
                        Monitor.Wait(threadData.Sync);
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM