Link to home
Start Free TrialLog in
Avatar of bfassler
bfassler

asked on

How can I get process name from a running windows service name

Is there a way in C# (Or using the windows C-API through interop services) to get the actual running process name from a windows service?

I see ServiceController classes for querying data on a service, but I don't see where you can actually pull the running process name from it so you can kill the individual process (if service.Stop() fails) or to check memory usage or CPU utilization...

Any thoughts?
Avatar of thefallguy
thefallguy

Avatar of bfassler

ASKER

I've seen that page, and that is great for getting info about a process, but it doesn't get them by the ServiceName which is my main point.

I have a service running (let's say it's called BridgeFeed) and I know this service is running under the process svcRealtimeBF.  Now, I can get the process data by KNOWING that BridgeFeed service == svcRealtimeBF process.  But how can i programatically make that distinction?
I think I may not have clearly conveyed the main point of the question.  I know how to kill processes, and I know how to stop services.  What I'm trying to ask is this: if I know I have a service named MySampleService, how do I find out (using C#) what is the name of the process that it is running as.  In my environment they are often times not the same  (For example, our service named BridgeFeed actually runs an exe named svcRealtimeBF.exe)

How can I query C# to say, give me the process name associated with the service BridgeFeed?

Now, I've been looking at importing the following function to C#

[DllImport("advapi32.dll", EntryPoint="QueryServiceConfig", SetLastError=true)]
private static extern int QueryServiceConfigA(int hService,
      ref QUERY_SERVICE_CONFIG config, int cbBufSize,
      ref int pcbBytesNeeded);

where QUERY_SERVICE_CONFIG is

// have to hand-pack our struct to make compatible with C++
[StructLayout(LayoutKind.Sequential)]
internal struct QUERY_SERVICE_CONFIG
{    
      int dwServiceType;  
      int dwStartType;  

      int dwErrorControl;  

      [MarshalAs (UnmanagedType.LPStr)]
      string lpBinaryPathName;  

      [MarshalAs (UnmanagedType.LPStr)]
      string lpLoadOrderGroup;  

      int dwTagId;  

      [MarshalAs (UnmanagedType.LPStr)]
      string lpDependencies;  

      [MarshalAs (UnmanagedType.LPStr)]
      string lpServiceStartName;  

      [MarshalAs (UnmanagedType.LPStr)]
      string lpDisplayName;
}

The problem is, according to MSDN documentation, QUERY_SERVICE_CONFIG can be VARIABLE length, and if the function returns false and a bytes needed number, you need to call it again with a larger structure.  How in the heck would I manage that in C#?  Should I just pass in an array of byte instead that is large enough?  If I do that, how do i get it back in the structure.

If someone can answer these two questions or give me an easier way, I will give them the points:

1)  How should I be passing in the structure since it could conceivably require more space?

2) If I pass in an array of byte instead, how do I find out where lpBinaryPathName (the actual name of my service's exe) lives in that array of bytes.  You would think it would be 12 bytes ahead (4 bytes for each DWORD (int) in front of it).  However, when I do pass an array of bytes, it comes back with the binary path name in position 36!!!  Why is it 3 times farther than i thought it would be (using AsciiEncoder to string out the string)

Okay, I'm able to do it this way:

// Try to get information about the query... data is an array of byte
int bRetVal = QueryServiceConfigA(hService, data,
      BUFFER_LENGTH, ref dwBytesNeeded);

// alloc mem
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);

try
{
                                          // convert the byte buffer to a struct
                                          QUERY_SERVICE_CONFIG myStruct;

                                          // demarshall the object
                                          IntPtr buffer = handle.AddrOfPinnedObject();
                                          myStruct = (QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(buffer, typeof(QUERY_SERVICE_CONFIG));
                                          result = myStruct.lpBinaryPathName;
}
finally
{
                                          // free the data
                                          handle.Free();
}


Is there a better way?  If not, I am going to delete this question.
Nevermind, I'm satisfied with the solution I came up with on my own.  I'm going to just delete the question.
Mind posting the solution?
Here was my solution:

namespace Service Tester
{
      /// <summary>
      /// Class to help in starting/stopping/finding NT services
      /// </summary>
      public class ServiceManager
      {
            .
            .
            .

            /// <summary>
            /// static method to find the process name from a service name
            /// </summary>
            /// <param name="serverName">The server service runs on</param>
            /// <param name="serviceName">The name of the service</param>
            /// <returns>The name of the binary process that is the service</returns>
            public static string GetProcessNameFromService(string serverName, string serviceName)
            {
                  string result = null;

                  try
                  {
                        // open the service manager
                        int hHandle = OpenSCManagerA(serverName, SERVICES_ACTIVE_DATABASE,
                              SC_MANAGER_ALL_ACCESS);
   
                        // if we can open the service manager successfully, open the service
                        if(hHandle != 0)
                        {
                              int dwBytesNeeded = 0;
   
                              // get the service
                              int hService = OpenServiceA(hHandle, serviceName, SERVICE_ALL_ACCESS);
               
                              // if we opened the service correctly, get its config
                              if (hService != 0)
                              {              
                                    // allocate buffer for request
                                    byte [] data = new byte[BUFFER_LENGTH];

                                    // Try to get information about the query
                                    int bRetVal = QueryServiceConfigA(hService, data,
                                          BUFFER_LENGTH, ref dwBytesNeeded);

                                    // alloc mem
                                    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);

                                    try
                                    {
                                          // convert the byte buffer to a struct
                                          QUERY_SERVICE_CONFIG myStruct;

                                          // demarshall the object
                                          IntPtr buffer = handle.AddrOfPinnedObject();
                                          myStruct = (QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(buffer, typeof(QUERY_SERVICE_CONFIG));
                                          result = myStruct.lpBinaryPathName;
                                    }
                                    finally
                                    {
                                          // free the data
                                          handle.Free();
                                    }
               
                                    // if we got a result...
                                    if (result != null)
                                    {
                                          // now find just the exe name and strip off the
                                          // directory if it's there
                                          int slashPos = result.LastIndexOf('\\');

                                          if(slashPos >= 0)
                                          {
                                                result = result.Substring(slashPos+1);

                                                // strip the .exe off the end
                                                int exePos = result.ToUpper().LastIndexOf(".EXE");

                                                if(exePos >= 0)
                                                {
                                                      result = result.Substring(0, exePos);
                                                }
                                          }
                                    }

                                    // close the service we opened
                                    CloseServiceHandle(hService);
                              }
   
                              // close the service manager
                              CloseServiceHandle(hHandle);
                        }
                  }
                  catch
                  {
                        result = null;
                  }

                  // return result if we found it (will be null if could not get it)
                  return result;
            }



            /// <summary>
            /// Test method for unit testing
            /// </summary>
            /// <param name="args">not used</param>
            public static void Main(string [] args)
            {
                  try
                  {
                        Console.WriteLine("Going to try to find out about BridgeFeed");

                        string rez = GetProcessNameFromService("MYSERVER04", "BridgeFeed");

                        Console.WriteLine("Result was " + rez);
                  }
                  catch(Exception ex)
                  {
                        Console.WriteLine("Caught: " + ex.Message);
                  }
                  catch
                  {
                        Console.WriteLine("Caught unmanaged exception.");
                  }
            }


            // Native method to get the last win32 error code
            [DllImport("kernel32.dll", SetLastError=true)]
            private static extern int GetLastError();

            // Native method to query config data from a service
            // We are using this to ask a service what process it runs as
            [DllImport("advapi32.dll", EntryPoint="QueryServiceConfig",
                   SetLastError=true)]
            private static extern int QueryServiceConfigA(int hService,
                  byte [] lpServiceConfig, int cbBufSize,
                  ref int pcbBytesNeeded);

            // Native method to open the service manager on a remote machine
            [DllImport("advapi32.dll", EntryPoint="OpenSCManager",
                   SetLastError=true)]
            private static extern int OpenSCManagerA(string lpMachineName,
                  string lpDatabaseName, int dwDesiredAccess);

            // Native method to open a service from a service manager
            [DllImport("advapi32.dll", EntryPoint="OpenService",
                   SetLastError=true)]
            private static extern int OpenServiceA(int hSCManager,
                  string lpServiceName, int dwDesiredAccess);

            // Native method to close a service or service manager handle
            [DllImport("advapi32.dll")]
            private static extern int CloseServiceHandle(int hSCObject);

            // consts for querying service type
            private const int STARTING_POSITION = 36;
            private const int BUFFER_LENGTH     = 4096;

            // Service constants for API calls
            private const string SERVICES_ACTIVE_DATABASE = "ServicesActive";
            private const int SERVICE_CONTROL_STOP = 0x01;
            private const int SERVICE_CONTROL_PAUSE = 0x02;
            private const int SERVICE_STOPPED = 0x01;
            private const int SERVICE_START_PENDING = 0x02;
            private const int SERVICE_STOP_PENDING = 0x03;
            private const int SERVICE_RUNNING = 0x04;
            private const int SERVICE_CONTINUE_PENDING = 0x05;
            private const int SERVICE_PAUSE_PENDING = 0x06;
            private const int SERVICE_PAUSED = 0x07;
            
            // Service Control Manager object specific access types
            private const int STANDARD_RIGHTS_REQUIRED = 0x0000;
            private const int SC_MANAGER_CONNECT = 0x01;
            private const int SC_MANAGER_CREATE_SERVICE = 0x02;
            private const int SC_MANAGER_ENUMERATE_SERVICE = 0x04;
            private const int SC_MANAGER_LOCK = 0x08;
            private const int SC_MANAGER_QUERY_LOCK_STATUS = 0x10;
            private const int SC_MANAGER_MODIFY_BOOT_CONFIG = 0x20;
            private const int SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG);
            
            // Service object specific access types
            private const int SERVICE_QUERY_CONFIG = 0x01;
            private const int SERVICE_CHANGE_CONFIG = 0x02;
            private const int SERVICE_QUERY_STATUS = 0x04;
            private const int SERVICE_ENUMERATE_DEPENDENTS = 0x08;
            private const int SERVICE_START = 0x10;
            private const int SERVICE_STOP = 0x20;
            private const int SERVICE_PAUSE_CONTINUE = 0x40;
            private const int SERVICE_INTERROGATE = 0x80;
            private const int SERVICE_USER_DEFINED_CONTROL = 0x0100;
            private const int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL);

      }

      // have to hand-pack our struct to make compatible with C++
      [StructLayout(LayoutKind.Sequential)]
      internal struct QUERY_SERVICE_CONFIG
      {    
            public int dwServiceType;  
            public int dwStartType;  

            public int dwErrorControl;  

            [MarshalAs (UnmanagedType.LPStr)]
            public string lpBinaryPathName;  

            [MarshalAs (UnmanagedType.LPStr)]
            public string lpLoadOrderGroup;  

            public int dwTagId;  

            [MarshalAs (UnmanagedType.LPStr)]
            public string lpDependencies;  

            [MarshalAs (UnmanagedType.LPStr)]
            public string lpServiceStartName;  

            [MarshalAs (UnmanagedType.LPStr)]
            public string lpDisplayName;
      }
}
Please Close and refund points.
ASKER CERTIFIED SOLUTION
Avatar of DarthMod
DarthMod
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial