QueryServiceConfig (advapi32)
Last changed: Smoke-190.64.103.228

.
Summary
The QueryServiceConfig function retrieves the configuration parameters of the specified service. Optional configuration parameters are available using the QueryServiceConfig2 function.

C# Signature:

[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded);

VB Signature:

Declare Function QueryServiceConfig Lib "advapi32.dll" (TODO) As TODO

User-Defined Types:

None.

Notes:

None.

Tips & Tricks:

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)

Sample Code:

    // 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);

Another Sample Code:

    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();
                }
            }
        }
    }

Alternative Managed API:

Do you know one? Please contribute it!

Documentation