[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool EnumServicesStatusEx(IntPtr hSCManager,
int infoLevel, int dwServiceType,
int dwServiceState, IntPtr lpServices, UInt32 cbBufSize,
out uint pcbBytesNeeded, out uint lpServicesReturned,
ref uint lpResumeHandle, string pszGroupName);
TODO
(see example code below).
There is no known alternative managed API as of .Net 3.5/
This works on both 32 bit and 64 bit machines.
As usual when doing pinvoke operations, watch out for 64 bit vs 32 bit and packing boundaries.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Permissions;
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
internal static ENUM_SERVICE_STATUS_PROCESS[] GetServices()
{
List<ENUM_SERVICE_STATUS_PROCESS> result = new List<ENUM_SERVICE_STATUS_PROCESS>();
IntPtr handle = IntPtr.Zero;
IntPtr buf = IntPtr.Zero;
try
{
handle = OpenSCManager(null, null, (int)ServiceControlManagerType.SC_MANAGER_ALL_ACCESS);
if (handle != IntPtr.Zero)
{
uint iBytesNeeded = 0;
uint iServicesReturned = 0;
uint iResumeHandle = 0;
ENUM_SERVICE_STATUS_PROCESS infoLevel = new ENUM_SERVICE_STATUS_PROCESS();
if (!EnumServicesStatusEx(handle, SC_ENUM_PROCESS_INFO, (int)ServiceType.SERVICE_WIN32, (int)ServiceStateRequest.SERVICE_STATE_ALL, IntPtr.Zero, 0, out iBytesNeeded, out iServicesReturned, ref iResumeHandle, null))
{
// allocate our memory to receive the data for all the services (including the names)
buf = Marshal.AllocHGlobal((int)iBytesNeeded);
if (!EnumServicesStatusEx(handle, SC_ENUM_PROCESS_INFO, (int)ServiceType.SERVICE_WIN32, (int)ServiceStateRequest.SERVICE_STATE_ALL, buf, iBytesNeeded, out iBytesNeeded, out iServicesReturned, ref iResumeHandle, null))
throw new Win32Exception(Marshal.GetLastWin32Error());
ENUM_SERVICE_STATUS_PROCESS serviceStatus;
// check if 64 bit system which has different pack sizes
if (IntPtr.Size == 8)
{
long pointer = buf.ToInt64();
for (int i = 0; i < (int)iServicesReturned; i++)
{
serviceStatus = (ENUM_SERVICE_STATUS_PROCESS)Marshal.PtrToStructure(new IntPtr(pointer),
typeof(ENUM_SERVICE_STATUS_PROCESS));
result.Add(serviceStatus);
// incremement by sizeof(ENUM_SERVICE_STATUS_PROCESS) allow Packing of 8
pointer += ENUM_SERVICE_STATUS_PROCESS.SizePack8;
}
}
else
{
int pointer = buf.ToInt32();
for (int i = 0; i < (int)iServicesReturned; i++)
{
serviceStatus = (ENUM_SERVICE_STATUS_PROCESS)Marshal.PtrToStructure(new IntPtr(pointer),
typeof(ENUM_SERVICE_STATUS_PROCESS));
result.Add(serviceStatus);
// incremement by sizeof(ENUM_SERVICE_STATUS_PROCESS) allow Packing of 4
pointer += ENUM_SERVICE_STATUS_PROCESS.SizePack4;
}
}
}
}
}
catch(Exception e)
{
;
}
finally
{
if (handle != IntPtr.Zero)
CloseServiceHandle(handle);
if (buf != IntPtr.Zero)
Marshal.FreeHGlobal(buf);
}
return result.ToArray();
}
private const int SC_ENUM_PROCESS_INFO = 0;
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool EnumServicesStatusEx(IntPtr hSCManager,
int infoLevel, int dwServiceType,
int dwServiceState, IntPtr lpServices, UInt32 cbBufSize,
out uint pcbBytesNeeded, out uint lpServicesReturned,
ref uint lpResumeHandle, string pszGroupName);
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct ENUM_SERVICE_STATUS_PROCESS
{
internal static readonly int SizePack4 = Marshal.SizeOf(typeof(ENUM_SERVICE_STATUS_PROCESS));
/// <summary>
/// sizeof(ENUM_SERVICE_STATUS_PROCESS) allow Packing of 8 on 64 bit machines
/// </summary>
internal static readonly int SizePack8 = Marshal.SizeOf(typeof(ENUM_SERVICE_STATUS_PROCESS)) + 4;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
internal string pServiceName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
internal string pDisplayName;
internal SERVICE_STATUS_PROCESS ServiceStatus;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SERVICE_STATUS_PROCESS
{
public int serviceType;
public int currentState;
public int controlsAccepted;
public int win32ExitCode;
public int serviceSpecificExitCode;
public int checkPoint;
public int waitHint;
public int processId;
public int serviceFlags;
}
private enum ServiceType { SERVICE_KERNEL_DRIVER = 0x1, SERVICE_FILE_SYSTEM_DRIVER = 0x2, SERVICE_WIN32_OWN_PROCESS = 0x10, SERVICE_WIN32_SHARE_PROCESS = 0x20, SERVICE_INTERACTIVE_PROCESS = 0x100, SERVICETYPE_NO_CHANGE = SERVICE_NO_CHANGE, SERVICE_WIN32 = (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) }
private enum ServiceStateRequest { SERVICE_ACTIVE = 0x1, SERVICE_INACTIVE = 0x2, SERVICE_STATE_ALL = (SERVICE_ACTIVE | SERVICE_INACTIVE) }
private enum ServiceControlManagerType { SC_MANAGER_CONNECT = 0x1, SC_MANAGER_CREATE_SERVICE = 0x2, SC_MANAGER_ENUMERATE_SERVICE = 0x4, SC_MANAGER_LOCK = 0x8, SC_MANAGER_QUERY_LOCK_STATUS = 0x10, SC_MANAGER_MODIFY_BOOT_CONFIG = 0x20, 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 }