Solved

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

Posted on 2004-08-18
11
2,292 Views
Last Modified: 2012-06-22
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?
0
Comment
Question by:bfassler
11 Comments
 
LVL 1

Expert Comment

by:thefallguy
ID: 11831544
0
 

Author Comment

by:bfassler
ID: 11831632
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?
0
 
LVL 3

Expert Comment

by:nhewitt21
ID: 11839399
0
 

Author Comment

by:bfassler
ID: 11840411
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)

0
 

Author Comment

by:bfassler
ID: 11841753
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.
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:bfassler
ID: 11842703
Nevermind, I'm satisfied with the solution I came up with on my own.  I'm going to just delete the question.
0
 
LVL 1

Expert Comment

by:thefallguy
ID: 11842719
Mind posting the solution?
0
 

Author Comment

by:bfassler
ID: 11851561
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;
      }
}
0
 

Author Comment

by:bfassler
ID: 11892493
Please Close and refund points.
0
 
LVL 1

Accepted Solution

by:
DarthMod earned 0 total points
ID: 12142496
Submitted to PAQ with points refunded (125)

DarthMod
Community Support Moderator
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
.xltm file opens as .xlsx file 3 37
Using MS Code on my Mac 6 45
How do I get the id from URL? 19 48
Duplicate a row 2 33
Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now