简体   繁体   中英

How to wait on a system process from a user process?

I have a .net Windows Service running as Local System. I have another .net process that needs to wait for the service to terminate. That process does not know the service name so it can't query the service control manager. It does know the service process Id. I can modify sources of both the windows service and the other process.

When I do:

process = Process.GetProcessById(processId);
process.WaitForExit();

from the other process, I'm getting:

System.ComponentModel.Win32Exception: Access is denied

Stack trace: 
  at System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited)
  at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)

GetProcessHandle calls OpenProcess . Apparently the target process should allow SYNCHRONIZE bit for the above to work, which in theory can be set by SetSecurityInfo from the Windows Service. However it does not appear that there is an easy way of doing this in .NET short of calling several pinvokes to elevate, enable privilege and finally change the security.

Am I overlooking a simple way of waiting on another (system) process from a user process?

Try use the same user account to start the service and your program, Or use the built in Administrator account to run your program(Windows Vista and after).

If it still throw the exception, try set your computer's DEP(Data Execution Prevention) setting.

Updated: Maybe you could use this stupid code.. It's trouble for getting the Service Name, since it may not the same as Process.Name.

static ServiceController GetServiceControllerByPId(int processId)
{

    string serviceName = "";

    string qry = "SELECT NAME FROM WIN32_SERVICE WHERE PROCESSID = " + processId.ToString();
    System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(qry);
    System.Management.ManagementObjectCollection mngntObjs = searcher.Get();

    foreach (System.Management.ManagementObject mngntObj in mngntObjs)
    {
        serviceName = (string)mngntObj["NAME"];
    }
    if (serviceName == "")
    {
        return null;
    }

    return System.ServiceProcess.ServiceController.GetServices().FirstOrDefault(x => x.ServiceName == serviceName);
}

Call this function, and monitor the ServiceController.Status

If you know the service process ID, Why can't you get the service name and check for the service status from process as follows ?

Process process = Process.GetProcessById(1);
ServiceController windowsService = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName == process.ProcessName);

//Wait until the windows service stops running
while (windowsService.Status == ServiceControllerStatus.Running)
{
   Thread.Sleep(1000);
}

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