Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the PID of a Windows service

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)
    });
like image 301
Johnny Avatar asked Apr 15 '14 13:04

Johnny


People also ask

How do I find the PID of a Windows service?

Task Manager can be opened in a number of ways, but the simplest is to select Ctrl+Alt+Delete, and then select Task Manager. In Windows, first click More details to expand the information displayed. From the Processes tab, select Details to see the process ID listed in the PID column.

How do you find the PID of a specific process?

A PID is automatically assigned to each process when it is created. A process is nothing but running instance of a program and each process has a unique PID on a Unix-like system. The easiest way to find out if process is running is run ps aux command and grep process name.


2 Answers

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;
}
like image 52
Christian.K Avatar answered Oct 06 '22 21:10

Christian.K


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.

like image 39
M C Avatar answered Oct 06 '22 21:10

M C