15

Could anyone help me to know how to get the PID of a Windows service?
I need to get the PID in order to run the following command:

Process.Start(new ProcessStartInfo 
    {
        Filename = "cmd.exe",
        CreateNoWindow = true,
        UseShellExecute = false,
        Arguments = string.Format("/c taskkill /pid {0} /f", pidnumber)
    });
Fedor
  • 1,548
  • 3
  • 28
  • 38
Johnny
  • 193
  • 1
  • 2
  • 5
  • Please don't neglect code formatting next time. Properly formatted code helps people a lot to understand what you want. – Fedor Apr 15 '14 at 13:33
  • Even if the Taskmanager doesn't show your service in the Processes tab. It still has some sort of executabe file. – M C Apr 15 '14 at 13:34

3 Answers3

32

What the other answers neglect is the fact that a single process can also host multiple, autonomous services. The multiple instances of the svchost.exe process, each hosting a couple of services, is the best example.

So in general, it is absolutely unsafe to try to kill an arbitrary service by killing it's hosting process (I assume that is what you attempt to do, since you refer to taskkill.exe). You might take down several unrelated services in the process.

If you do know that the service's process only hosts the service you care about, than you can choose the strategy as suggested by @M C in his/her answer.

Alternatively, you can also use the ServiceController class to open a handle to your service and then use it (via the ServiceHandle property) to P/Invoke the QueryServiceStatusEx function to find out the Process ID you want to know.

If you need more details, you should clarify what it is that you're actually trying to achieve. It is not clear from your question.

Update Here is some code I ripped out of an existing project that should do what you want, given you have a ServiceController instance. _As said above, use with care!__

[StructLayout(LayoutKind.Sequential)]
internal sealed class SERVICE_STATUS_PROCESS
{
    [MarshalAs(UnmanagedType.U4)]
    public uint dwServiceType;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwCurrentState;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwControlsAccepted;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwWin32ExitCode;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwServiceSpecificExitCode;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwCheckPoint;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwWaitHint;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwProcessId;
    [MarshalAs(UnmanagedType.U4)]
    public uint dwServiceFlags;
}

internal const int ERROR_INSUFFICIENT_BUFFER = 0x7a;
internal const int SC_STATUS_PROCESS_INFO = 0;

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool QueryServiceStatusEx(SafeHandle hService, int infoLevel, IntPtr lpBuffer, uint cbBufSize, out uint pcbBytesNeeded);

public static int GetServiceProcessId(this ServiceController sc)
{
    if (sc == null)
        throw new ArgumentNullException("sc");

    IntPtr zero = IntPtr.Zero;

    try
    {
        UInt32 dwBytesNeeded;
        // Call once to figure the size of the output buffer.
        QueryServiceStatusEx(sc.ServiceHandle, SC_STATUS_PROCESS_INFO, zero, 0, out dwBytesNeeded);
        if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
        {
            // Allocate required buffer and call again.
            zero = Marshal.AllocHGlobal((int)dwBytesNeeded);

            if (QueryServiceStatusEx(sc.ServiceHandle, SC_STATUS_PROCESS_INFO, zero, dwBytesNeeded, out dwBytesNeeded))
            {
                var ssp = new SERVICE_STATUS_PROCESS();
                Marshal.PtrToStructure(zero, ssp);
                return (int)ssp.dwProcessId;
            }
        }
    }
    finally
    {
        if (zero != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(zero);
        }
    }
    return -1;
}
Christian.K
  • 47,778
  • 10
  • 99
  • 143
  • 1
    Using the service controller, as suggested in thyis answer, would be my choice too. – Felice Pollano Apr 15 '14 at 13:31
  • 2
    This is the best answer here. – Jeff Paquette Oct 07 '14 at 14:02
  • 1
    Does the call to `QueryServiceStatusEx` need admin rights? – Cocowalla Oct 13 '17 at 12:45
  • It depends. In general yes, but you could also setup service rights (for particular services) to allow access (to query those services status) as a non-admin user ([reference](https://learn.microsoft.com/de-de/windows/desktop/Services/service-security-and-access-rights)). – Christian.K May 12 '19 at 08:40
  • For me, `Marshal.GetLastWin32Error()` returned zero, but the `dwBytesNeeded` was set. So I had to check for either `ERROR_INSUFFICIENT_BUFFER` or zero. – ergohack Jun 01 '21 at 17:43
3

See this answer on a similar question: Finding out Windows service's running process name

Using a WMI query you can -

Find all services related to a single exe (a single exe can host multiple services):

select Name from Win32_Service where ProcessId = 588

Or, to answer this question, you can get the PID of the process that a service is running in:

select ProcessId from Win32_Service where Name = 'wuauserv'

Community
  • 1
  • 1
Patrick
  • 1,089
  • 14
  • 17
2

Assuming you know the name of the EXE the service uses and there is exactly one of them:

int procID = Process.GetProcessesByName("yourservice")[0].Id;

The method Process.GetProcessesByName("yourservice") returns an Array of Processes with your specified name, so in case you don't know how much of "yourservice.exe" runs simultaneously you might need a foreach loop.

olegvs
  • 345
  • 3
  • 11
M C
  • 626
  • 1
  • 11
  • 27
  • 2
    you should mention you can have more than one result – Felice Pollano Apr 15 '14 at 13:17
  • To verify that I have the correct PID, I check the filepaths in a loop like so `if (processes[i].MainModule.FileName == myServiceExecutableFilePath)` – Smitty-Werben-Jager-Manjenson Jun 20 '19 at 17:57
  • There may be multiple EXE files with the same name, not all of which are the service process of the service you are interested in. Also, if you are using this to kill a service process after failing to stop it gracefully, it can fail with an exception if the process dies at the wrong time. – Florian Winter Feb 07 '20 at 10:24