Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

QueryServiceConfig (advapi32)
 
.
Summary
The QueryServiceConfig2 function retrieves the optional configuration parameters of the specified service. At present, these are the service description and the failure actions.
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, EntryPoint = "QueryServiceConfig2W" )]
public static extern Boolean QueryServiceConfig2( IntPtr hService, UInt32 dwInfoLevel, IntPtr buffer, UInt32 cbBufSize, out UInt32 pcbBytesNeeded );
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded);

VB.NET Signature:

<DllImport("advapi32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
Shared Function QueryServiceConfig2(ByVal hService As IntPtr, ByVal dwInfoLevel As Integer, ByVal buffer As IntPtr, ByVal cbBufSize As Integer, ByRef pcbBytesNeeded As Integer) As Boolean
End Function

<DllImport("advapi32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _

Shared Function QueryServiceConfig(ByVal hService As IntPtr, ByVal lpServiceConfig As IntPtr, ByVal cbBufSize As Integer, ByRef pcbBytesNeeded As Integer) As Boolean

End Function

VB Signature:

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

User-Defined Types:

None.

Alternative Managed API:

None.

Notes:

None.

Tips & Tricks:

Please add some!

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)

Sample Code:

using System;

using System.Runtime.InteropServices;

using System.Text;

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)

    static void Main( string [] args )
    {
        // Use the service name and *NOT* the display name.
        string serviceName = "Dnscache"; // Display name is "DNS Client"
        if ( args.Length > 0 )
            serviceName = args [ 0 ];
        IntPtr databaseHandle = OpenSCManager( null, null, SC_MANAGER_ALL_ACCESS );
        if ( databaseHandle == IntPtr.Zero )
            throw new System.Runtime.InteropServices.ExternalException( "Error OpenSCManager\n" );

Sample Code:

        IntPtr serviceHandle = OpenService( databaseHandle, serviceName, SERVICE_QUERY_CONFIG );
        if ( serviceHandle == IntPtr.Zero )
            throw new System.Runtime.InteropServices.ExternalException( "Error OpenService\n" );
    // Get service executable and run it in the console. Change "Name of service" to your service name.
    using System;
    using System.Runtime.InteropServices;

        ReportDescription( serviceHandle );
        ReportFailureActions( serviceHandle );
    }

    static private void ReportDescription( IntPtr serviceHandle )
    #region P/Invoke QueryService
    [StructLayout(LayoutKind.Sequential)]
    public class QUERY_SERVICE_CONFIG
    {
        UInt32 dwBytesNeeded;
        [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;
    };

        // Determine the buffer size needed
        bool sucess = QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_DESCRIPTION, IntPtr.Zero, 0, out dwBytesNeeded );
    [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);

        IntPtr ptr = Marshal.AllocHGlobal( ( int )dwBytesNeeded );
        sucess = QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_DESCRIPTION, ptr, dwBytesNeeded, out dwBytesNeeded );
        SERVICE_DESCRIPTION descriptionStruct = new SERVICE_DESCRIPTION();
        Marshal.PtrToStructure( ptr, descriptionStruct );
        Marshal.FreeHGlobal( ptr );
    private const int SC_MANAGER_ALL_ACCESS = 0x000F003F;
    private const int SERVICE_QUERY_CONFIG = 0x00000001;

        // Report it.
        Console.WriteLine( descriptionStruct.lpDescription );
    }
    #endregion P/Invoke QueryService

    static private void ReportFailureActions( IntPtr serviceHandle )
    {
        UInt32 dwBytesNeeded;
        const UInt32 INFINITE = 0xFFFFFFFF;
    IntPtr databaseHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
    if(databaseHandle == IntPtr.Zero)
        throw new System.Runtime.InteropServices.ExternalException("Error OpenSCManager\n");

        // Determine the buffer size needed
        bool sucess = QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, IntPtr.Zero, 0, out dwBytesNeeded );
    IntPtr serviceHandle = OpenService(databaseHandle,  "Name of service", SERVICE_QUERY_CONFIG);
    if(serviceHandle == IntPtr.Zero)
        throw new System.Runtime.InteropServices.ExternalException("Error OpenService\n");

        IntPtr ptr = Marshal.AllocHGlobal( ( int )dwBytesNeeded );
        sucess = QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, ptr, dwBytesNeeded, out dwBytesNeeded );
        SERVICE_FAILURE_ACTIONS failureActions = new SERVICE_FAILURE_ACTIONS();
        Marshal.PtrToStructure( ptr, failureActions );
    UInt32 dwBytesNeeded = 0;

        // Report it.
        Console.WriteLine( "Reset Period: {0}", ( UInt32 )failureActions.dwResetPeriod != INFINITE
            ? failureActions.dwResetPeriod.ToString() : "INFINITE" );
        Console.WriteLine( "Reboot message: {0}", failureActions.lpRebootMsg );
        Console.WriteLine( "Command line: {0}", failureActions.lpCommand );
        Console.WriteLine( "Number of actions: {0}", failureActions.cActions );
    // Allocate memory for struct.
    IntPtr ptr = Marshal.AllocHGlobal(4096);

        SC_ACTION [] actions = new SC_ACTION [ failureActions.cActions ];
        int offset = 0;
        for ( int i = 0; i < failureActions.cActions; i++ )
        {
            SC_ACTION action = new SC_ACTION();
            action.type = Marshal.ReadInt32( failureActions.lpsaActions, offset );
            offset += sizeof( Int32 );
            action.dwDelay = ( UInt32 )Marshal.ReadInt32( failureActions.lpsaActions, offset );
            offset += sizeof( Int32 );
            actions [ i ] = action;
        }
    bool success = QueryServiceConfig(serviceHandle, ptr, 4096, out dwBytesNeeded);

        Marshal.FreeHGlobal( ptr );

        foreach ( SC_ACTION action in actions )
        {
            Console.WriteLine( "Type: {0}, Delay (msec): {1}", action.type, action.dwDelay );
        }
    }
    QUERY_SERVICE_CONFIG qUERY_SERVICE_CONFIG = new QUERY_SERVICE_CONFIG();
    // Copy
    Marshal.PtrToStructure(ptr, qUERY_SERVICE_CONFIG);
    // Free memory for struct.
    Marshal.FreeHGlobal(ptr);

    #region P/Invoke declarations
    [StructLayout( LayoutKind.Sequential )]
    public class SERVICE_DESCRIPTION
    {
        [MarshalAs( System.Runtime.InteropServices.UnmanagedType.LPWStr )]
        public String lpDescription;
    }
    ProcessStartInfo psi = new ProcessStartInfo();
    psi.FileName = qUERY_SERVICE_CONFIG.lpBinaryPathName;
    psi.Arguments = "-r";
    Process p = Process.Start(psi);

    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Unicode )]
    public class SERVICE_FAILURE_ACTIONS

Another Sample Code:

    namespace Services
    {
        public int dwResetPeriod;
        [MarshalAs( UnmanagedType.LPWStr )]
        public string lpRebootMsg;
        [MarshalAs( UnmanagedType.LPWStr )]
        public string lpCommand;
        public int cActions;
        public IntPtr lpsaActions;
    }
        /// <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);

    [StructLayout( LayoutKind.Sequential )]
    public class SC_ACTION
    {
        public Int32 type;
        public UInt32 dwDelay;
    }
            [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", 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 );
    [DllImport( "advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "QueryServiceConfig2W" )]
    public static extern Boolean QueryServiceConfig2( IntPtr hService, UInt32 dwInfoLevel, IntPtr buffer, UInt32 cbBufSize, out UInt32 pcbBytesNeeded );
            [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();

    private const Int32 SC_MANAGER_ALL_ACCESS = 0x000F003F;
    private const Int32 SERVICE_QUERY_CONFIG = 0x00000001;
    private const UInt32 SERVICE_CONFIG_DESCRIPTION = 0x01;
    private const UInt32 SERVICE_CONFIG_FAILURE_ACTIONS = 0x02;
                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;
            }

    #endregion // P/Invoke declarations
            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

The problem with the lpdependencies is already solved within .NET 2.0 (?) using public ServiceController[] DependentServices { get; }

However, to make live easier, this helper function avoids all the DllImports. It's not necessary to support Win9x since this OS, does not support these functions at all. Therefore the Unicode and exactspelling declaration (it kinda speeds things up)

[DllImport(ADVAPI32, EntryPoint = "ChangeServiceConfigW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]

    static extern bool ChangeServiceConfig(
        SafeHandle hService,
        [MarshalAs(UnmanagedType.U4)]
        ServiceType dwServiceType,
        [MarshalAs(UnmanagedType.U4)]
        ServiceStartMode dwStartType, int dwErrorControl,
        [In, MarshalAs(UnmanagedType.LPWStr)] string lpBinaryPathName,
        [In, MarshalAs(UnmanagedType.LPWStr)] string lpLoadOrderGroup,
        int lpdwTagId, //is out-opt specify 0
        // in fact an array
        [In, MarshalAs(UnmanagedType.LPWStr)] string lpDependencies,
            [In, MarshalAs(UnmanagedType.LPWStr)]
        string lpServiceStartName,
        [In, MarshalAs(UnmanagedType.LPWStr)]string lpPassWord, [In, MarshalAs(UnmanagedType.LPWStr)]string lpDisplayName);

    [DllImport(ADVAPI32, EntryPoint = "QueryServiceConfigW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
    static extern bool QueryServiceConfig(SafeHandle hService,
        IntPtr lpServiceConfig,
        int cbBufSize,
        out int pcbBytesNeeded);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct QUERY_SERVICE_CONFIG
    {
        [MarshalAs(UnmanagedType.U4)]
        internal ServiceType dwServiceType;
        [MarshalAs(UnmanagedType.U4)]
        internal ServiceStartMode dwStartType;
        internal int dwErrorControl;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string lpBinaryPathName;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string lpLoadOrderGroup;
        internal int dwTagId;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string lpDependencies;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string lpServiceStartName;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string lpDisplayName;
    }
/// <summary>
    /// Created since controller does not contain additional needed startup information
    /// </summary>
    /// <param name="controller"></param>
    /// <returns>ServiceStartMode value</returns>
    internal static ServiceStartMode GetServiceStartMode(ServiceController controller)
    {
        if (controller == null) throw new ArgumentNullException("controller");
        int neededBytes = 0;

        bool result = QueryServiceConfig(controller.ServiceHandle, IntPtr.Zero, 0, out neededBytes);
        int win32err = Marshal.GetLastWin32Error();
        if (win32err == ERROR_INSUFFICIENT_BUFFER) //122
        {
        IntPtr ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.AllocCoTaskMem(neededBytes);
            result = QueryServiceConfig(controller.ServiceHandle, ptr, neededBytes, out neededBytes);
            if (result)
            {
            QUERY_SERVICE_CONFIG config = (QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(ptr, typeof(QUERY_SERVICE_CONFIG));
            return config.dwStartType;
            }
            else
            {
            win32err = Marshal.GetLastWin32Error();
            throw new Win32Exception(win32err, "QueryServiceConfig failed");
            }
        }
        finally
        {
            Marshal.FreeCoTaskMem(ptr);
        }
        }
        else
        {
        throw new Win32Exception(win32err, "QueryServiceConfig failed");
        }
    }

    internal static void SetServiceStartupModde(ServiceController controller, ServiceStartMode mode)
    {
       if (controller == null) throw new ArgumentNullException("controller");
        bool result = util.ChangeServiceConfig(controller.ServiceHandle, (ServiceType)util.SERVICE_NO_CHANGE, mode,
           util.SERVICE_NO_CHANGE, null, null, 0, null, null, null, null);
        if (!result)
        {
        throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

Is there any chance to get the password of the current username?

Background is that I want to update, fix or patch an existing service automatically. I am not interested in the password. I just want to restore the identity configuration of the service after uninstalling the old and installing the new service.

Documentation

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Edit This Page
Find References
Show Printable Version
Revisions