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?
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?
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 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?
check these out:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassGetProcessesByNameTopic.asp
http://www.codeproject.com/csharp/dll_profiler.asp
http://www.codeguru.com/Cpp/Cpp/cpp_managed/threads/article.php/c4875/
http://www.codeproject.com/csharp/oneProcessOnly.asp
http://www.eggheadcafe.com/articles/20011015.asp
http://www.eggheadcafe.com/articles/20011021.asp
http://www.syncfusion.com/FAQ/WinForms/FAQ_c40c.asp
hope they help you out.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassGetProcessesByNameTopic.asp
http://www.codeproject.com/csharp/dll_profiler.asp
http://www.codeguru.com/Cpp/Cpp/cpp_managed/threads/article.php/c4875/
http://www.codeproject.com/csharp/oneProcessOnly.asp
http://www.eggheadcafe.com/articles/20011015.asp
http://www.eggheadcafe.com/articles/20011021.asp
http://www.syncfusion.com/FAQ/WinForms/FAQ_c40c.asp
hope they help you out.
ASKER
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="QueryServiceCo nfig", 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.S equential) ]
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)
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",
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.S
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)
ASKER
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(hServi ce, 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)Mars hal.PtrToS tructure(b uffer, typeof(QUERY_SERVICE_CONFI G));
result = myStruct.lpBinaryPathName;
}
finally
{
// free the data
handle.Free();
}
Is there a better way? If not, I am going to delete this question.
// Try to get information about the query... data is an array of byte
int bRetVal = QueryServiceConfigA(hServi
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)Mars
result = myStruct.lpBinaryPathName;
}
finally
{
// free the data
handle.Free();
}
Is there a better way? If not, I am going to delete this question.
ASKER
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?
ASKER
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(hServi ce, 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)Mars hal.PtrToS tructure(b uffer, typeof(QUERY_SERVICE_CONFI G));
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().LastIndex Of(".EXE") ;
if(exePos >= 0)
{
result = result.Substring(0, exePos);
}
}
}
// close the service we opened
CloseServiceHandle(hServic e);
}
// 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( "MYSERVER0 4", "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="QueryServiceCo nfig",
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_SERVI CE = 0x04;
private const int SC_MANAGER_LOCK = 0x08;
private const int SC_MANAGER_QUERY_LOCK_STAT US = 0x10;
private const int SC_MANAGER_MODIFY_BOOT_CON FIG = 0x20;
private const int SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVI CE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STAT US | SC_MANAGER_MODIFY_BOOT_CON FIG);
// 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_DEPENDEN TS = 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_CONTR OL = 0x0100;
private const int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDEN TS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTR OL);
}
// have to hand-pack our struct to make compatible with C++
[StructLayout(LayoutKind.S equential) ]
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;
}
}
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 result = null;
try
{
// open the service manager
int hHandle = OpenSCManagerA(serverName,
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(hServi
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)Mars
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+
// strip the .exe off the end
int exePos = result.ToUpper().LastIndex
if(exePos >= 0)
{
result = result.Substring(0, exePos);
}
}
}
// close the service we opened
CloseServiceHandle(hServic
}
// 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(
Console.WriteLine("Result was " + rez);
}
catch(Exception ex)
{
Console.WriteLine("Caught:
}
catch
{
Console.WriteLine("Caught unmanaged exception.");
}
}
// Native method to get the last win32 error code
[DllImport("kernel32.dll",
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",
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",
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",
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_SERVI
private const int SC_MANAGER_LOCK = 0x08;
private const int SC_MANAGER_QUERY_LOCK_STAT
private const int SC_MANAGER_MODIFY_BOOT_CON
private const int SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVI
// 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_DEPENDEN
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_CONTR
private const int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDEN
}
// have to hand-pack our struct to make compatible with C++
[StructLayout(LayoutKind.S
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;
}
}
ASKER
Please Close and refund points.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
http://zamov.online.fr/EXHTML/CSharp/CSharp_368897.html