[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded);
Declare Function QueryServiceConfig Lib "advapi32.dll" (TODO) As TODO
None.
None.
I have opted to list my changes here as the bulk of this code is largely correct, the only problem is with the lpDependencies field within the QUERY_SERVICE_CONFIG structure, which as the API documentation states, is not in fact a single string, but a double null terminated array of strings.
Therefore the correct declaration for this field is:
public IntPtr lpDependencies;//you will manually have to marshal these strings out of the pointer (I will add examples when i have worked out the best approach)
Another point is that all the string types should in fact be marshalled as System.Runtime.InteropServices.UnmanagedType.LPTStr, and change the struct layout attribute to [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)] this way you will gleam maximum compatibility (ie support older operating systems like windows 95)
// Get service executable and run it in the console. Change "Name of service" to your service name.
using System;
using System.Runtime.InteropServices;
#region P/Invoke QueryService
[StructLayout(LayoutKind.Sequential)]
public class QUERY_SERVICE_CONFIG
{
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwServiceType;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwStartType;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwErrorControl;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpBinaryPathName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpLoadOrderGroup;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwTagID;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpDependencies;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpServiceStartName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpDisplayName;
};
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded);
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern IntPtr OpenSCManager(String lpMachineName, String lpDatabaseName, UInt32 dwDesiredAccess);
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern IntPtr OpenService(IntPtr hSCManager, String lpServiceName, UInt32 dwDesiredAccess);
private const int SC_MANAGER_ALL_ACCESS = 0x000F003F;
private const int SERVICE_QUERY_CONFIG = 0x00000001;
#endregion P/Invoke QueryService
IntPtr databaseHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if(databaseHandle == IntPtr.Zero)
throw new System.Runtime.InteropServices.ExternalException("Error OpenSCManager\n");
IntPtr serviceHandle = OpenService(databaseHandle, "Name of service", SERVICE_QUERY_CONFIG);
if(serviceHandle == IntPtr.Zero)
throw new System.Runtime.InteropServices.ExternalException("Error OpenService\n");
UInt32 dwBytesNeeded = 0;
// Allocate memory for struct.
IntPtr ptr = Marshal.AllocHGlobal(4096);
bool success = QueryServiceConfig(serviceHandle, ptr, 4096, out dwBytesNeeded);
QUERY_SERVICE_CONFIG qUERY_SERVICE_CONFIG = new QUERY_SERVICE_CONFIG();
// Copy
Marshal.PtrToStructure(ptr, qUERY_SERVICE_CONFIG);
// Free memory for struct.
Marshal.FreeHGlobal(ptr);
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = qUERY_SERVICE_CONFIG.lpBinaryPathName;
psi.Arguments = "-r";
Process p = Process.Start(psi);
namespace Services
{
/// <summary>
/// Some wrappers around Win32 calls dealing with services.
/// </summary>
public class ServiceConfigurator
{
[StructLayout(LayoutKind.Sequential)]
private struct QueryServiceConfigStruct
{
public int serviceType;
public int startType;
public int errorControl;
public IntPtr binaryPathName;
public IntPtr loadOrderGroup;
public int tagID;
public IntPtr dependencies;
public IntPtr startName;
public IntPtr displayName;
}
public struct ServiceInfo
{
public int serviceType;
public int startType;
public int errorControl;
public string binaryPathName;
public string loadOrderGroup;
public int tagID;
public string dependencies;
public string startName;
public string displayName;
}
#region constants
private enum SCManagerAccess : int
{
GENERIC_ALL = 0x10000000
}
private enum ServiceAccess : int
{
QUERY_CONFIG = 0x1,
CHANGE_CONFIG = 0x2,
}
private const int SERVICE_NO_CHANGE = 0xFFFF;
#endregion
#region DllImports
[DllImport("advapi32.dll",
SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenSCManager(
[MarshalAs(UnmanagedType.LPTStr)]
string machineName,
[MarshalAs(UnmanagedType.LPTStr)]
string databaseName,
int desiredAccess);
[DllImport("advapi32.dll",
SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenService(
IntPtr scManager,
[MarshalAs(UnmanagedType.LPTStr)]
string serviceName,
int desiredAccess);
[DllImport("advapi32.dll",
SetLastError = true, CharSet = CharSet.Auto)]
private static extern int ChangeServiceConfig(
IntPtr service,
int serviceType,
int startType,
int errorControl,
[MarshalAs(UnmanagedType.LPTStr)]
string binaryPathName,
[MarshalAs(UnmanagedType.LPTStr)]
string loadOrderGroup,
IntPtr tagID,
[MarshalAs(UnmanagedType.LPTStr)]
string dependencies,
[MarshalAs(UnmanagedType.LPTStr)]
string startName,
[MarshalAs(UnmanagedType.LPTStr)]
string password,
[MarshalAs(UnmanagedType.LPTStr)]
string displayName);
[DllImport("advapi32.dll",
SetLastError = true, CharSet = CharSet.Auto)]
private static extern int QueryServiceConfig(
IntPtr service,
IntPtr queryServiceConfig,
int bufferSize,
ref int bytesNeeded);
#endregion
public static ServiceInfo GetServiceInfo(string ServiceName)
{
if (ServiceName.Equals(""))
throw new NullReferenceException("ServiceName must contain a valid service name.");
IntPtr scManager = OpenSCManager(".", null,
(int)SCManagerAccess.GENERIC_ALL);
if (scManager.ToInt32() <= 0)
throw new Win32Exception();
IntPtr service = OpenService(scManager,
ServiceName, (int)ServiceAccess.QUERY_CONFIG);
if (service.ToInt32() <= 0)
throw new NullReferenceException();
int bytesNeeded = 5;
QueryServiceConfigStruct qscs = new QueryServiceConfigStruct();
IntPtr qscPtr = Marshal.AllocCoTaskMem(0);
int retCode = QueryServiceConfig(service, qscPtr,
0, ref bytesNeeded);
if (retCode == 0 && bytesNeeded == 0)
{
throw new Win32Exception();
}
else
{
qscPtr = Marshal.AllocCoTaskMem(bytesNeeded);
retCode = QueryServiceConfig(service, qscPtr,
bytesNeeded, ref bytesNeeded);
if (retCode == 0)
{
throw new Win32Exception();
}
qscs.binaryPathName = IntPtr.Zero;
qscs.dependencies = IntPtr.Zero;
qscs.displayName = IntPtr.Zero;
qscs.loadOrderGroup = IntPtr.Zero;
qscs.startName = IntPtr.Zero;
qscs = (QueryServiceConfigStruct)
Marshal.PtrToStructure(qscPtr,
new QueryServiceConfigStruct().GetType());
}
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.binaryPathName =
Marshal.PtrToStringAuto(qscs.binaryPathName);
serviceInfo.dependencies =
Marshal.PtrToStringAuto(qscs.dependencies);
serviceInfo.displayName =
Marshal.PtrToStringAuto(qscs.displayName);
serviceInfo.loadOrderGroup =
Marshal.PtrToStringAuto(qscs.loadOrderGroup);
serviceInfo.startName =
Marshal.PtrToStringAuto(qscs.startName);
serviceInfo.errorControl = qscs.errorControl;
serviceInfo.serviceType = qscs.serviceType;
serviceInfo.startType = qscs.startType;
serviceInfo.tagID = qscs.tagID;
Marshal.FreeCoTaskMem(qscPtr);
return serviceInfo;
}
public static void ChangeAccount(string ServiceName,
string Username, string Password)
{
ServiceInfo serviceInfo = GetServiceInfo(ServiceName);
IntPtr scManager = OpenSCManager(".", null,
(int)SCManagerAccess.GENERIC_ALL);
if (scManager.ToInt32() <= 0)
throw new Win32Exception();
IntPtr service = OpenService(scManager,
ServiceName, (int)ServiceAccess.CHANGE_CONFIG);
if (service.ToInt32() <= 0)
throw new Win32Exception();
if (ChangeServiceConfig(service, serviceInfo.serviceType,
serviceInfo.startType, serviceInfo.errorControl,
serviceInfo.binaryPathName, serviceInfo.loadOrderGroup,
IntPtr.Zero, serviceInfo.dependencies,
Username, Password, serviceInfo.displayName) == 0)
{
throw new Win32Exception();
}
}
}
}
Do you know one? Please contribute it!