Vanara/PInvoke/Security/AdvApi32/WinSvc.cs

6838 lines
343 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
namespace Vanara.PInvoke
{
public static partial class AdvApi32
{
/// <summary/>
public const uint SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1;
/// <summary>
/// <para>
/// An application-defined callback function used with the RegisterServiceCtrlHandler function. A service program can use it as the
/// control handler function of a particular service.
/// </para>
/// <para>
/// The <c>LPHANDLER_FUNCTION</c> type defines a pointer to this function. <c>Handler</c> is a placeholder for the
/// application-defined name.
/// </para>
/// <para>
/// This function has been superseded by the HandlerEx control handler function used with the RegisterServiceCtrlHandlerEx function.
/// A service can use either control handler, but the new control handler supports user-defined context data and additional extended
/// control codes.
/// </para>
/// </summary>
/// <param name="dwControl"/>
/// <returns>
/// <para>This function does not return a value.</para>
/// </returns>
/// <remarks>
/// <para>
/// When a service is started, its ServiceMain function should immediately call the RegisterServiceCtrlHandler function to specify a
/// <c>Handler</c> function to process control requests.
/// </para>
/// <para>
/// The control dispatcher in the main thread of a service process invokes the control handler function for the specified service
/// whenever it receives a control request from the service control manager. After processing the control request, the control
/// handler must call the SetServiceStatus function if the service state changes to report its new status to the service control manager.
/// </para>
/// <para>
/// The control handler function is intended to receive notification and return immediately. The callback function should save its
/// parameters and create other threads to perform additional work. (Your application must ensure that such threads have exited
/// before stopping the service.) In particular, a control handler should avoid operations that might block, such as taking a lock,
/// because this could result in a deadlock or cause the system to stop responding.
/// </para>
/// <para>
/// When the service control manager sends a control code to a service, it waits for the handler function to return before sending
/// additional control codes to other services. The control handler should return as quickly as possible; if it does not return
/// within 30 seconds, the SCM returns an error. If a service must do lengthy processing when the service is executing the control
/// handler, it should create a secondary thread to perform the lengthy processing, and then return from the control handler. This
/// prevents the service from tying up the control dispatcher and blocking other services from receiving control codes.
/// </para>
/// <para>
/// The <c>SERVICE_CONTROL_SHUTDOWN</c> control code should only be processed by services that must absolutely clean up during
/// shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system
/// shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not
/// restarted or powered down), the service continues to run. If your service registers to accept <c>SERVICE_CONTROL_SHUTDOWN</c>, it
/// must handle the control code and stop in a timely fashion. Otherwise, the service can increase the time required to shut down the
/// system, because the system must wait for the full amount of time allowed for service shutdown before system shutdown can proceed.
/// </para>
/// <para>
/// If the service requires more time to clean up, it should send <c>STOP_PENDING</c> status messages, along with a wait hint, so the
/// service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a
/// service from stopping shutdown, there is a limit to how long the service controller will wait. If the service is being shut down
/// through the Services snap-in, the limit is 125 seconds. If the operating system is rebooting, the time limit is specified in the
/// <c>WaitToKillServiceTimeout</c> value of the following registry key:
/// </para>
/// <para><c>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control</c></para>
/// <para>
/// Services can also use the SetConsoleCtrlHandler function to receive shutdown notification. This notification is received when the
/// running applications are shutting down, which occurs before services are shut down.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Writing a Control Handler Function.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nc-winsvc-lphandler_function LPHANDLER_FUNCTION LphandlerFunction;
// void LphandlerFunction( DWORD dwControl ) {...}
[PInvokeData("winsvc.h", MSDNShortId = "e2d6d3a7-070e-4343-abd7-b4b9f8dd6fbc")]
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate void Handler(ServiceControl dwControl);
/// <summary>
/// <para>
/// An application-defined callback function used with the RegisterServiceCtrlHandlerEx function. A service program can use it as the
/// control handler function of a particular service.
/// </para>
/// <para>
/// The <c>LPHANDLER_FUNCTION_EX</c> type defines a pointer to this function. <c>HandlerEx</c> is a placeholder for the
/// application-defined name.
/// </para>
/// <para>
/// This function supersedes the Handler control handler function used with the RegisterServiceCtrlHandler function. A service can
/// use either control handler, but the new control handler supports user-defined context data and additional extended control codes.
/// </para>
/// </summary>
/// <param name="dwControl">
/// <para>The control code. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTROL_CONTINUE 0x00000003</term>
/// <term>Notifies a paused service that it should resume.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_INTERROGATE 0x00000004</term>
/// <term>
/// Notifies a service to report its current status information to the service control manager. The handler should simply return
/// NO_ERROR; the SCM is aware of the current state of the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDADD 0x00000007</term>
/// <term>
/// Notifies a network service that there is a new component for binding. The service should bind to the new component. Applications
/// should use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDDISABLE 0x0000000A</term>
/// <term>
/// Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and
/// remove the binding. Applications should use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDENABLE 0x00000009</term>
/// <term>
/// Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add
/// the new binding. Applications should use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDREMOVE 0x00000008</term>
/// <term>
/// Notifies a network service that a component for binding has been removed. The service should reread its binding information and
/// unbind from the removed component. Applications should use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PARAMCHANGE 0x00000006</term>
/// <term>Notifies a service that service-specific startup parameters have changed. The service should reread its startup parameters.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PAUSE 0x00000002</term>
/// <term>Notifies a service that it should pause.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PRESHUTDOWN 0x0000000F</term>
/// <term>
/// Notifies a service that the system will be shutting down. Services that need additional time to perform cleanup tasks beyond the
/// tight time restriction at system shutdown can use this notification. The service control manager sends this notification to
/// applications that have registered for it before sending a SERVICE_CONTROL_SHUTDOWN notification to applications that have
/// registered for that notification. A service that handles this notification blocks system shutdown until the service stops or the
/// preshutdown time-out interval specified through SERVICE_PRESHUTDOWN_INFO expires. Because this affects the user experience,
/// services should use this feature only if it is absolutely necessary to avoid data loss or significant recovery time at the next
/// system start. Windows Server 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_SHUTDOWN 0x00000005</term>
/// <term>
/// Notifies a service that the system is shutting down so the service can perform cleanup tasks. Note that services that register
/// for SERVICE_CONTROL_PRESHUTDOWN notifications cannot receive this notification because they have already stopped. If a service
/// accepts this control code, it must stop after it performs its cleanup tasks and return NO_ERROR. After the SCM sends this control
/// code, it will not send other control codes to the service. For more information, see the Remarks section of this topic.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_STOP 0x00000001</term>
/// <term>
/// Notifies a service that it should stop. If a service accepts this control code, it must stop upon receipt and return NO_ERROR.
/// After the SCM sends this control code, it will not send other control codes to the service. Windows XP: If the service returns
/// NO_ERROR and continues to run, it continues to receive control codes. This behavior changed starting with Windows Server 2003 and
/// Windows XP with SP2.
/// </term>
/// </item>
/// </list>
/// <para>
/// This parameter can also be one of the following extended control codes. Note that these control codes are not supported by the
/// Handler function.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Control Code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTROL_DEVICEEVENT 0x0000000B</term>
/// <term>
/// Notifies a service of device events. (The service must have registered to receive these notifications using the
/// RegisterDeviceNotification function.) The dwEventType and lpEventData parameters contain additional information.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_HARDWAREPROFILECHANGE 0x0000000C</term>
/// <term>Notifies a service that the computer's hardware profile has changed. The dwEventType parameter contains additional information.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_POWEREVENT 0x0000000D</term>
/// <term>
/// Notifies a service of system power events. The dwEventType parameter contains additional information. If dwEventType is
/// PBT_POWERSETTINGCHANGE, the lpEventData parameter also contains additional information.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_SESSIONCHANGE 0x0000000E</term>
/// <term>
/// Notifies a service of session change events. Note that a service will only be notified of a user logon if it is fully loaded
/// before the logon attempt is made. The dwEventType and lpEventData parameters contain additional information.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_TIMECHANGE 0x00000010</term>
/// <term>
/// Notifies a service that the system time has changed. The lpEventData parameter contains additional information. The dwEventType
/// parameter is not used. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_TRIGGEREVENT 0x00000020</term>
/// <term>
/// Notifies a service registered for a service trigger event that the event has occurred. Windows Server 2008, Windows Vista,
/// Windows Server 2003 and Windows XP: This control code is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_USERMODEREBOOT 0x00000040</term>
/// <term>
/// Notifies a service that the user has initiated a reboot. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista,
/// Windows Server 2003 and Windows XP: This control code is not supported.
/// </term>
/// </item>
/// </list>
/// <para>This parameter can also be a user-defined control code, as described in the following table.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>Range 128 to 255.</term>
/// <term>The service defines the action associated with the control code.</term>
/// </item>
/// </list>
/// </param>
/// <param name="dwEventType">
/// <para>
/// The type of event that has occurred. This parameter is used if dwControl is <c>SERVICE_CONTROL_DEVICEEVENT</c>,
/// <c>SERVICE_CONTROL_HARDWAREPROFILECHANGE</c>, <c>SERVICE_CONTROL_POWEREVENT</c>, or <c>SERVICE_CONTROL_SESSIONCHANGE</c>.
/// Otherwise, it is zero.
/// </para>
/// <para>If dwControl is <c>SERVICE_CONTROL_DEVICEEVENT</c>, this parameter can be one of the following values:</para>
/// <list type="bullet">
/// <item>
/// <term>DBT_DEVICEARRIVAL</term>
/// </item>
/// <item>
/// <term>DBT_DEVICEREMOVECOMPLETE</term>
/// </item>
/// <item>
/// <term>DBT_DEVICEQUERYREMOVE</term>
/// </item>
/// <item>
/// <term>DBT_DEVICEQUERYREMOVEFAILED</term>
/// </item>
/// <item>
/// <term>DBT_DEVICEREMOVEPENDING</term>
/// </item>
/// <item>
/// <term>DBT_CUSTOMEVENT</term>
/// </item>
/// </list>
/// <para>If</para>
/// <para>dwControl</para>
/// <para>is</para>
/// <para>SERVICE_CONTROL_HARDWAREPROFILECHANGE</para>
/// <para>, this parameter can be one of the following values:</para>
/// <list type="bullet">
/// <item>
/// <term>DBT_CONFIGCHANGED</term>
/// </item>
/// <item>
/// <term>DBT_QUERYCHANGECONFIG</term>
/// </item>
/// <item>
/// <term>DBT_CONFIGCHANGECANCELED</term>
/// </item>
/// </list>
/// <para>If</para>
/// <para>dwControl</para>
/// <para>is</para>
/// <para>SERVICE_CONTROL_POWEREVENT</para>
/// <para>, this parameter can be one of the values specified in the</para>
/// <para>wParam</para>
/// <para>parameter of the</para>
/// <para>WM_POWERBROADCAST</para>
/// <para>message.</para>
/// <para>
/// If dwControl is <c>SERVICE_CONTROL_SESSIONCHANGE</c>, this parameter can be one of the values specified in the wParam parameter
/// of the WM_WTSSESSION_CHANGE message.
/// </para>
/// </param>
/// <param name="lpEventData">
/// <para>
/// Additional device information, if required. The format of this data depends on the value of the dwControl and dwEventType parameters.
/// </para>
/// <para>
/// If dwControl is <c>SERVICE_CONTROL_DEVICEEVENT</c>, this data corresponds to the lParam parameter that applications receive as
/// part of a WM_DEVICECHANGE message.
/// </para>
/// <para>
/// If dwControl is <c>SERVICE_CONTROL_POWEREVENT</c> and dwEventType is PBT_POWERSETTINGCHANGE, this data is a pointer to a
/// POWERBROADCAST_SETTING structure.
/// </para>
/// <para>If dwControl is <c>SERVICE_CONTROL_SESSIONCHANGE</c>, this parameter is a pointer to a WTSSESSION_NOTIFICATION structure.</para>
/// <para>If dwControl is <c>SERVICE_CONTROL_TIMECHANGE</c>, this data is a pointer to a SERVICE_TIMECHANGE_INFO structure.</para>
/// </param>
/// <param name="lpContext">
/// User-defined data passed from RegisterServiceCtrlHandlerEx. When multiple services share a process, the lpContext parameter can
/// help identify the service.
/// </param>
/// <returns>
/// <para>The return value for this function depends on the control code received.</para>
/// <para>The following list identifies the rules for this return value:</para>
/// <list type="bullet">
/// <item>
/// <term>
/// In general, if your service does not handle the control, return <c>ERROR_CALL_NOT_IMPLEMENTED</c>. However, your service should
/// return <c>NO_ERROR</c> for <c>SERVICE_CONTROL_INTERROGATE</c> even if your service does not handle it.
/// </term>
/// </item>
/// <item>
/// <term>If your service handles <c>SERVICE_CONTROL_STOP</c> or <c>SERVICE_CONTROL_SHUTDOWN</c>, return <c>NO_ERROR</c>.</term>
/// </item>
/// <item>
/// <term>
/// If your service handles <c>SERVICE_CONTROL_DEVICEEVENT</c>, return <c>NO_ERROR</c> to grant the request and an error code to deny
/// the request.
/// </term>
/// </item>
/// <item>
/// <term>
/// If your service handles <c>SERVICE_CONTROL_HARDWAREPROFILECHANGE</c>, return <c>NO_ERROR</c> to grant the request and an error
/// code to deny the request.
/// </term>
/// </item>
/// <item>
/// <term>
/// If your service handles <c>SERVICE_CONTROL_POWEREVENT</c>, return <c>NO_ERROR</c> to grant the request and an error code to deny
/// the request.
/// </term>
/// </item>
/// <item>
/// <term>For all other control codes your service handles, return <c>NO_ERROR</c>.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// When a service is started, its ServiceMain function should immediately call the RegisterServiceCtrlHandlerEx function to specify
/// a <c>HandlerEx</c> function to process control requests. To specify the control codes to be accepted, use the SetServiceStatus
/// and RegisterDeviceNotification functions.
/// </para>
/// <para>
/// The control dispatcher in the main thread of a service invokes the control handler function for the specified service whenever it
/// receives a control request from the service control manager. After processing the control request, the control handler must call
/// SetServiceStatus if the service state changes to report its new status to the service control manager.
/// </para>
/// <para>
/// The control handler function is intended to receive notification and return immediately. The callback function should save its
/// parameters and create other threads to perform additional work. (Your application must ensure that such threads have exited
/// before stopping the service.) In particular, a control handler should avoid operations that might block, such as taking a lock,
/// because this could result in a deadlock or cause the system to stop responding.
/// </para>
/// <para>
/// When the service control manager sends a control code to a service, it waits for the handler function to return before sending
/// additional control codes to other services. The control handler should return as quickly as possible; if it does not return
/// within 30 seconds, the SCM returns an error. If a service must do lengthy processing when the service is executing the control
/// handler, it should create a secondary thread to perform the lengthy processing, and then return from the control handler. This
/// prevents the service from tying up the control dispatcher and blocking other services from receiving control codes.
/// </para>
/// <para>
/// The <c>SERVICE_CONTROL_SHUTDOWN</c> control code should only be processed by services that must absolutely clean up during
/// shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system
/// shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not
/// restarted or powered down), the service continues to run. If your service registers to accept <c>SERVICE_CONTROL_SHUTDOWN</c>, it
/// must handle the control code and return <c>NO_ERROR</c>. Returning an error for this control code and not stopping in a timely
/// fashion can increase the time required to shut down the system, because the system must wait for the full amount of time allowed
/// for service shutdown before system shutdown can proceed.
/// </para>
/// <para>
/// If the service requires more time to clean up, it should send <c>STOP_PENDING</c> status messages, along with a wait hint, so the
/// service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a
/// service from stopping shutdown, there is a limit to how long the service controller waits. If the service is being shut down
/// through the Services snap-in, the limit is 125 seconds. If the operating system is rebooting, the time limit is specified in the
/// <c>WaitToKillServiceTimeout</c> value of the following registry key:
/// </para>
/// <para><c>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control</c></para>
/// <para>
/// Be sure to handle Plug and Play device events as quickly as possible; otherwise, the system may become unresponsive. If your
/// event handler is to perform an operation that may block execution (such as I/O), it is best to start another thread to perform
/// the operation asynchronously.
/// </para>
/// <para>
/// Services can also use the SetConsoleCtrlHandler function to receive shutdown notification. This notification is received when the
/// running applications are shutting down, which occurs before services are shut down.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nc-winsvc-lphandler_function_ex LPHANDLER_FUNCTION_EX
// LphandlerFunctionEx; DWORD LphandlerFunctionEx( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) {...}
[PInvokeData("winsvc.h", MSDNShortId = "bb1b863f-e29f-496f-a50e-9ea524fe8603")]
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate Win32Error HandlerEx(ServiceControl dwControl, uint dwEventType, IntPtr lpEventData, IntPtr lpContext);
/// <summary>Callback function used in <see cref="SERVICE_NOTIFY_2"/> to alert changes registered by <see cref="NotifyServiceStatusChange"/>.</summary>
/// <param name="pParameter">A pointer to the SERVICE_NOTIFY structure provided by the caller.</param>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
[PInvokeData("winsvc.h", MSDNShortId = "52ede72e-eb50-48e2-b5c1-125816f6fe57")]
public delegate void PFN_SC_NOTIFY_CALLBACK(IntPtr pParameter); //in SERVICE_NOTIFY_2 pParameter);
/// <summary>
/// <para>The entry point for a service.</para>
/// <para>
/// The <c>LPSERVICE_MAIN_FUNCTION</c> type defines a pointer to this callback function. <c>ServiceMain</c> is a placeholder for an
/// application-defined function name.
/// </para>
/// </summary>
/// <param name="dwNumServicesArgs">Number of arguments in the <paramref name="lpServiceArgVectors"/> array.</param>
/// <param name="lpServiceArgVectors">
/// Array of strings. The first string is the name of the service and subsequent strings are passed by the process that called the
/// StartService function to start the service.
/// </param>
/// <returns>This function does not return a value.</returns>
/// <remarks>
/// <para>
/// A service program can start one or more services. A service process has a SERVICE_TABLE_ENTRY structure for each service that it
/// can start. The structure specifies the service name and a pointer to the <c>ServiceMain</c> function for that service.
/// </para>
/// <para>
/// When the service control manager receives a request to start a service, it starts the service process (if it is not already
/// running). The main thread of the service process calls the StartServiceCtrlDispatcher function with a pointer to an array of
/// SERVICE_TABLE_ENTRY structures. Then the service control manager sends a start request to the service control dispatcher for this
/// service process. The service control dispatcher creates a new thread to execute the <c>ServiceMain</c> function of the service
/// being started.
/// </para>
/// <para>
/// The <c>ServiceMain</c> function should immediately call the RegisterServiceCtrlHandlerEx function to specify a HandlerEx function
/// to handle control requests. Next, it should call the SetServiceStatus function to send status information to the service control
/// manager. After these calls, the function should complete the initialization of the service. Do not attempt to start another
/// service in the <c>ServiceMain</c> function.
/// </para>
/// <para>
/// The Service Control Manager (SCM) waits until the service reports a status of SERVICE_RUNNING. It is recommended that the service
/// reports this status as quickly as possible, as other components in the system that require interaction with SCM will be blocked
/// during this time. Some functions may require interaction with the SCM either directly or indirectly.
/// </para>
/// <para>
/// The SCM locks the service control database during initialization, so if a service attempts to call StartService during
/// initialization, the call will block. When the service reports to the SCM that it has successfully started, it can call
/// <c>StartService</c>. If the service requires another service to be running, the service should set the required dependencies.
/// </para>
/// <para>
/// Furthermore, you should not call any system functions during service initialization. The service code should call system
/// functions only after it reports a status of SERVICE_RUNNING.
/// </para>
/// <para>
/// The <c>ServiceMain</c> function should create a global event, call the RegisterWaitForSingleObject function on this event, and
/// exit. This will terminate the thread that is running the <c>ServiceMain</c> function, but will not terminate the service. When
/// the service is stopping, the service control handler should call SetServiceStatus with SERVICE_STOP_PENDING and signal this
/// event. A thread from the thread pool will execute the wait callback function; this function should perform clean-up tasks,
/// including closing the global event, and call <c>SetServiceStatus</c> with SERVICE_STOPPED. After the service has stopped, you
/// should not execute any additional service code because you can introduce a race condition if the service receives a start control
/// and <c>ServiceMain</c> is called again. Note that this problem is more likely to occur when multiple services share a process.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Writing a ServiceMain Function.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nc-winsvc-lpservice_main_functiona LPSERVICE_MAIN_FUNCTIONA
// LpserviceMainFunctiona; void LpserviceMainFunctiona( DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors ) {...}
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "d7f3235e-91bd-4107-a30c-4a8f9a6c731e")]
public delegate void ServiceMain(uint dwNumServicesArgs, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeParamIndex = 0)] string[] lpServiceArgVectors);
/// <summary>Defines the action to be performed in a <see cref="SC_ACTION"/>.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "e2c355a6-affe-46bf-a3e6-f8c420422d46")]
public enum SC_ACTION_TYPE
{
/// <summary>No action.</summary>
SC_ACTION_NONE = 0,
/// <summary>Reboot the computer.</summary>
SC_ACTION_REBOOT = 2,
/// <summary>Restart the service.</summary>
SC_ACTION_RESTART = 1,
/// <summary>Run a command.</summary>
SC_ACTION_RUN_COMMAND = 3,
/// <summary>Undocumented.</summary>
SC_ACTION_OWN_RESTART = 4
}
/// <summary>The service attributes that are to be returned from <see cref="EnumServicesStatusEx(SC_HANDLE, ServiceTypes, SERVICE_STATE, string)"/>.</summary>
public enum SC_ENUM_TYPE
{
/// <summary>
/// Retrieve the name and service status information for each service in the database. The lpServices parameter is a pointer to a
/// buffer that receives an array of ENUM_SERVICE_STATUS_PROCESS structures.
/// </summary>
SC_ENUM_PROCESS_INFO = 0
}
/// <summary>Info levels for <see cref="QueryServiceStatusEx"/></summary>
public enum SC_STATUS_TYPE
{
/// <summary/>
[CorrespondingType(typeof(SERVICE_STATUS_PROCESS))]
SC_STATUS_PROCESS_INFO = 0
}
/// <summary>Service Control Manager object specific access types</summary>
[PInvokeData("winsvc.h")]
[Flags]
public enum ScManagerAccessTypes : uint
{
/// <summary>Required to connect to the service control manager.</summary>
SC_MANAGER_CONNECT = 0x0001,
/// <summary>Required to call the CreateService function to create a service object and add it to the database.</summary>
SC_MANAGER_CREATE_SERVICE = 0x0002,
/// <summary>
/// Required to call the <see cref="EnumServicesStatus(SC_HANDLE, ServiceTypes, SERVICE_STATE)"/> or <see cref="EnumServicesStatusEx(SC_HANDLE, ServiceTypes, SERVICE_STATE, string)"/> function to list the services
/// that are in the database. Required to call the <see cref="NotifyServiceStatusChange"/> function to receive notification when
/// any service is created or deleted.
/// </summary>
SC_MANAGER_ENUMERATE_SERVICE = 0x0004,
/// <summary>Required to call the <see cref="LockServiceDatabase"/> function to acquire a lock on the database.</summary>
SC_MANAGER_LOCK = 0x0008,
/// <summary>
/// Required to call the <see cref="QueryServiceLockStatus"/> function to retrieve the lock status information for the database.
/// </summary>
SC_MANAGER_QUERY_LOCK_STATUS = 0x0010,
/// <summary>Required to call the <see cref="NotifyBootConfigStatus"/> function.</summary>
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020,
/// <summary>Includes <see cref="ACCESS_MASK.STANDARD_RIGHTS_REQUIRED"/>, in addition to all access rights in this table.</summary>
SC_MANAGER_ALL_ACCESS = ACCESS_MASK.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
}
/// <summary>The type of status changes that should be reported.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "e22b7f69-f096-486f-97fa-0465bef499cd")]
[Flags]
public enum SERVICE_NOTIFY_FLAGS
{
/// <summary>
/// Report when the service has been created.
/// <para>The hService parameter must be a handle to the SCM.</para>
/// </summary>
SERVICE_NOTIFY_CREATED = 0x00000080,
/// <summary>
/// Report when the service is about to continue.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_CONTINUE_PENDING = 0x00000010,
/// <summary>
/// Report when an application has specified the service in a call to the DeleteService function. Your application should close
/// any handles to the service so it can be deleted.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_DELETE_PENDING = 0x00000200,
/// <summary>
/// Report when the service has been deleted. An application cannot receive this notification if it has an open handle to the service.
/// <para>The hService parameter must be a handle to the SCM.</para>
/// </summary>
SERVICE_NOTIFY_DELETED = 0x00000100,
/// <summary>
/// Report when the service is pausing.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_PAUSE_PENDING = 0x00000020,
/// <summary>
/// Report when the service has paused.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_PAUSED = 0x00000040,
/// <summary>
/// Report when the service is running.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_RUNNING = 0x00000008,
/// <summary>
/// Report when the service is starting.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_START_PENDING = 0x00000002,
/// <summary>
/// Report when the service is stopping.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_STOP_PENDING = 0x00000004,
/// <summary>
/// Report when the service has stopped.
/// <para>The hService parameter must be a handle to the service.</para>
/// </summary>
SERVICE_NOTIFY_STOPPED = 0x00000001,
}
/// <summary>The state of the services to be enumerated.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "905d4453-96d4-4055-8a17-36714c547cdd")]
[Flags]
public enum SERVICE_STATE
{
/// <summary>
/// Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING,
/// SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
/// </summary>
SERVICE_ACTIVE = 0x00000001,
/// <summary>Enumerates services that are in the SERVICE_STOPPED state.</summary>
SERVICE_INACTIVE = 0x00000002,
/// <summary>Combines the following states: SERVICE_ACTIVE and SERVICE_INACTIVE.</summary>
SERVICE_STATE_ALL = 0x00000003,
}
/// <summary/>
[Flags]
public enum SERVICE_STOP_REASON : uint
{
// Stop reason flags. Update SERVICE_STOP_REASON_FLAG_MAX when new flags are added.
/// <summary/>
SERVICE_STOP_REASON_FLAG_MIN = 0x00000000,
/// <summary/>
SERVICE_STOP_REASON_FLAG_UNPLANNED = 0x10000000,
/// <summary/>
SERVICE_STOP_REASON_FLAG_CUSTOM = 0x20000000,
/// <summary/>
SERVICE_STOP_REASON_FLAG_PLANNED = 0x40000000,
/// <summary/>
SERVICE_STOP_REASON_FLAG_MAX = 0x80000000,
// Microsoft major reasons. Update SERVICE_STOP_REASON_MAJOR_MAX when new codes are added.
/// <summary/>
SERVICE_STOP_REASON_MAJOR_MIN = 0x00000000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_OTHER = 0x00010000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_HARDWARE = 0x00020000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_OPERATINGSYSTEM = 0x00030000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_SOFTWARE = 0x00040000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_APPLICATION = 0x00050000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_NONE = 0x00060000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_MAX = 0x00070000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_MIN_CUSTOM = 0x00400000,
/// <summary/>
SERVICE_STOP_REASON_MAJOR_MAX_CUSTOM = 0x00ff0000,
// Microsoft minor reasons. Update SERVICE_STOP_REASON_MINOR_MAX when new codes are added.
/// <summary/>
SERVICE_STOP_REASON_MINOR_MIN = 0x00000000,
/// <summary/>
SERVICE_STOP_REASON_MINOR_OTHER = 0x00000001,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MAINTENANCE = 0x00000002,
/// <summary/>
SERVICE_STOP_REASON_MINOR_INSTALLATION = 0x00000003,
/// <summary/>
SERVICE_STOP_REASON_MINOR_UPGRADE = 0x00000004,
/// <summary/>
SERVICE_STOP_REASON_MINOR_RECONFIG = 0x00000005,
/// <summary/>
SERVICE_STOP_REASON_MINOR_HUNG = 0x00000006,
/// <summary/>
SERVICE_STOP_REASON_MINOR_UNSTABLE = 0x00000007,
/// <summary/>
SERVICE_STOP_REASON_MINOR_DISK = 0x00000008,
/// <summary/>
SERVICE_STOP_REASON_MINOR_NETWORKCARD = 0x00000009,
/// <summary/>
SERVICE_STOP_REASON_MINOR_ENVIRONMENT = 0x0000000a,
/// <summary/>
SERVICE_STOP_REASON_MINOR_HARDWARE_DRIVER = 0x0000000b,
/// <summary/>
SERVICE_STOP_REASON_MINOR_OTHERDRIVER = 0x0000000c,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SERVICEPACK = 0x0000000d,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE = 0x0000000e,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SECURITYFIX = 0x0000000f,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SECURITY = 0x00000010,
/// <summary/>
SERVICE_STOP_REASON_MINOR_NETWORK_CONNECTIVITY = 0x00000011,
/// <summary/>
SERVICE_STOP_REASON_MINOR_WMI = 0x00000012,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SERVICEPACK_UNINSTALL = 0x00000013,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE_UNINSTALL = 0x00000014,
/// <summary/>
SERVICE_STOP_REASON_MINOR_SECURITYFIX_UNINSTALL = 0x00000015,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MMC = 0x00000016,
/// <summary/>
SERVICE_STOP_REASON_MINOR_NONE = 0x00000017,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MEMOTYLIMIT = 0x00000018,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MAX = 0x00000019,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MIN_CUSTOM = 0x00000100,
/// <summary/>
SERVICE_STOP_REASON_MINOR_MAX_CUSTOM = 0x0000FFFF
}
/// <summary>Service control codes.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "d268609b-d442-4d0f-9d49-ed23fee84961")]
[Flags]
public enum ServiceAcceptedControlCodes : uint
{
/// <summary>The service can be stopped. This control code allows the service to receive SERVICE_CONTROL_STOP notifications.</summary>
SERVICE_ACCEPT_STOP = 0x00000001,
/// <summary>
/// The service can be paused and continued. This control code allows the service to receive SERVICE_CONTROL_PAUSE and
/// SERVICE_CONTROL_CONTINUE notifications.
/// </summary>
SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002,
/// <summary>
/// The service is notified when system shutdown occurs. This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// </summary>
SERVICE_ACCEPT_SHUTDOWN = 0x00000004,
/// <summary>
/// The service can reread its startup parameters without being stopped and restarted. This control code allows the service to
/// receive SERVICE_CONTROL_PARAMCHANGE notifications.
/// </summary>
SERVICE_ACCEPT_PARAMCHANGE = 0x00000008,
/// <summary>
/// The service is a network component that can accept changes in its binding without being stopped and restarted. This control
/// code allows the service to receive SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE,
/// and SERVICE_CONTROL_NETBINDDISABLE notifications.
/// </summary>
SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010,
/// <summary>
/// The service is notified when the computer's hardware profile has changed. This enables the system to send
/// SERVICE_CONTROL_HARDWAREPROFILECHANGE notifications to the service.
/// </summary>
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020,
/// <summary>
/// The service is notified when the computer's power status has changed. This enables the system to send
/// SERVICE_CONTROL_POWEREVENT notifications to the service.
/// </summary>
SERVICE_ACCEPT_POWEREVENT = 0x00000040,
/// <summary>
/// The service is notified when the computer's session status has changed. This enables the system to send
/// SERVICE_CONTROL_SESSIONCHANGE notifications to the service.
/// </summary>
SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080,
/// <summary>
/// The service can perform preshutdown tasks. This control code enables the service to receive SERVICE_CONTROL_PRESHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// Windows Server 2003 and Windows XP: This value is not supported.
/// </summary>
SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100,
/// <summary>
/// The service is notified when the system time has changed. This enables the system to send SERVICE_CONTROL_TIMECHANGE
/// notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is
/// not supported.
/// </summary>
SERVICE_ACCEPT_TIMECHANGE = 0x00000200,
/// <summary>
/// The service is notified when an event for which the service has registered occurs. This enables the system to send
/// SERVICE_CONTROL_TRIGGEREVENT notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and
/// Windows XP: This control code is not supported.
/// </summary>
SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400,
/// <summary>
/// The services is notified when the user initiates a reboot. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows
/// Vista, Windows Server 2003 and Windows XP: This control code is not supported.
/// </summary>
SERVICE_ACCEPT_USER_LOGOFF = 0x00000800,
/// <summary>Undocumented.</summary>
SERVICE_ACCEPT_LOWRESOURCES = 0x00002000,
/// <summary>Undocumented.</summary>
SERVICE_ACCEPT_SYSTEMLOWRESOURCES = 0x00004000,
}
/// <summary>Service access rights.</summary>
[Flags]
public enum ServiceAccessRights : uint
{
/// <summary>Includes STANDARD_RIGHTS_REQUIRED in addition to all access rights in this table.</summary>
SERVICE_ALL_ACCESS = 0xF01FF,
/// <summary>
/// Required to call the ChangeServiceConfig or ChangeServiceConfig2 function to change the service configuration. Because this
/// grants the caller the right to change the executable file that the system runs, it should be granted only to administrators.
/// </summary>
SERVICE_CHANGE_CONFIG = 0x0002,
/// <summary>Required to call the EnumDependentServices function to enumerate all the services dependent on the service.</summary>
SERVICE_ENUMERATE_DEPENDENTS = 0x0008,
/// <summary>Required to call the ControlService function to ask the service to report its status immediately.</summary>
SERVICE_INTERROGATE = 0x0080,
/// <summary>Required to call the ControlService function to pause or continue the service.</summary>
SERVICE_PAUSE_CONTINUE = 0x0040,
/// <summary>Required to call the QueryServiceConfig and QueryServiceConfig2 functions to query the service configuration.</summary>
SERVICE_QUERY_CONFIG = 0x0001,
/// <summary>
/// Required to call the QueryServiceStatus or QueryServiceStatusEx function to ask the service control manager about the status
/// of the service.
/// <para>Required to call the NotifyServiceStatusChange function to receive notification when a service changes status.</para>
/// </summary>
SERVICE_QUERY_STATUS = 0x0004,
/// <summary>Required to call the StartService function to start the service.</summary>
SERVICE_START = 0x0010,
/// <summary>Required to call the ControlService function to stop the service.</summary>
SERVICE_STOP = 0x0020,
/// <summary>Required to call the ControlService function to specify a user-defined control code.</summary>
SERVICE_USER_DEFINED_CONTROL = 0x0100,
/// <summary>
/// Required to call the QueryServiceObjectSecurity or SetServiceObjectSecurity function to access the SACL. The proper way to
/// obtain this access is to enable the SE_SECURITY_NAMEprivilege in the caller's current access token, open the handle for
/// ACCESS_SYSTEM_SECURITY access, and then disable the privilege.
/// </summary>
ACCESS_SYSTEM_SECURITY = 0x01000000,
/// <summary>Required to call the DeleteService function to delete the service.</summary>
DELETE = ACCESS_MASK.DELETE,
/// <summary>Required to call the QueryServiceObjectSecurity function to query the security descriptor of the service object.</summary>
READ_CONTROL = ACCESS_MASK.READ_CONTROL,
/// <summary>
/// Required to call the SetServiceObjectSecurity function to modify the Dacl member of the service object's security descriptor.
/// </summary>
WRITE_DAC = ACCESS_MASK.WRITE_DAC,
/// <summary>
/// Required to call the SetServiceObjectSecurity function to modify the Owner and Group members of the service object's security descriptor.
/// </summary>
WRITE_OWNER = ACCESS_MASK.WRITE_OWNER,
/// <summary/>
GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS,
/// <summary/>
GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG,
/// <summary/>
GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL,
}
/// <summary>Service object specific access type</summary>
[PInvokeData("winsvc.h")]
[Flags]
public enum ServiceAccessTypes : uint
{
/// <summary>
/// Required to call the <see cref="QueryServiceConfig"/> and <see cref="QueryServiceConfig2"/> functions to query the service configuration.
/// </summary>
SERVICE_QUERY_CONFIG = 0x0001,
/// <summary>
/// Required to call the <see cref="ChangeServiceConfig(SC_HANDLE, ServiceTypes, ServiceStartType, ServiceErrorControlType, string, string, IntPtr, string, string, string, string)"/> or <see cref="ChangeServiceConfig2"/> function to change the service
/// configuration. Because this grants the caller the right to change the executable file that the system runs, it should be
/// granted only to administrators.
/// </summary>
SERVICE_CHANGE_CONFIG = 0x0002,
/// <summary>
/// Required to call the <see cref="QueryServiceStatus"/> or <see cref="QueryServiceStatusEx"/> function to ask the service
/// control manager about the status of the service. Required to call the <see cref="NotifyServiceStatusChange"/> function to
/// receive notification when a service changes status.
/// </summary>
SERVICE_QUERY_STATUS = 0x0004,
/// <summary>
/// Required to call the <see cref="EnumDependentServices(SC_HANDLE, SERVICE_STATE)"/> function to enumerate all the services dependent on the service.
/// </summary>
SERVICE_ENUMERATE_DEPENDENTS = 0x0008,
/// <summary>Required to call the <see cref="StartService"/> function to start the service.</summary>
SERVICE_START = 0x0010,
/// <summary>Required to call the <see cref="ControlService"/> function to stop the service.</summary>
SERVICE_STOP = 0x0020,
/// <summary>Required to call the <see cref="ControlService"/> function to pause or continue the service.</summary>
SERVICE_PAUSE_CONTINUE = 0x0040,
/// <summary>Required to call the <see cref="ControlService"/> function to ask the service to report its status immediately.</summary>
SERVICE_INTERROGATE = 0x0080,
/// <summary>Required to call the <see cref="ControlService"/> function to specify a user-defined control code.</summary>
SERVICE_USER_DEFINED_CONTROL = 0x0100,
/// <summary>Includes <see cref="ACCESS_MASK.STANDARD_RIGHTS_REQUIRED"/> in addition to all access rights in this table.</summary>
SERVICE_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL
}
/// <summary>Used by the <see cref="ChangeServiceConfig2"/> method.</summary>
public enum ServiceConfigOption : uint
{
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_DELAYED_AUTO_START_INFO structure.
/// <para><c>Windows Server 2003 and Windows XP:</c> This value is not supported.</para>
/// </summary>
[CorrespondingType(typeof(SERVICE_DELAYED_AUTO_START_INFO))]
SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3,
/// <summary>The lpInfo parameter is a pointer to a SERVICE_DESCRIPTION structure.</summary>
[CorrespondingType(typeof(SERVICE_DESCRIPTION))]
SERVICE_CONFIG_DESCRIPTION = 1,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.
/// <para>
/// If the service controller handles the SC_ACTION_REBOOT action, the caller must have the SE_SHUTDOWN_NAME privilege. For more
/// information, see Running with Special Privileges.
/// </para>
/// </summary>
[CorrespondingType(typeof(SERVICE_FAILURE_ACTIONS))]
SERVICE_CONFIG_FAILURE_ACTIONS = 2,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS_FLAG structure.
/// <para><c>Windows Server 2003 and Windows XP:</c> This value is not supported.</para>
/// </summary>
[CorrespondingType(typeof(SERVICE_FAILURE_ACTIONS_FLAG))]
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_PREFERRED_NODE_INFO structure.
/// <para><c>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:</c> This value is not supported.</para>
/// </summary>
[CorrespondingType(typeof(SERVICE_PREFERRED_NODE_INFO))]
SERVICE_CONFIG_PREFERRED_NODE = 9,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_PRESHUTDOWN_INFO structure.
/// <para><c>Windows Server 2003 and Windows XP:</c> This value is not supported.</para>
/// </summary>
[CorrespondingType(typeof(SERVICE_PRESHUTDOWN_INFO))]
SERVICE_CONFIG_PRESHUTDOWN_INFO = 7,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_REQUIRED_PRIVILEGES_INFO structure.
/// <para><c>Windows Server 2003 and Windows XP:</c> This value is not supported.</para>
/// </summary>
[CorrespondingType(typeof(SERVICE_REQUIRED_PRIVILEGES_INFO))]
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6,
/// <summary>The lpInfo parameter is a pointer to a SERVICE_SID_INFO structure.</summary>
[CorrespondingType(typeof(SERVICE_SID_INFO))]
SERVICE_CONFIG_SERVICE_SID_INFO = 5,
/// <summary>
/// The lpInfo parameter is a pointer to a SERVICE_TRIGGER_INFO structure. This value is not supported by the ANSI version of ChangeServiceConfig2.
/// <para>
/// <c>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:</c> This value is not supported until Windows
/// Server 2008 R2.
/// </para>
/// </summary>
[CorrespondingType(typeof(SERVICE_TRIGGER_INFO))]
SERVICE_CONFIG_TRIGGER_INFO = 8,
/// <summary>
/// <para>The lpInfo parameter is a pointer a SERVICE_LAUNCH_P/// ROTECTED_INFO structure.</para>
/// <note>This value is supported starting with Windows 8.1.</note>
/// </summary>
[CorrespondingType(typeof(SERVICE_LAUNCH_PROTECTED_INFO))]
SERVICE_CONFIG_LAUNCH_PROTECTED = 12,
}
/// <summary>Service control codes to be used with <see cref="ControlService"/> and <see cref="ControlServiceEx"/></summary>
public enum ServiceControl : uint
{
/// <summary>Notifies a service that it should pause. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.</summary>
SERVICE_CONTROL_PAUSE = 0x00000002,
/// <summary>
/// Notifies a paused service that it should resume. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.
/// </summary>
SERVICE_CONTROL_CONTINUE = 0x00000003,
/// <summary>
/// Notifies a service that it should report its current status information to the service control manager. The hService handle
/// must have the SERVICE_INTERROGATE access right. Note that this control is not generally useful as the SCM is aware of the
/// current state of the service
/// </summary>
SERVICE_CONTROL_INTERROGATE = 0x00000004,
/// <summary>
/// Notifies a service that its startup parameters have changed. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.
/// </summary>
SERVICE_CONTROL_PARAMCHANGE = 0x00000006,
/// <summary>
/// Notifies a network service that there is a new component for binding. The hService handle must have the
/// SERVICE_PAUSE_CONTINUE access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </summary>
SERVICE_CONTROL_NETBINDADD = 0x00000007,
/// <summary>
/// Notifies a network service that a component for binding has been removed. The hService handle must have the
/// SERVICE_PAUSE_CONTINUE access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </summary>
SERVICE_CONTROL_NETBINDREMOVE = 0x00000008,
/// <summary>
/// Notifies a network service that a disabled binding has been enabled. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </summary>
SERVICE_CONTROL_NETBINDENABLE = 0x00000009,
/// <summary>
/// Notifies a network service that one of its bindings has been disabled. The hService handle must have the
/// SERVICE_PAUSE_CONTINUE access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </summary>
SERVICE_CONTROL_NETBINDDISABLE = 0x0000000A,
//#define SERVICE_CONTROL_USER_LOGOFF = 0x00000011
//reserved for internal use = 0x00000021
//reserved for internal use = 0x00000050
/// <summary></summary>
SERVICE_CONTROL_LOWRESOURCES = 0x00000060,
/// <summary></summary>
SERVICE_CONTROL_SYSTEMLOWRESOURCES = 0x00000061,
/// <summary>
/// Notifies a service that the system will be shutting down. Services that need additional time to perform cleanup tasks beyond
/// the tight time restriction at system shutdown can use this notification. The service control manager sends this notification
/// to applications that have registered for it before sending a SERVICE_CONTROL_SHUTDOWN notification to applications that have
/// registered for that notification.
/// <para>
/// A service that handles this notification blocks system shutdown until the service stops or the pre-shutdown time-out interval
/// specified through SERVICE_PRESHUTDOWN_INFO expires. Because this affects the user experience, services should use this
/// feature only if it is absolutely necessary to avoid data loss or significant recovery time at the next system start.
/// </para>
/// <para>Windows Server 2003 and Windows XP: This value is not supported.</para>
/// </summary>
SERVICE_CONTROL_PRESHUTDOWN = 0x0000000F,
/// <summary>
/// Notifies a service that the system is shutting down so the service can perform cleanup tasks. Note that services that
/// register for SERVICE_CONTROL_PRESHUTDOWN notifications cannot receive this notification because they have already stopped.
/// <para>
/// If a service accepts this control code, it must stop after it performs its cleanup tasks and return NO_ERROR. After the SCM
/// sends this control code, it will not send other control codes to the service.
/// </para>
/// <para>For more information, see the Remarks section of this topic.</para>
/// </summary>
SERVICE_CONTROL_SHUTDOWN = 0x00000005,
/// <summary>
/// Notifies a service that it should stop.
/// <para>
/// If a service accepts this control code, it must stop upon receipt and return NO_ERROR. After the SCM sends this control code,
/// it will not send other control codes to the service. Windows XP: If the service returns NO_ERROR and continues to run, it
/// continues to receive control codes. This behavior changed starting with Windows Server 2003 and Windows XP with SP2.
/// </para>
/// <para>
/// This parameter can also be one of the following extended control codes. Note that these control codes are not supported by
/// the Handler function.
/// </para>
/// </summary>
SERVICE_CONTROL_STOP = 0x00000001,
/// <summary>
/// Notifies a service of device events. (The service must have registered to receive these notifications using the
/// RegisterDeviceNotification function.) The dwEventType and lpEventData parameters contain additional information.
/// </summary>
SERVICE_CONTROL_DEVICEEVENT = 0x0000000B,
/// <summary>
/// Notifies a service that the computer's hardware profile has changed. The dwEventType parameter contains additional information.
/// </summary>
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 0x0000000C,
/// <summary>
/// Notifies a service of system power events. The dwEventType parameter contains additional information. If dwEventType is
/// PBT_POWERSETTINGCHANGE, the lpEventData parameter also contains additional information.
/// </summary>
SERVICE_CONTROL_POWEREVENT = 0x0000000D,
/// <summary>
/// Notifies a service of session change events. Note that a service will only be notified of a user logon if it is fully loaded
/// before the logon attempt is made. The dwEventType and lpEventData parameters contain additional information.
/// </summary>
SERVICE_CONTROL_SESSIONCHANGE = 0x0000000E,
/// <summary>
/// Notifies a service that the system time has changed. The lpEventData parameter contains additional information. The
/// dwEventType parameter is not used.
/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is not supported.</para>
/// </summary>
SERVICE_CONTROL_TIMECHANGE = 0x00000010,
/// <summary>
/// Notifies a service registered for a service trigger event that the event has occurred.
/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is not supported.</para>
/// </summary>
SERVICE_CONTROL_TRIGGEREVENT = 0x00000020,
/// <summary>
/// Notifies a service that the user has initiated a reboot.
/// <para>
/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code
/// is not supported.
/// </para>
/// </summary>
SERVICE_CONTROL_USERMODEREBOOT = 0x00000040,
}
/// <summary>Info levels for <see cref="ControlServiceEx"/></summary>
public enum ServiceInfoLevels : uint
{
/// <summary/>
[CorrespondingType(typeof(SERVICE_CONTROL_STATUS_REASON_PARAMS))]
SERVICE_CONTROL_STATUS_REASON_INFO = 1
}
/// <summary/>
[Flags]
public enum ServiceStartReason : uint
{
/// <summary/>
SERVICE_START_REASON_DEMAND = 1 << 0,
/// <summary/>
SERVICE_START_REASON_AUTO = 1 << 1,
/// <summary/>
SERVICE_START_REASON_TRIGGER = 1 << 2,
/// <summary/>
SERVICE_START_REASON_RESTART_ON_FAILURE = 1 << 3,
/// <summary/>
SERVICE_START_REASON_DELAYEDAUTO = 1 << 4,
}
/// <summary>The current state of the service.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "d268609b-d442-4d0f-9d49-ed23fee84961")]
public enum ServiceState : uint
{
/// <summary>The service continue is pending.</summary>
SERVICE_CONTINUE_PENDING = 0x00000005,
/// <summary>The service pause is pending.</summary>
SERVICE_PAUSE_PENDING = 0x00000006,
/// <summary>The service is paused.</summary>
SERVICE_PAUSED = 0x00000007,
/// <summary>The service is running.</summary>
SERVICE_RUNNING = 0x00000004,
/// <summary>The service is starting.</summary>
SERVICE_START_PENDING = 0x00000002,
/// <summary>The service is stopping.</summary>
SERVICE_STOP_PENDING = 0x00000003,
/// <summary>The service is not running.</summary>
SERVICE_STOPPED = 0x00000001,
}
/// <summary>Service trigger action types referenced by <see cref="SERVICE_TRIGGER"/>.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "a57aa702-40a2-4880-80db-6c4f43c3e7ea")]
public enum ServiceTriggerAction : uint
{
/// <summary>Start the service when the specified trigger event occurs.</summary>
SERVICE_TRIGGER_ACTION_SERVICE_START = 1,
/// <summary>Stop the service when the specified trigger event occurs.</summary>
SERVICE_TRIGGER_ACTION_SERVICE_STOP = 2,
}
/// <summary>The data type of the trigger-specific data pointed to by <c>pData</c> in <see cref="SERVICE_TRIGGER_SPECIFIC_DATA_ITEM"/>.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "670e6c49-bbc0-4af6-9e47-6c89801ebb45")]
public enum ServiceTriggerDataType
{
/// <summary>The trigger-specific data is in binary format.</summary>
SERVICE_TRIGGER_DATA_TYPE_BINARY = 1,
/// <summary>The trigger-specific data is in string format.</summary>
SERVICE_TRIGGER_DATA_TYPE_STRING = 2,
/// <summary>The trigger-specific data is a byte value.</summary>
SERVICE_TRIGGER_DATA_TYPE_LEVEL = 3,
/// <summary>The trigger-specific data is a 64-bit unsigned integer value.</summary>
SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY = 4,
/// <summary>The trigger-specific data is a 64-bit unsigned integer value.</summary>
SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL = 5,
}
/// <summary>Service trigger types referenced by <see cref="SERVICE_TRIGGER"/>.</summary>
[PInvokeData("winsvc.h", MSDNShortId = "a57aa702-40a2-4880-80db-6c4f43c3e7ea")]
public enum ServiceTriggerType
{
/// <summary>
/// The event is triggered when a device of the specified device interface class arrives or is present when the system starts.
/// This trigger event is commonly used to start a service. The pTriggerSubtype member specifies the device interface class GUID.
/// These GUIDs are defined in device-specific header files provided with the Windows Driver Kit (WDK). The pDataItems member
/// specifies one or more hardware ID and compatible ID strings for the device interface class. Strings must be Unicode. If more
/// than one string is specified, the event is triggered if any one of the strings match. For example, the Wpdbusenum service is
/// started when a device of device interface class GUID_DEVINTERFACE_DISK {53f56307-b6bf-11d0-94f2-00a0c91efb8b} and a hardware
/// ID string of arrives.
/// </summary>
SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL = 1,
/// <summary>
/// The event is triggered when the first IP address on the TCP/IP networking stack becomes available or the last IP address on
/// the stack becomes unavailable. This trigger event can be used to start or stop a service. The pTriggerSubtype member
/// specifies NETWORK_MANAGER_FIRST_IP_ADDRESS_ARRIVAL_GUID or NETWORK_MANAGER_LAST_IP_ADDRESS_REMOVAL_GUID. The pDataItems
/// member is not used.
/// </summary>
SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY = 2,
/// <summary>
/// The event is triggered when the computer joins or leaves a domain. This trigger event can be used to start or stop a service.
/// The pTriggerSubtype member specifies DOMAIN_JOIN_GUID or DOMAIN_LEAVE_GUID. The pDataItems member is not used.
/// </summary>
SERVICE_TRIGGER_TYPE_DOMAIN_JOIN = 3,
/// <summary>
/// The event is triggered when a firewall port is opened or approximately 60 seconds after the firewall port is closed. This
/// trigger event can be used to start or stop a service. The pTriggerSubtype member specifies FIREWALL_PORT_OPEN_GUID or
/// FIREWALL_PORT_CLOSE_GUID. The pDataItems member specifies the port, the protocol, and optionally the executable path and user
/// information (SID string or name) of the service listening on the event. The "RPC" token can be used in place of the port to
/// specify any listening socket used by RPC. The "system" token can be used in place of the executable path to specify ports
/// created by and listened on by the Windows kernel. The event is triggered only if all strings match. For example, if MyService
/// hosted inside MyServiceProcess.exe is to be trigger-started when port UDP 5001 opens, the trigger-specific data would be the
/// Unicode representation of .
/// </summary>
SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT = 4,
/// <summary>
/// The event is triggered when a machine policy or user policy change occurs. This trigger event is commonly used to start a
/// service. The pTriggerSubtype member specifies MACHINE_POLICY_PRESENT_GUID or USER_POLICY_PRESENT_GUID. The pDataItems member
/// is not used.
/// </summary>
SERVICE_TRIGGER_TYPE_GROUP_POLICY = 5,
/// <summary>
/// The event is triggered when a packet or request arrives on a particular network protocol. This request is commonly used to
/// start a service that has stopped itself after an idle time-out when there is no work to do. Windows 7 and Windows Server 2008
/// R2: This trigger type is not supported until Windows 8 and Windows Server 2012. The pTriggerSubtype member specifies one of
/// the following values: RPC_INTERFACE_EVENT_GUID or NAMED_PIPE_EVENT_GUID. The pDataItems member specifies an endpoint or
/// interface GUID. The string must be Unicode. The event triggers if the string is an exact match. The dwAction member must be SERVICE_TRIGGER_ACTION_SERVICE_START.
/// </summary>
SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT = 6,
/// <summary>Undocumented.</summary>
SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE = 7,
/// <summary>
/// The event is a custom event generated by an Event Tracing for Windows (ETW) provider. This trigger event can be used to start
/// or stop a service. The pTriggerSubtype member specifies the event provider's GUID. The pDataItems member specifies
/// trigger-specific data defined by the provider.
/// </summary>
SERVICE_TRIGGER_TYPE_CUSTOM = 20,
/// <summary>Undocumented.</summary>
SERVICE_TRIGGER_TYPE_AGGREGATE = 30,
}
/// <summary>Changes the configuration parameters of a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// SERVICE_CHANGE_CONFIG access right.
/// </param>
/// <param name="nServiceType">
/// The type of service. Specify SERVICE_NO_CHANGE if you are not changing the existing service type. If you specify either
/// SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the context of the LocalSystem account,
/// you can also specify SERVICE_INTERACTIVE_PROCESS.
/// </param>
/// <param name="nStartType">The service start options. Specify SERVICE_NO_CHANGE if you are not changing the existing start type.</param>
/// <param name="nErrorControl">
/// The severity of the error, and action taken, if this service fails to start. Specify SERVICE_NO_CHANGE if you are not changing
/// the existing error control.
/// </param>
/// <param name="lpBinaryPathName">
/// The fully qualified path to the service binary file. Specify NULL if you are not changing the existing path. If the path contains
/// a space, it must be quoted so that it is correctly interpreted. For example, "d:\\my share\\myservice.exe" should be specified as
/// "\"d:\\my share\\myservice.exe\"".
/// <para>
/// The path can also include arguments for an auto-start service. For example, "d:\\myshare\\myservice.exe arg1 arg2". These
/// arguments are passed to the service entry point (typically the main function).
/// </para>
/// <para>
/// If you specify a path on another computer, the share must be accessible by the computer account of the local computer because
/// this is the security context used in the remote call. However, this requirement allows any potential vulnerabilities in the
/// remote computer to affect the local computer. Therefore, it is best to use a local file.
/// </para>
/// </param>
/// <param name="lpLoadOrderGroup">
/// The name of the load ordering group of which this service is a member. Specify NULL if you are not changing the existing group.
/// Specify an empty string if the service does not belong to a group.
/// <para>
/// The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups.
/// The list of load ordering groups is contained in the ServiceGroupOrder value of the following registry key:
/// </para>
/// <para>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</para>
/// </param>
/// <param name="lpdwTagId">
/// A pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter.
/// Specify NULL if you are not changing the existing tag.
/// <para>
/// You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the
/// GroupOrderList value of the following registry key:
/// </para>
/// <para>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</para>
/// <para>Tags are only evaluated for driver services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.</para>
/// </param>
/// <param name="lpDependencies">
/// A pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must
/// start before this service can be started. (Dependency on a group means that this service can run if at least one member of the
/// group is running after an attempt to start all members of the group.) Specify NULL if you are not changing the existing
/// dependencies. Specify an empty string if the service has no dependencies.
/// <para>
/// You must prefix group names with SC_GROUP_IDENTIFIER so that they can be distinguished from a service name, because services and
/// service groups share the same name space.
/// </para>
/// </param>
/// <param name="lpServiceStartName">
/// The name of the account under which the service should run. Specify NULL if you are not changing the existing account name. If
/// the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be
/// logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName (note that the corresponding
/// C/C++ string is ".\\UserName"). For more information, see Service User Accounts and the warning in the Remarks section.
/// <para>A shared process can run as any user.</para>
/// <para>
/// If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, the name is the driver object name that the system
/// uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.
/// </para>
/// <para>
/// A service can be configured to use a managed account or a virtual account. If the service is configured to use a managed service
/// account, the name is the managed service account name. If the service is configured to use a virtual account, specify the name as
/// NT SERVICE\ServiceName. For more information about managed service accounts and virtual accounts, see the Service Accounts
/// Step-by-Step Guide.
/// </para>
/// <para>
/// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: Managed service accounts and virtual accounts are not
/// supported until Windows 7 and Windows Server 2008 R2.
/// </para>
/// </param>
/// <param name="lpPassword">
/// The password to the account name specified by the lpServiceStartName parameter. Specify NULL if you are not changing the existing
/// password. Specify an empty string if the account has no password or if the service runs in the LocalService, NetworkService, or
/// LocalSystem account. For more information, see Service Record List.
/// <para>
/// If the account name specified by the lpServiceStartName parameter is the name of a managed service account or virtual account
/// name, the lpPassword parameter must be NULL.
/// </para>
/// <para>Passwords are ignored for driver services.</para>
/// </param>
/// <param name="lpDisplayName">
/// The display name to be used by applications to identify the service for its users. Specify NULL if you are not changing the
/// existing display name; otherwise, this string has a maximum length of 256 characters. The name is case-preserved in the service
/// control manager. Display name comparisons are always case-insensitive.
/// <para>This parameter can specify a localized string using the following format:</para>
/// <para>@[path\]dllname,-strID</para>
/// <para>The string with identifier strID is loaded from dllname; the path is optional. For more information, see RegLoadMUIString.</para>
/// <para>Windows Server 2003 and Windows XP: Localized strings are not supported until Windows Vista.</para>
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.To get extended error
/// information, call GetLastError.
/// </returns>
[DllImport(Lib.AdvApi32, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[PInvokeData("winsvc.h", MSDNShortId = "ms681987")]
public static extern bool ChangeServiceConfig(SC_HANDLE hService, ServiceTypes nServiceType, ServiceStartType nStartType, ServiceErrorControlType nErrorControl,
[Optional] string lpBinaryPathName, [Optional] string lpLoadOrderGroup, out uint lpdwTagId, [In, Optional] string lpDependencies,
[Optional] string lpServiceStartName, [Optional] string lpPassword, [Optional] string lpDisplayName);
/// <summary>Changes the configuration parameters of a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// SERVICE_CHANGE_CONFIG access right.
/// </param>
/// <param name="nServiceType">
/// The type of service. Specify SERVICE_NO_CHANGE if you are not changing the existing service type. If you specify either
/// SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the context of the LocalSystem account,
/// you can also specify SERVICE_INTERACTIVE_PROCESS.
/// </param>
/// <param name="nStartType">The service start options. Specify SERVICE_NO_CHANGE if you are not changing the existing start type.</param>
/// <param name="nErrorControl">
/// The severity of the error, and action taken, if this service fails to start. Specify SERVICE_NO_CHANGE if you are not changing
/// the existing error control.
/// </param>
/// <param name="lpBinaryPathName">
/// The fully qualified path to the service binary file. Specify NULL if you are not changing the existing path. If the path contains
/// a space, it must be quoted so that it is correctly interpreted. For example, "d:\\my share\\myservice.exe" should be specified as
/// "\"d:\\my share\\myservice.exe\"".
/// <para>
/// The path can also include arguments for an auto-start service. For example, "d:\\myshare\\myservice.exe arg1 arg2". These
/// arguments are passed to the service entry point (typically the main function).
/// </para>
/// <para>
/// If you specify a path on another computer, the share must be accessible by the computer account of the local computer because
/// this is the security context used in the remote call. However, this requirement allows any potential vulnerabilities in the
/// remote computer to affect the local computer. Therefore, it is best to use a local file.
/// </para>
/// </param>
/// <param name="lpLoadOrderGroup">
/// The name of the load ordering group of which this service is a member. Specify NULL if you are not changing the existing group.
/// Specify an empty string if the service does not belong to a group.
/// <para>
/// The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups.
/// The list of load ordering groups is contained in the ServiceGroupOrder value of the following registry key:
/// </para>
/// <para>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</para>
/// </param>
/// <param name="lpdwTagId">
/// A pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter.
/// Specify NULL if you are not changing the existing tag.
/// <para>
/// You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the
/// GroupOrderList value of the following registry key:
/// </para>
/// <para>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</para>
/// <para>Tags are only evaluated for driver services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.</para>
/// </param>
/// <param name="lpDependencies">
/// A pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must
/// start before this service can be started. (Dependency on a group means that this service can run if at least one member of the
/// group is running after an attempt to start all members of the group.) Specify NULL if you are not changing the existing
/// dependencies. Specify an empty string if the service has no dependencies.
/// <para>
/// You must prefix group names with SC_GROUP_IDENTIFIER so that they can be distinguished from a service name, because services and
/// service groups share the same name space.
/// </para>
/// </param>
/// <param name="lpServiceStartName">
/// The name of the account under which the service should run. Specify NULL if you are not changing the existing account name. If
/// the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be
/// logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName (note that the corresponding
/// C/C++ string is ".\\UserName"). For more information, see Service User Accounts and the warning in the Remarks section.
/// <para>A shared process can run as any user.</para>
/// <para>
/// If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, the name is the driver object name that the system
/// uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.
/// </para>
/// <para>
/// A service can be configured to use a managed account or a virtual account. If the service is configured to use a managed service
/// account, the name is the managed service account name. If the service is configured to use a virtual account, specify the name as
/// NT SERVICE\ServiceName. For more information about managed service accounts and virtual accounts, see the Service Accounts
/// Step-by-Step Guide.
/// </para>
/// <para>
/// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: Managed service accounts and virtual accounts are not
/// supported until Windows 7 and Windows Server 2008 R2.
/// </para>
/// </param>
/// <param name="lpPassword">
/// The password to the account name specified by the lpServiceStartName parameter. Specify NULL if you are not changing the existing
/// password. Specify an empty string if the account has no password or if the service runs in the LocalService, NetworkService, or
/// LocalSystem account. For more information, see Service Record List.
/// <para>
/// If the account name specified by the lpServiceStartName parameter is the name of a managed service account or virtual account
/// name, the lpPassword parameter must be NULL.
/// </para>
/// <para>Passwords are ignored for driver services.</para>
/// </param>
/// <param name="lpDisplayName">
/// The display name to be used by applications to identify the service for its users. Specify NULL if you are not changing the
/// existing display name; otherwise, this string has a maximum length of 256 characters. The name is case-preserved in the service
/// control manager. Display name comparisons are always case-insensitive.
/// <para>This parameter can specify a localized string using the following format:</para>
/// <para>@[path\]dllname,-strID</para>
/// <para>The string with identifier strID is loaded from dllname; the path is optional. For more information, see RegLoadMUIString.</para>
/// <para>Windows Server 2003 and Windows XP: Localized strings are not supported until Windows Vista.</para>
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.To get extended error
/// information, call GetLastError.
/// </returns>
[DllImport(Lib.AdvApi32, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[PInvokeData("winsvc.h", MSDNShortId = "ms681987")]
public static extern bool ChangeServiceConfig(SC_HANDLE hService, ServiceTypes nServiceType, ServiceStartType nStartType, ServiceErrorControlType nErrorControl,
[Optional] string lpBinaryPathName, [Optional] string lpLoadOrderGroup, [Optional] IntPtr lpdwTagId, [In, Optional] string lpDependencies,
[Optional] string lpServiceStartName, [Optional] string lpPassword, [Optional] string lpDisplayName);
/// <summary>Changes the optional configuration parameters of a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// SERVICE_CHANGE_CONFIG access right.
/// </param>
/// <param name="dwInfoLevel">The configuration information to be changed.</param>
/// <param name="lpInfo">
/// A pointer to the new value to be set for the configuration information. The format of this data depends on the value of the
/// dwInfoLevel parameter. If this value is NULL, the information remains unchanged.
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
/// information, call GetLastError.
/// </returns>
[DllImport(Lib.AdvApi32, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[PInvokeData("winsvc.h", MSDNShortId = "ms681988")]
public static extern bool ChangeServiceConfig2(SC_HANDLE hService, ServiceConfigOption dwInfoLevel, IntPtr lpInfo);
/// <summary>Changes the optional configuration parameters of a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// SERVICE_CHANGE_CONFIG access right.
/// </param>
/// <param name="dwInfoLevel">The configuration information to be changed.</param>
/// <param name="lpInfo">
/// The new value to be set for the configuration information. The format of this data depends on the value of the dwInfoLevel
/// parameter. If this value is NULL, the information remains unchanged.
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
/// information, call GetLastError.
/// </returns>
[PInvokeData("winsvc.h", MSDNShortId = "ms681988")]
public static bool ChangeServiceConfig2<T>(SC_HANDLE hService, ServiceConfigOption dwInfoLevel, in T lpInfo) where T : struct
{
if (!CorrespondingTypeAttribute.CanSet(dwInfoLevel, typeof(T))) throw new ArgumentException("Type mismatch", nameof(lpInfo));
using (var ptr = SafeCoTaskMemHandle.CreateFromStructure(lpInfo))
return ChangeServiceConfig2(hService, dwInfoLevel, ptr.DangerousGetHandle());
}
/// <summary>
/// <para>Closes a handle to a service control manager or service object.</para>
/// </summary>
/// <param name="hSCObject">
/// <para>
/// A handle to the service control manager object or the service object to close. Handles to service control manager objects are
/// returned by the OpenSCManager function, and handles to service objects are returned by either the OpenService or CreateService function.
/// </para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error code can be set by the service control manager. Other error codes can be set by registry functions that are
/// called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>CloseServiceHandle</c> function does not destroy the service control manager object referred to by the handle. A service
/// control manager object cannot be destroyed. A service object can be destroyed by calling the DeleteService function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Deleting a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-closeservicehandle BOOL CloseServiceHandle( SC_HANDLE
// hSCObject );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "6cf25994-4939-4aff-af38-5ffc8fc606ae")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseServiceHandle(SC_HANDLE hSCObject);
/// <summary>
/// <para>Sends a control code to a service.</para>
/// <para>To specify additional information when stopping a service, use the ControlServiceEx function.</para>
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function. The access rights required for
/// this handle depend on the dwControl code requested.
/// </param>
/// <param name="dwControl">
/// <para>This parameter can be one of the following control codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTROL_CONTINUE 0x00000003</term>
/// <term>Notifies a paused service that it should resume. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_INTERROGATE 0x00000004</term>
/// <term>
/// Notifies a service that it should report its current status information to the service control manager. The hService handle must
/// have the SERVICE_INTERROGATE access right. Note that this control is not generally useful as the SCM is aware of the current
/// state of the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDADD 0x00000007</term>
/// <term>
/// Notifies a network service that there is a new component for binding. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDDISABLE 0x0000000A</term>
/// <term>
/// Notifies a network service that one of its bindings has been disabled. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDENABLE 0x00000009</term>
/// <term>
/// Notifies a network service that a disabled binding has been enabled. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDREMOVE 0x00000008</term>
/// <term>
/// Notifies a network service that a component for binding has been removed. The hService handle must have the
/// SERVICE_PAUSE_CONTINUE access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PARAMCHANGE 0x00000006</term>
/// <term>
/// Notifies a service that its startup parameters have changed. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PAUSE 0x00000002</term>
/// <term>Notifies a service that it should pause. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_STOP 0x00000001</term>
/// <term>
/// Notifies a service that it should stop. The hService handle must have the SERVICE_STOP access right. After sending the stop
/// request to a service, you should not send other controls to the service.
/// </term>
/// </item>
/// </list>
/// <para>This value can also be a user-defined control code, as described in the following table.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>Range 128 to 255</term>
/// <term>
/// The service defines the action associated with the control code. The hService handle must have the SERVICE_USER_DEFINED_CONTROL
/// access right.
/// </term>
/// </item>
/// </list>
/// </param>
/// <param name="lpServiceStatus">
/// <para>
/// A pointer to a SERVICE_STATUS structure that receives the latest service status information. The information returned reflects
/// the most recent status that the service reported to the service control manager.
/// </para>
/// <para>
/// The service control manager fills in the structure only when <c>ControlService</c> returns one of the following error codes:
/// <c>NO_ERROR</c>, <c>ERROR_INVALID_SERVICE_CONTROL</c>, <c>ERROR_SERVICE_CANNOT_ACCEPT_CTRL</c>, or
/// <c>ERROR_SERVICE_NOT_ACTIVE</c>. Otherwise, the structure is not filled in.
/// </para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the required access right.</term>
/// </item>
/// <item>
/// <term>ERROR_DEPENDENT_SERVICES_RUNNING</term>
/// <term>The service cannot be stopped because other running services are dependent on it.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle was not obtained using CreateService or OpenService, or the handle is no longer valid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>The requested control code is undefined.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_SERVICE_CONTROL</term>
/// <term>The requested control code is not valid, or it is unacceptable to the service.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_CANNOT_ACCEPT_CTRL</term>
/// <term>
/// The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED,
/// SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_NOT_ACTIVE</term>
/// <term>The service has not been started.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_REQUEST_TIMEOUT</term>
/// <term>
/// The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called
/// StartServiceCtrlDispatcher may be blocked in a control handler function.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SHUTDOWN_IN_PROGRESS</term>
/// <term>The system is shutting down.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>ControlService</c> function asks the Service Control Manager (SCM) to send the requested control code to the service. The
/// SCM sends the code if the service has specified that it will accept the code, and is in a state in which a control code can be
/// sent to it.
/// </para>
/// <para>
/// The SCM processes service control notifications in a serial fashion—it will wait for one service to complete processing a service
/// control notification before sending the next one. Because of this, a call to <c>ControlService</c> will block for 30 seconds if
/// any service is busy handling a control code. If the busy service still has not returned from its handler function when the
/// timeout expires, <c>ControlService</c> fails with <c>ERROR_SERVICE_REQUEST_TIMEOUT</c>.
/// </para>
/// <para>
/// To stop and start a service requires a security descriptor that allows you to do so. The default security descriptor allows the
/// LocalSystem account, and members of the Administrators and Power Users groups to stop and start services. To change the security
/// descriptor of a service, see Modifying the DACL for a Service.
/// </para>
/// <para>
/// The QueryServiceStatusEx function returns a SERVICE_STATUS_PROCESS structure whose <c>dwCurrentState</c> and
/// <c>dwControlsAccepted</c> members indicate the current state and controls accepted by a running service. All running services
/// accept the <c>SERVICE_CONTROL_INTERROGATE</c> control code by default. Drivers do not accept control codes other than
/// <c>SERVICE_CONTROL_STOP</c> and <c>SERVICE_CONTROL_INTERROGATE</c>. Each service specifies the other control codes that it
/// accepts when it calls the SetServiceStatus function to report its status. A service should always accept these codes when it is
/// running, no matter what it is doing.
/// </para>
/// <para>The following table shows the action of the SCM in each of the possible service states.</para>
/// <list type="table">
/// <listheader>
/// <term>Service state</term>
/// <term>Stop</term>
/// <term>Other controls</term>
/// </listheader>
/// <item>
/// <term>STOPPED</term>
/// <term>(c)</term>
/// <term>(c)</term>
/// </item>
/// <item>
/// <term>STOP_PENDING</term>
/// <term>(b)</term>
/// <term>(b)</term>
/// </item>
/// <item>
/// <term>START_PENDING</term>
/// <term>(a)</term>
/// <term>(b)</term>
/// </item>
/// <item>
/// <term>RUNNING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>CONTINUE_PENDING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>PAUSE_PENDING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>PAUSED</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// </list>
/// <para>Examples</para>
/// <para>For an example, see Stopping a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-controlservice BOOL ControlService( SC_HANDLE hService,
// DWORD dwControl, LPSERVICE_STATUS lpServiceStatus );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "c112b587-7455-4f15-93e1-ded73de6dbbd")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ControlService(SC_HANDLE hService, ServiceControl dwControl, out SERVICE_STATUS lpServiceStatus);
/// <summary>Sends a control code to a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function. The access rights required for
/// this handle depend on the dwControl code requested.
/// </param>
/// <param name="dwControl">
/// <para>This parameter can be one of the following control codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTROL_CONTINUE 0x00000003</term>
/// <term>Notifies a paused service that it should resume. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_INTERROGATE 0x00000004</term>
/// <term>
/// Notifies a service that it should report its current status information to the service control manager. The hService handle must
/// have the SERVICE_INTERROGATE access right. Note that this control is not generally useful as the SCM is aware of the current
/// state of the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDADD 0x00000007</term>
/// <term>
/// Notifies a network service that there is a new component for binding. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDDISABLE 0x0000000A</term>
/// <term>
/// Notifies a network service that one of its bindings has been disabled. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDENABLE 0x00000009</term>
/// <term>
/// Notifies a network service that a disabled binding has been enabled. The hService handle must have the SERVICE_PAUSE_CONTINUE
/// access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_NETBINDREMOVE 0x00000008</term>
/// <term>
/// Notifies a network service that a component for binding has been removed. The hService handle must have the
/// SERVICE_PAUSE_CONTINUE access right. However, this control code has been deprecated; use Plug and Play functionality instead.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PARAMCHANGE 0x00000006</term>
/// <term>
/// Notifies a service that its startup parameters have changed. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_PAUSE 0x00000002</term>
/// <term>Notifies a service that it should pause. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONTROL_STOP 0x00000001</term>
/// <term>
/// Notifies a service that it should stop. The hService handle must have the SERVICE_STOP access right. After sending the stop
/// request to a service, you should not send other controls to the service.
/// </term>
/// </item>
/// </list>
/// <para>This parameter can also be a user-defined control code, as described in the following table.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>Range 128 to 255</term>
/// <term>
/// The service defines the action associated with the control code. The hService handle must have the SERVICE_USER_DEFINED_CONTROL
/// access right.
/// </term>
/// </item>
/// </list>
/// </param>
/// <param name="dwInfoLevel">
/// The information level for the service control parameters. This parameter must be set to SERVICE_CONTROL_STATUS_REASON_INFO (1).
/// </param>
/// <param name="pControlParams">
/// A pointer to the service control parameters. If dwInfoLevel is SERVICE_CONTROL_STATUS_REASON_INFO, this member is a pointer to a
/// SERVICE_CONTROL_STATUS_REASON_PARAMS structure.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the required access right.</term>
/// </item>
/// <item>
/// <term>ERROR_DEPENDENT_SERVICES_RUNNING</term>
/// <term>The service cannot be stopped because other running services are dependent on it.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle was not obtained using CreateService or OpenService, or the handle is no longer valid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>
/// The requested control code in the dwControl parameter is undefined, or dwControl is SERVICE_CONTROL_STOP but the dwReason or
/// pszComment members of the SERVICE_CONTROL_STATUS_REASON_PARAMS structure are not valid.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_SERVICE_CONTROL</term>
/// <term>The requested control code is not valid, or it is unacceptable to the service.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_CANNOT_ACCEPT_CTRL</term>
/// <term>
/// The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED,
/// SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_NOT_ACTIVE</term>
/// <term>The service has not been started.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_REQUEST_TIMEOUT</term>
/// <term>
/// The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called
/// StartServiceCtrlDispatcher may be blocked in a control handler function.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SHUTDOWN_IN_PROGRESS</term>
/// <term>The system is shutting down.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>ControlServiceEx</c> function asks the Service Control Manager (SCM) to send the requested control code to the service.
/// The SCM sends the code if the service has specified that it will accept the code, and is in a state in which a control code can
/// be sent to it.
/// </para>
/// <para>
/// The SCM processes service control notifications in a serial fashion — it waits for one service to complete processing a service
/// control notification before sending the next one. Because of this, a call to <c>ControlServiceEx</c> blocks for 30 seconds if any
/// service is busy handling a control code. If the busy service still has not returned from its handler function when the timeout
/// expires, <c>ControlServiceEx</c> fails with ERROR_SERVICE_REQUEST_TIMEOUT.
/// </para>
/// <para>
/// To stop and start a service requires a security descriptor that allows you to do so. The default security descriptor allows the
/// LocalSystem account, and members of the Administrators and Power Users groups to stop and start services. To change the security
/// descriptor of a service, see Modifying the DACL for a Service.
/// </para>
/// <para>
/// The QueryServiceStatusEx function returns a SERVICE_STATUS_PROCESS structure whose <c>dwCurrentState</c> and
/// <c>dwControlsAccepted</c> members indicate the current state and controls accepted by a running service. All running services
/// accept the SERVICE_CONTROL_INTERROGATE control code by default. Drivers do not accept control codes other than
/// SERVICE_CONTROL_STOP and SERVICE_CONTROL_INTERROGATE. Each service specifies the other control codes that it accepts when it
/// calls the SetServiceStatus function to report its status. A service should always accept these codes when it is running, no
/// matter what it is doing.
/// </para>
/// <para>The following table shows the action of the SCM in each of the possible service states.</para>
/// <list type="table">
/// <listheader>
/// <term>Service state</term>
/// <term>Stop</term>
/// <term>Other controls</term>
/// </listheader>
/// <item>
/// <term>STOPPED</term>
/// <term>(c)</term>
/// <term>(c)</term>
/// </item>
/// <item>
/// <term>STOP_PENDING</term>
/// <term>(b)</term>
/// <term>(b)</term>
/// </item>
/// <item>
/// <term>START_PENDING</term>
/// <term>(a)</term>
/// <term>(b)</term>
/// </item>
/// <item>
/// <term>RUNNING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>CONTINUE_PENDING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>PAUSE_PENDING</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// <item>
/// <term>PAUSED</term>
/// <term>(a)</term>
/// <term>(a)</term>
/// </item>
/// </list>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-controlserviceexa BOOL ControlServiceExA( SC_HANDLE
// hService, DWORD dwControl, DWORD dwInfoLevel, PVOID pControlParams );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "de249903-7545-4fb6-925a-aa647f862f93")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ControlServiceEx(SC_HANDLE hService, ServiceControl dwControl, ServiceInfoLevels dwInfoLevel, ref SERVICE_CONTROL_STATUS_REASON_PARAMS pControlParams);
/// <summary>
/// <para>Creates a service object and adds it to the specified service control manager database.</para>
/// </summary>
/// <param name="hSCManager">
/// <para>
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function and must have the
/// <c>SC_MANAGER_CREATE_SERVICE</c> access right. For more information, see Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="lpServiceName">
/// <para>
/// The name of the service to install. The maximum string length is 256 characters. The service control manager database preserves
/// the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and backslash () are not
/// valid service name characters.
/// </para>
/// </param>
/// <param name="lpDisplayName">
/// <para>
/// The display name to be used by user interface programs to identify the service. This string has a maximum length of 256
/// characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.
/// </para>
/// </param>
/// <param name="dwDesiredAccess">
/// <para>
/// The access to the service. Before granting the requested access, the system checks the access token of the calling process. For a
/// list of values, see Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="dwServiceType">
/// <para>The service type. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ADAPTER 0x00000004</term>
/// <term>Reserved.</term>
/// </item>
/// <item>
/// <term>SERVICE_FILE_SYSTEM_DRIVER 0x00000002</term>
/// <term>File system driver service.</term>
/// </item>
/// <item>
/// <term>SERVICE_KERNEL_DRIVER 0x00000001</term>
/// <term>Driver service.</term>
/// </item>
/// <item>
/// <term>SERVICE_RECOGNIZER_DRIVER 0x00000008</term>
/// <term>Reserved.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_OWN_PROCESS 0x00000010</term>
/// <term>Service that runs in its own process.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_SHARE_PROCESS 0x00000020</term>
/// <term>Service that shares a process with one or more other services. For more information, see Service Programs.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_OWN_PROCESS 0x00000050</term>
/// <term>The service runs in its own process under the logged-on user account.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_SHARE_PROCESS 0x00000060</term>
/// <term>The service shares a process with one or more other services that run under the logged-on user account.</term>
/// </item>
/// </list>
/// <para>
/// If you specify either <c>SERVICE_WIN32_OWN_PROCESS</c> or <c>SERVICE_WIN32_SHARE_PROCESS</c>, and the service is running in the
/// context of the LocalSystem account, you can also specify the following value.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_INTERACTIVE_PROCESS 0x00000100</term>
/// <term>The service can interact with the desktop. For more information, see Interactive Services.</term>
/// </item>
/// </list>
/// </param>
/// <param name="dwStartType">
/// <para>The service start options. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_AUTO_START 0x00000002</term>
/// <term>
/// A service started automatically by the service control manager during system startup. For more information, see Automatically
/// Starting Services.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_BOOT_START 0x00000000</term>
/// <term>A device driver started by the system loader. This value is valid only for driver services.</term>
/// </item>
/// <item>
/// <term>SERVICE_DEMAND_START 0x00000003</term>
/// <term>
/// A service started by the service control manager when a process calls the StartService function. For more information, see
/// Starting Services on Demand.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_DISABLED 0x00000004</term>
/// <term>A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.</term>
/// </item>
/// <item>
/// <term>SERVICE_SYSTEM_START 0x00000001</term>
/// <term>A device driver started by the IoInitSystem function. This value is valid only for driver services.</term>
/// </item>
/// </list>
/// </param>
/// <param name="dwErrorControl">
/// <para>
/// The severity of the error, and action taken, if this service fails to start. This parameter can be one of the following values.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ERROR_CRITICAL 0x00000003</term>
/// <term>
/// The startup program logs the error in the event log, if possible. If the last-known-good configuration is being started, the
/// startup operation fails. Otherwise, the system is restarted with the last-known good configuration.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_IGNORE 0x00000000</term>
/// <term>The startup program ignores the error and continues the startup operation.</term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_NORMAL 0x00000001</term>
/// <term>The startup program logs the error in the event log but continues the startup operation.</term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_SEVERE 0x00000002</term>
/// <term>
/// The startup program logs the error in the event log. If the last-known-good configuration is being started, the startup operation
/// continues. Otherwise, the system is restarted with the last-known-good configuration.
/// </term>
/// </item>
/// </list>
/// </param>
/// <param name="lpBinaryPathName">
/// <para>
/// The fully qualified path to the service binary file. If the path contains a space, it must be quoted so that it is correctly
/// interpreted. For example, "d:\my share\myservice.exe" should be specified as ""d:\my share\myservice.exe"".
/// </para>
/// <para>
/// The path can also include arguments for an auto-start service. For example, "d:\myshare\myservice.exe arg1 arg2". These arguments
/// are passed to the service entry point (typically the <c>main</c> function).
/// </para>
/// <para>
/// If you specify a path on another computer, the share must be accessible by the computer account of the local computer because
/// this is the security context used in the remote call. However, this requirement allows any potential vulnerabilities in the
/// remote computer to affect the local computer. Therefore, it is best to use a local file.
/// </para>
/// </param>
/// <param name="lpLoadOrderGroup">
/// <para>
/// The names of the load ordering group of which this service is a member. Specify NULL or an empty string if the service does not
/// belong to a group.
/// </para>
/// <para>
/// The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups.
/// The list of load ordering groups is contained in the following registry value: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</c>&lt;b&gt;ServiceGroupOrder
/// </para>
/// </param>
/// <param name="lpdwTagId">
/// <para>
/// A pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter.
/// Specify NULL if you are not changing the existing tag.
/// </para>
/// <para>
/// You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the following
/// registry value: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</c>&lt;b&gt;GroupOrderList
/// </para>
/// <para>Tags are only evaluated for driver services that have <c>SERVICE_BOOT_START</c> or <c>SERVICE_SYSTEM_START</c> start types.</para>
/// </param>
/// <param name="lpDependencies">
/// <para>
/// A pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must
/// start before this service. Specify NULL or an empty string if the service has no dependencies. Dependency on a group means that
/// this service can run if at least one member of the group is running after an attempt to start all members of the group.
/// </para>
/// <para>
/// You must prefix group names with <c>SC_GROUP_IDENTIFIER</c> so that they can be distinguished from a service name, because
/// services and service groups share the same name space.
/// </para>
/// </param>
/// <param name="lpServiceStartName">
/// <para>
/// The name of the account under which the service should run. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name
/// in the form DomainName&lt;i&gt;UserName. The service process will be logged on as this user. If the account belongs to the
/// built-in domain, you can specify .&lt;i&gt;UserName.
/// </para>
/// <para>
/// If this parameter is NULL, <c>CreateService</c> uses the LocalSystem account. If the service type specifies
/// <c>SERVICE_INTERACTIVE_PROCESS</c>, the service must run in the LocalSystem account.
/// </para>
/// <para>
/// If this parameter is NT AUTHORITY\LocalService, <c>CreateService</c> uses the LocalService account. If the parameter is NT
/// AUTHORITY\NetworkService, <c>CreateService</c> uses the NetworkService account.
/// </para>
/// <para>A shared process can run as any user.</para>
/// <para>
/// If the service type is <c>SERVICE_KERNEL_DRIVER</c> or <c>SERVICE_FILE_SYSTEM_DRIVER</c>, the name is the driver object name that
/// the system uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.
/// </para>
/// <para>
/// A service can be configured to use a managed account or a virtual account. If the service is configured to use a managed service
/// account, the name is the managed service account name. If the service is configured to use a virtual account, specify the name as
/// NT SERVICE&lt;i&gt;ServiceName. For more information about managed service accounts and virtual accounts, see the Service
/// Accounts Step-by-Step Guide.
/// </para>
/// <para>
/// <c>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:</c> Managed service accounts and virtual accounts are
/// not supported until Windows 7 and Windows Server 2008 R2.
/// </para>
/// </param>
/// <param name="lpPassword">
/// <para>
/// The password to the account name specified by the lpServiceStartName parameter. Specify an empty string if the account has no
/// password or if the service runs in the LocalService, NetworkService, or LocalSystem account. For more information, see Service
/// Record List.
/// </para>
/// <para>
/// If the account name specified by the lpServiceStartName parameter is the name of a managed service account or virtual account
/// name, the lpPassword parameter must be NULL.
/// </para>
/// <para>Passwords are ignored for driver services.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a handle to the service.</para>
/// <para>If the function fails, the return value is NULL. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle to the SCM database does not have the SC_MANAGER_CREATE_SERVICE access right.</term>
/// </item>
/// <item>
/// <term>ERROR_CIRCULAR_DEPENDENCY</term>
/// <term>A circular service dependency was specified.</term>
/// </item>
/// <item>
/// <term>ERROR_DUPLICATE_SERVICE_NAME</term>
/// <term>
/// The display name already exists in the service control manager database either as a service name or as another display name.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle to the specified service control manager database is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_NAME</term>
/// <term>The specified service name is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>A parameter that was specified is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_SERVICE_ACCOUNT</term>
/// <term>The user account name specified in the lpServiceStartName parameter does not exist.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_EXISTS</term>
/// <term>The specified service already exists in this database.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_MARKED_FOR_DELETE</term>
/// <term>The specified service already exists in this database and has been marked for deletion.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>CreateService</c> function creates a service object and installs it in the service control manager database by creating a
/// key with the same name as the service under the following registry key: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services</c>
/// </para>
/// <para>
/// Information specified by <c>CreateService</c>, ChangeServiceConfig, and ChangeServiceConfig2 is saved as values under this key.
/// The following are examples of values stored for a service.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>DependOnGroup</term>
/// <term>Load-ordering groups on which this service depends, as specified by lpDependencies.</term>
/// </item>
/// <item>
/// <term>DependOnService</term>
/// <term>Services on which this service depends, as specified by lpDependencies.</term>
/// </item>
/// <item>
/// <term>Description</term>
/// <term>Description specified by ChangeServiceConfig2.</term>
/// </item>
/// <item>
/// <term>DisplayName</term>
/// <term>Display name specified by lpDisplayName.</term>
/// </item>
/// <item>
/// <term>ErrorControl</term>
/// <term>Error control specified by dwErrorControl.</term>
/// </item>
/// <item>
/// <term>FailureActions</term>
/// <term>Failure actions specified by ChangeServiceConfig2.</term>
/// </item>
/// <item>
/// <term>Group</term>
/// <term>
/// Load ordering group specified by lpLoadOrderGroup. Note that setting this value can override the setting of the DependOnService value.
/// </term>
/// </item>
/// <item>
/// <term>ImagePath</term>
/// <term>Name of binary file, as specified by lpBinaryPathName.</term>
/// </item>
/// <item>
/// <term>ObjectName</term>
/// <term>Account name specified by lpServiceStartName.</term>
/// </item>
/// <item>
/// <term>Start</term>
/// <term>When to start service, as specified by dwStartType.</term>
/// </item>
/// <item>
/// <term>Tag</term>
/// <term>Tag identifier specified by lpdwTagId.</term>
/// </item>
/// <item>
/// <term>Type</term>
/// <term>Service type specified by dwServiceType.</term>
/// </item>
/// </list>
/// <para>Setup programs and the service itself can create additional subkeys for service-specific information.</para>
/// <para>
/// The returned handle is only valid for the process that called <c>CreateService</c>. It can be closed by calling the
/// CloseServiceHandle function.
/// </para>
/// <para>
/// If you are creating services that share a process, avoid calling functions with process-wide effects, such as ExitProcess. In
/// addition, do not unload your service DLL.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Installing a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-createservicea SC_HANDLE CreateServiceA( SC_HANDLE
// hSCManager, LPCSTR lpServiceName, LPCSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD
// dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR
// lpServiceStartName, LPCSTR lpPassword );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "47288924-3294-4a50-b27d-7df80d5c957c")]
public static extern SafeSC_HANDLE CreateService(SC_HANDLE hSCManager, string lpServiceName, [Optional] string lpDisplayName, uint dwDesiredAccess, ServiceTypes dwServiceType,
ServiceStartType dwStartType, ServiceErrorControlType dwErrorControl, string lpBinaryPathName, [Optional] string lpLoadOrderGroup, out uint lpdwTagId,
[In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[] lpDependencies,
[Optional] string lpServiceStartName, [Optional] string lpPassword);
/// <summary>
/// <para>Creates a service object and adds it to the specified service control manager database.</para>
/// </summary>
/// <param name="hSCManager">
/// <para>
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function and must have the
/// <c>SC_MANAGER_CREATE_SERVICE</c> access right. For more information, see Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="lpServiceName">
/// <para>
/// The name of the service to install. The maximum string length is 256 characters. The service control manager database preserves
/// the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and backslash () are not
/// valid service name characters.
/// </para>
/// </param>
/// <param name="lpDisplayName">
/// <para>
/// The display name to be used by user interface programs to identify the service. This string has a maximum length of 256
/// characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.
/// </para>
/// </param>
/// <param name="dwDesiredAccess">
/// <para>
/// The access to the service. Before granting the requested access, the system checks the access token of the calling process. For a
/// list of values, see Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="dwServiceType">
/// <para>The service type. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ADAPTER 0x00000004</term>
/// <term>Reserved.</term>
/// </item>
/// <item>
/// <term>SERVICE_FILE_SYSTEM_DRIVER 0x00000002</term>
/// <term>File system driver service.</term>
/// </item>
/// <item>
/// <term>SERVICE_KERNEL_DRIVER 0x00000001</term>
/// <term>Driver service.</term>
/// </item>
/// <item>
/// <term>SERVICE_RECOGNIZER_DRIVER 0x00000008</term>
/// <term>Reserved.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_OWN_PROCESS 0x00000010</term>
/// <term>Service that runs in its own process.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_SHARE_PROCESS 0x00000020</term>
/// <term>Service that shares a process with one or more other services. For more information, see Service Programs.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_OWN_PROCESS 0x00000050</term>
/// <term>The service runs in its own process under the logged-on user account.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_SHARE_PROCESS 0x00000060</term>
/// <term>The service shares a process with one or more other services that run under the logged-on user account.</term>
/// </item>
/// </list>
/// <para>
/// If you specify either <c>SERVICE_WIN32_OWN_PROCESS</c> or <c>SERVICE_WIN32_SHARE_PROCESS</c>, and the service is running in the
/// context of the LocalSystem account, you can also specify the following value.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_INTERACTIVE_PROCESS 0x00000100</term>
/// <term>The service can interact with the desktop. For more information, see Interactive Services.</term>
/// </item>
/// </list>
/// </param>
/// <param name="dwStartType">
/// <para>The service start options. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_AUTO_START 0x00000002</term>
/// <term>
/// A service started automatically by the service control manager during system startup. For more information, see Automatically
/// Starting Services.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_BOOT_START 0x00000000</term>
/// <term>A device driver started by the system loader. This value is valid only for driver services.</term>
/// </item>
/// <item>
/// <term>SERVICE_DEMAND_START 0x00000003</term>
/// <term>
/// A service started by the service control manager when a process calls the StartService function. For more information, see
/// Starting Services on Demand.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_DISABLED 0x00000004</term>
/// <term>A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.</term>
/// </item>
/// <item>
/// <term>SERVICE_SYSTEM_START 0x00000001</term>
/// <term>A device driver started by the IoInitSystem function. This value is valid only for driver services.</term>
/// </item>
/// </list>
/// </param>
/// <param name="dwErrorControl">
/// <para>
/// The severity of the error, and action taken, if this service fails to start. This parameter can be one of the following values.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ERROR_CRITICAL 0x00000003</term>
/// <term>
/// The startup program logs the error in the event log, if possible. If the last-known-good configuration is being started, the
/// startup operation fails. Otherwise, the system is restarted with the last-known good configuration.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_IGNORE 0x00000000</term>
/// <term>The startup program ignores the error and continues the startup operation.</term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_NORMAL 0x00000001</term>
/// <term>The startup program logs the error in the event log but continues the startup operation.</term>
/// </item>
/// <item>
/// <term>SERVICE_ERROR_SEVERE 0x00000002</term>
/// <term>
/// The startup program logs the error in the event log. If the last-known-good configuration is being started, the startup operation
/// continues. Otherwise, the system is restarted with the last-known-good configuration.
/// </term>
/// </item>
/// </list>
/// </param>
/// <param name="lpBinaryPathName">
/// <para>
/// The fully qualified path to the service binary file. If the path contains a space, it must be quoted so that it is correctly
/// interpreted. For example, "d:\my share\myservice.exe" should be specified as ""d:\my share\myservice.exe"".
/// </para>
/// <para>
/// The path can also include arguments for an auto-start service. For example, "d:\myshare\myservice.exe arg1 arg2". These arguments
/// are passed to the service entry point (typically the <c>main</c> function).
/// </para>
/// <para>
/// If you specify a path on another computer, the share must be accessible by the computer account of the local computer because
/// this is the security context used in the remote call. However, this requirement allows any potential vulnerabilities in the
/// remote computer to affect the local computer. Therefore, it is best to use a local file.
/// </para>
/// </param>
/// <param name="lpLoadOrderGroup">
/// <para>
/// The names of the load ordering group of which this service is a member. Specify NULL or an empty string if the service does not
/// belong to a group.
/// </para>
/// <para>
/// The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups.
/// The list of load ordering groups is contained in the following registry value: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</c>&lt;b&gt;ServiceGroupOrder
/// </para>
/// </param>
/// <param name="lpdwTagId">
/// <para>
/// A pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter.
/// Specify NULL if you are not changing the existing tag.
/// </para>
/// <para>
/// You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the following
/// registry value: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control</c>&lt;b&gt;GroupOrderList
/// </para>
/// <para>Tags are only evaluated for driver services that have <c>SERVICE_BOOT_START</c> or <c>SERVICE_SYSTEM_START</c> start types.</para>
/// </param>
/// <param name="lpDependencies">
/// <para>
/// A pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must
/// start before this service. Specify NULL or an empty string if the service has no dependencies. Dependency on a group means that
/// this service can run if at least one member of the group is running after an attempt to start all members of the group.
/// </para>
/// <para>
/// You must prefix group names with <c>SC_GROUP_IDENTIFIER</c> so that they can be distinguished from a service name, because
/// services and service groups share the same name space.
/// </para>
/// </param>
/// <param name="lpServiceStartName">
/// <para>
/// The name of the account under which the service should run. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name
/// in the form DomainName&lt;i&gt;UserName. The service process will be logged on as this user. If the account belongs to the
/// built-in domain, you can specify .&lt;i&gt;UserName.
/// </para>
/// <para>
/// If this parameter is NULL, <c>CreateService</c> uses the LocalSystem account. If the service type specifies
/// <c>SERVICE_INTERACTIVE_PROCESS</c>, the service must run in the LocalSystem account.
/// </para>
/// <para>
/// If this parameter is NT AUTHORITY\LocalService, <c>CreateService</c> uses the LocalService account. If the parameter is NT
/// AUTHORITY\NetworkService, <c>CreateService</c> uses the NetworkService account.
/// </para>
/// <para>A shared process can run as any user.</para>
/// <para>
/// If the service type is <c>SERVICE_KERNEL_DRIVER</c> or <c>SERVICE_FILE_SYSTEM_DRIVER</c>, the name is the driver object name that
/// the system uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.
/// </para>
/// <para>
/// A service can be configured to use a managed account or a virtual account. If the service is configured to use a managed service
/// account, the name is the managed service account name. If the service is configured to use a virtual account, specify the name as
/// NT SERVICE&lt;i&gt;ServiceName. For more information about managed service accounts and virtual accounts, see the Service
/// Accounts Step-by-Step Guide.
/// </para>
/// <para>
/// <c>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:</c> Managed service accounts and virtual accounts are
/// not supported until Windows 7 and Windows Server 2008 R2.
/// </para>
/// </param>
/// <param name="lpPassword">
/// <para>
/// The password to the account name specified by the lpServiceStartName parameter. Specify an empty string if the account has no
/// password or if the service runs in the LocalService, NetworkService, or LocalSystem account. For more information, see Service
/// Record List.
/// </para>
/// <para>
/// If the account name specified by the lpServiceStartName parameter is the name of a managed service account or virtual account
/// name, the lpPassword parameter must be NULL.
/// </para>
/// <para>Passwords are ignored for driver services.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a handle to the service.</para>
/// <para>If the function fails, the return value is NULL. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle to the SCM database does not have the SC_MANAGER_CREATE_SERVICE access right.</term>
/// </item>
/// <item>
/// <term>ERROR_CIRCULAR_DEPENDENCY</term>
/// <term>A circular service dependency was specified.</term>
/// </item>
/// <item>
/// <term>ERROR_DUPLICATE_SERVICE_NAME</term>
/// <term>
/// The display name already exists in the service control manager database either as a service name or as another display name.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle to the specified service control manager database is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_NAME</term>
/// <term>The specified service name is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>A parameter that was specified is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_SERVICE_ACCOUNT</term>
/// <term>The user account name specified in the lpServiceStartName parameter does not exist.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_EXISTS</term>
/// <term>The specified service already exists in this database.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_MARKED_FOR_DELETE</term>
/// <term>The specified service already exists in this database and has been marked for deletion.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>CreateService</c> function creates a service object and installs it in the service control manager database by creating a
/// key with the same name as the service under the following registry key: <c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services</c>
/// </para>
/// <para>
/// Information specified by <c>CreateService</c>, ChangeServiceConfig, and ChangeServiceConfig2 is saved as values under this key.
/// The following are examples of values stored for a service.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>DependOnGroup</term>
/// <term>Load-ordering groups on which this service depends, as specified by lpDependencies.</term>
/// </item>
/// <item>
/// <term>DependOnService</term>
/// <term>Services on which this service depends, as specified by lpDependencies.</term>
/// </item>
/// <item>
/// <term>Description</term>
/// <term>Description specified by ChangeServiceConfig2.</term>
/// </item>
/// <item>
/// <term>DisplayName</term>
/// <term>Display name specified by lpDisplayName.</term>
/// </item>
/// <item>
/// <term>ErrorControl</term>
/// <term>Error control specified by dwErrorControl.</term>
/// </item>
/// <item>
/// <term>FailureActions</term>
/// <term>Failure actions specified by ChangeServiceConfig2.</term>
/// </item>
/// <item>
/// <term>Group</term>
/// <term>
/// Load ordering group specified by lpLoadOrderGroup. Note that setting this value can override the setting of the DependOnService value.
/// </term>
/// </item>
/// <item>
/// <term>ImagePath</term>
/// <term>Name of binary file, as specified by lpBinaryPathName.</term>
/// </item>
/// <item>
/// <term>ObjectName</term>
/// <term>Account name specified by lpServiceStartName.</term>
/// </item>
/// <item>
/// <term>Start</term>
/// <term>When to start service, as specified by dwStartType.</term>
/// </item>
/// <item>
/// <term>Tag</term>
/// <term>Tag identifier specified by lpdwTagId.</term>
/// </item>
/// <item>
/// <term>Type</term>
/// <term>Service type specified by dwServiceType.</term>
/// </item>
/// </list>
/// <para>Setup programs and the service itself can create additional subkeys for service-specific information.</para>
/// <para>
/// The returned handle is only valid for the process that called <c>CreateService</c>. It can be closed by calling the
/// CloseServiceHandle function.
/// </para>
/// <para>
/// If you are creating services that share a process, avoid calling functions with process-wide effects, such as ExitProcess. In
/// addition, do not unload your service DLL.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Installing a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-createservicea SC_HANDLE CreateServiceA( SC_HANDLE
// hSCManager, LPCSTR lpServiceName, LPCSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD
// dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR
// lpServiceStartName, LPCSTR lpPassword );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "47288924-3294-4a50-b27d-7df80d5c957c")]
public static extern SafeSC_HANDLE CreateService(SC_HANDLE hSCManager, string lpServiceName, [Optional] string lpDisplayName, uint dwDesiredAccess, ServiceTypes dwServiceType,
ServiceStartType dwStartType, ServiceErrorControlType dwErrorControl, string lpBinaryPathName, [Optional] string lpLoadOrderGroup, [Optional] IntPtr lpdwTagId,
[In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[] lpDependencies,
[Optional] string lpServiceStartName, [Optional] string lpPassword);
/// <summary>Marks the specified service for deletion from the service control manager database.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the DELETE access
/// right. For more information, see Service Security and Access Rights.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes may be set by the service control manager. Others may be set by the registry functions that are called
/// by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the DELETE access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_MARKED_FOR_DELETE</term>
/// <term>The specified service has already been marked for deletion.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>DeleteService</c> function marks a service for deletion from the service control manager database. The database entry is
/// not removed until all open handles to the service have been closed by calls to the CloseServiceHandle function, and the service
/// is not running. A running service is stopped by a call to the ControlService function with the SERVICE_CONTROL_STOP control code.
/// If the service cannot be stopped, the database entry is removed when the system is restarted.
/// </para>
/// <para>The service control manager deletes the service by deleting the service key and its subkeys from the registry.</para>
/// <para>Examples</para>
/// <para>For an example, see Deleting a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-deleteservice BOOL DeleteService( SC_HANDLE hService );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "5b0fc714-60e0-4ae3-8fa8-ace36dab2fb0")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteService(SC_HANDLE hService);
/// <summary>
/// Retrieves the name and status of each service that depends on the specified service; that is, the specified service must be
/// running before the dependent services can run.
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the
/// <c>SERVICE_ENUMERATE_DEPENDENTS</c> access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <param name="lpServices">
/// <para>
/// A pointer to an array of ENUM_SERVICE_STATUS structures that receives the name and service status information for each dependent
/// service in the database. The buffer must be large enough to hold the structures, plus the strings to which their members point.
/// </para>
/// <para>
/// The order of the services in this array is the reverse of the start order of the services. In other words, the first service in
/// the array is the one that would be started last, and the last service in the array is the one that would be started first.
/// </para>
/// <para>
/// The maximum size of this array is 64,000 bytes. To determine the required size, specify <c>NULL</c> for this parameter and 0 for
/// the cbBufSize parameter. The function will fail and GetLastError will return <c>ERROR_MORE_DATA</c>. The pcbBytesNeeded parameter
/// will receive the required size.
/// </para>
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpServices parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to store the array of service entries. The variable only
/// receives this value if the buffer pointed to by lpServices is too small, indicated by function failure and the
/// <c>ERROR_MORE_DATA</c> error; otherwise, the contents of pcbBytesNeeded are undefined.
/// </param>
/// <param name="lpServicesReturned">A pointer to a variable that receives the number of service entries returned.</param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SERVICE_ENUMERATE_DEPENDENTS access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>A parameter that was specified is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_MORE_DATA</term>
/// <term>
/// The buffer pointed to by lpServices is not large enough. The function sets the variable pointed to by lpServicesReturned to the
/// actual number of service entries stored into the buffer. The function sets the variable pointed to by pcbBytesNeeded to the
/// number of bytes required to store all of the service entries.
/// </term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The returned services entries are ordered in the reverse order of the start order, with group order taken into account. If you
/// need to stop the dependent services, you can use the order of entries written to the lpServices buffer to stop the dependent
/// services in the proper order.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Stopping a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumdependentservicesa BOOL EnumDependentServicesA(
// SC_HANDLE hService, DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD
// lpServicesReturned );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "905d4453-96d4-4055-8a17-36714c547cdd")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDependentServices(SC_HANDLE hService, SERVICE_STATE dwServiceState, IntPtr lpServices, uint cbBufSize, out uint pcbBytesNeeded, out uint lpServicesReturned);
/// <summary>
/// Retrieves the name and status of each service that depends on the specified service; that is, the specified service must be
/// running before the dependent services can run.
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the
/// <c>SERVICE_ENUMERATE_DEPENDENTS</c> access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <returns>
/// <para>
/// An array of ENUM_SERVICE_STATUS structures that receives the name and service status information for each dependent service in
/// the database.
/// </para>
/// <para>
/// The order of the services in this array is the reverse of the start order of the services. In other words, the first service in
/// the array is the one that would be started last, and the last service in the array is the one that would be started first.
/// </para>
/// </returns>
[PInvokeData("winsvc.h", MSDNShortId = "905d4453-96d4-4055-8a17-36714c547cdd")]
public static IEnumerable<ENUM_SERVICE_STATUS> EnumDependentServices(SC_HANDLE hService, SERVICE_STATE dwServiceState = SERVICE_STATE.SERVICE_STATE_ALL)
{
EnumDependentServices(hService, dwServiceState, IntPtr.Zero, 0, out var sz, out var cnt);
if (sz == 0) Win32Error.ThrowLastError();
var mem = new SafeHGlobalHandle((int)sz);
if (!EnumDependentServices(hService, dwServiceState, (IntPtr)mem, (uint)mem.Size, out sz, out cnt))
Win32Error.ThrowLastError();
return mem.ToArray<ENUM_SERVICE_STATUS>((int)cnt);
}
/// <summary>
/// <para>Enumerates services in the specified service control manager database. The name and status of each service are provided.</para>
/// <para>
/// This function has been superseded by the EnumServicesStatusEx function. It returns the same information <c>EnumServicesStatus</c>
/// returns, plus the process identifier and additional information for the service. In addition, <c>EnumServicesStatusEx</c> enables
/// you to enumerate services that belong to a specified group.
/// </para>
/// </summary>
/// <param name="hSCManager">
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function, and must have the
/// SC_MANAGER_ENUMERATE_SERVICE access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwServiceType">The type of services to be enumerated. This parameter can be one or more of the following values.</param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <param name="lpServices">
/// <para>
/// A pointer to a buffer that contains an array of ENUM_SERVICE_STATUS structures that receive the name and service status
/// information for each service in the database. The buffer must be large enough to hold the structures, plus the strings to which
/// their members point.
/// </para>
/// <para>
/// The maximum size of this array is 256K bytes. To determine the required size, specify NULL for this parameter and 0 for the
/// cbBufSize parameter. The function will fail and GetLastError will return ERROR_INSUFFICIENT_BUFFER. The pcbBytesNeeded parameter
/// will receive the required size.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> The maximum size of this array is 64K bytes. This limit was increased as of Windows
/// Server 2003 with SP1 and Windows XP with SP2.
/// </para>
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpServices parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to return the remaining service entries, if the buffer is too small.
/// </param>
/// <param name="lpServicesReturned">A pointer to a variable that receives the number of service entries returned.</param>
/// <param name="lpResumeHandle">
/// A pointer to a variable that, on input, specifies the starting point of enumeration. You must set this value to zero the first
/// time this function is called. On output, this value is zero if the function succeeds. However, if the function returns zero and
/// the GetLastError function returns ERROR_MORE_DATA, this value is used to indicate the next service entry to be read when the
/// function is called to retrieve the additional data.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SC_MANAGER_ENUMERATE_SERVICE access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>A parameter that was specified is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_MORE_DATA</term>
/// <term>
/// There are more service entries than would fit into the lpServices buffer. The actual number of service entries written to
/// lpServices is returned in the lpServicesReturned parameter. The number of bytes required to get the remaining entries is returned
/// in the pcbBytesNeeded parameter. The remaining services can be enumerated by additional calls to EnumServicesStatus with the
/// lpResumeHandle parameter indicating the next service to read.
/// </term>
/// </item>
/// </list>
/// </returns>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusa BOOL EnumServicesStatusA( SC_HANDLE
// hSCManager, DWORD dwServiceType, DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
// LPDWORD lpServicesReturned, LPDWORD lpResumeHandle );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "3a82ac0e-f3e8-4a5a-9b13-84e952712229")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumServicesStatus(SC_HANDLE hSCManager, ServiceTypes dwServiceType, SERVICE_STATE dwServiceState, IntPtr lpServices, uint cbBufSize, out uint pcbBytesNeeded, out uint lpServicesReturned, ref uint lpResumeHandle);
/// <summary>
/// <para>Enumerates services in the specified service control manager database. The name and status of each service are provided.</para>
/// <para>
/// This function has been superseded by the EnumServicesStatusEx function. It returns the same information <c>EnumServicesStatus</c>
/// returns, plus the process identifier and additional information for the service. In addition, <c>EnumServicesStatusEx</c> enables
/// you to enumerate services that belong to a specified group.
/// </para>
/// </summary>
/// <param name="hSCManager">
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function, and must have the
/// SC_MANAGER_ENUMERATE_SERVICE access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwServiceType">The type of services to be enumerated. This parameter can be one or more of the following values.</param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <returns>A list of ENUM_SERVICE_STATUS structures with the name and service status information for each service in the database.</returns>
public static IEnumerable<ENUM_SERVICE_STATUS> EnumServicesStatus(SC_HANDLE hSCManager, ServiceTypes dwServiceType = ServiceTypes.SERVICE_TYPE_ALL, SERVICE_STATE dwServiceState = SERVICE_STATE.SERVICE_STATE_ALL)
{
var hRes = 0U;
Win32Error lastErr;
var res = EnumServicesStatus(hSCManager, dwServiceType, dwServiceState, default, 0, out var sz, out _, ref hRes);
if (!res && (lastErr = Win32Error.GetLastError()) != Win32Error.ERROR_MORE_DATA)
lastErr.ThrowIfFailed();
using (var mem = new SafeHGlobalHandle((int)sz))
{
do
{
res = EnumServicesStatus(hSCManager, dwServiceType, dwServiceState, (IntPtr)mem, sz, out sz, out var cnt, ref hRes);
if (!res && (lastErr = Win32Error.GetLastError()) != Win32Error.ERROR_MORE_DATA)
lastErr.ThrowIfFailed();
foreach (var i in mem.ToArray<ENUM_SERVICE_STATUS>((int)cnt))
yield return i;
} while (!res);
}
}
/// <summary>
/// Enumerates services in the specified service control manager database. The name and status of each service are provided, along
/// with additional data based on the specified information level.
/// </summary>
/// <param name="hSCManager">
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function, and must have the
/// <c>SC_MANAGER_ENUMERATE_SERVICE</c> access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="InfoLevel">
/// <para>
/// The service attributes that are to be returned. Use <c>SC_ENUM_PROCESS_INFO</c> to retrieve the name and service status
/// information for each service in the database. The lpServices parameter is a pointer to a buffer that receives an array of
/// ENUM_SERVICE_STATUS_PROCESS structures. The buffer must be large enough to hold the structures as well as the strings to which
/// their members point.
/// </para>
/// <para>Currently, no other information levels are defined.</para>
/// </param>
/// <param name="dwServiceType">The type of services to be enumerated. This parameter can be one or more of the following values.</param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <param name="lpServices">
/// <para>
/// A pointer to the buffer that receives the status information. The format of this data depends on the value of the InfoLevel parameter.
/// </para>
/// <para>
/// The maximum size of this array is 256K bytes. To determine the required size, specify <c>NULL</c> for this parameter and 0 for
/// the cbBufSize parameter. The function will fail and GetLastError will return <c>ERROR_MORE_DATA</c>. The pcbBytesNeeded parameter
/// will receive the required size.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> The maximum size of this array is 64K bytes. This limit was increased as of Windows
/// Server 2003 with SP1 and Windows XP with SP2.
/// </para>
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpServices parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to return the remaining service entries, if the buffer is too small.
/// </param>
/// <param name="lpServicesReturned">A pointer to a variable that receives the number of service entries returned.</param>
/// <param name="lpResumeHandle">
/// A pointer to a variable that, on input, specifies the starting point of enumeration. You must set this value to zero the first
/// time the <c>EnumServicesStatusEx</c> function is called. On output, this value is zero if the function succeeds. However, if the
/// function returns zero and the GetLastError function returns <c>ERROR_MORE_DATA</c>, this value indicates the next service entry
/// to be read when the <c>EnumServicesStatusEx</c> function is called to retrieve the additional data.
/// </param>
/// <param name="pszGroupName">
/// The load-order group name. If this parameter is a string, the only services enumerated are those that belong to the group that
/// has the name specified by the string. If this parameter is an empty string, only services that do not belong to any group are
/// enumerated. If this parameter is <c>NULL</c>, group membership is ignored and all services are enumerated.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>
/// If the function fails, the return value is zero. To get extended error information, call GetLastError. The following errors may
/// be returned.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SC_MANAGER_ENUMERATE_SERVICE access right.</term>
/// </item>
/// <item>
/// <term>ERROR_MORE_DATA</term>
/// <term>
/// The buffer is too small. Not all data in the active database could be returned. The pcbBytesNeeded parameter contains the number
/// of bytes required to receive the remaining entries.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>An illegal parameter value was used.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_LEVEL</term>
/// <term>The InfoLevel parameter contains an unsupported value.</term>
/// </item>
/// <item>
/// <term>ERROR_SHUTDOWN_IN_PROGRESS</term>
/// <term>The system is shutting down; this function cannot be called.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// If the caller does not have the <c>SERVICE_QUERY_STATUS</c> access right to a service, the service is silently omitted from the
/// list of services returned to the client.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexa BOOL EnumServicesStatusExA( SC_HANDLE
// hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD
// pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "7d7940c3-b562-455f-9a21-6d5fb5953030")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumServicesStatusEx(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, ServiceTypes dwServiceType, SERVICE_STATE dwServiceState, IntPtr lpServices, uint cbBufSize, out uint pcbBytesNeeded,
out uint lpServicesReturned, ref uint lpResumeHandle, string pszGroupName);
/// <summary>
/// <para>Enumerates services in the specified service control manager database. The name and status of each service are provided.</para>
/// <para>
/// This function has been superseded by the EnumServicesStatusEx function. It returns the same information <c>EnumServicesStatus</c>
/// returns, plus the process identifier and additional information for the service. In addition, <c>EnumServicesStatusEx</c> enables
/// you to enumerate services that belong to a specified group.
/// </para>
/// </summary>
/// <param name="hSCManager">
/// A handle to the service control manager database. This handle is returned by the OpenSCManager function, and must have the
/// SC_MANAGER_ENUMERATE_SERVICE access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwServiceType">The type of services to be enumerated. This parameter can be one or more of the following values.</param>
/// <param name="dwServiceState">The state of the services to be enumerated. This parameter can be one of the following values.</param>
/// <param name="pszGroupName">
/// The load-order group name. If this parameter is a string, the only services enumerated are those that belong to the group that
/// has the name specified by the string. If this parameter is an empty string, only services that do not belong to any group are
/// enumerated. If this parameter is <c>NULL</c>, group membership is ignored and all services are enumerated.
/// </param>
/// <returns>A list of ENUM_SERVICE_STATUS structures with the name and service status information for each service in the database.</returns>
public static IEnumerable<ENUM_SERVICE_STATUS_PROCESS> EnumServicesStatusEx(SC_HANDLE hSCManager, ServiceTypes dwServiceType = ServiceTypes.SERVICE_TYPE_ALL, SERVICE_STATE dwServiceState = SERVICE_STATE.SERVICE_STATE_ALL, string pszGroupName = null)
{
var hRes = 0U;
Win32Error lastErr;
var res = EnumServicesStatusEx(hSCManager, 0, dwServiceType, dwServiceState, default, 0, out var sz, out _, ref hRes, pszGroupName);
if (!res && (lastErr = Win32Error.GetLastError()) != Win32Error.ERROR_MORE_DATA)
lastErr.ThrowIfFailed();
using (var mem = new SafeHGlobalHandle((int)sz))
{
do
{
res = EnumServicesStatusEx(hSCManager, 0, dwServiceType, dwServiceState, (IntPtr)mem, sz, out sz, out var cnt, ref hRes, pszGroupName);
if (!res && (lastErr = Win32Error.GetLastError()) != Win32Error.ERROR_MORE_DATA)
lastErr.ThrowIfFailed();
foreach (var i in mem.ToArray<ENUM_SERVICE_STATUS_PROCESS>((int)cnt))
yield return i;
} while (!res);
}
}
/// <summary>Retrieves the display name of the specified service.</summary>
/// <param name="hSCManager">A handle to the service control manager database, as returned by the OpenSCManager function.</param>
/// <param name="lpServiceName">
/// The service name. This name is the same as the service's registry key name. It is best to choose a name that is less than 256 characters.
/// </param>
/// <param name="lpDisplayName">
/// <para>
/// A pointer to a buffer that receives the service's display name. If the function fails, this buffer will contain an empty string.
/// </para>
/// <para>
/// The maximum size of this array is 4K bytes. To determine the required size, specify NULL for this parameter and 0 for the
/// lpcchBuffer parameter. The function will fail and GetLastError will return <c>ERROR_INSUFFICIENT_BUFFER</c>. The lpcchBuffer
/// parameter will receive the required size.
/// </para>
/// <para>This parameter can specify a localized string using the following format:</para>
/// <para>@[path]dllname,-strID</para>
/// <para>The string with identifier strID is loaded from dllname; the path is optional. For more information, see RegLoadMUIString.</para>
/// <para><c>Windows Server 2003 and Windows XP:</c> Localized strings are not supported until Windows Vista.</para>
/// </param>
/// <param name="lpcchBuffer">
/// <para>A pointer to a variable that specifies the size of the buffer pointed to by lpDisplayName, in <c>TCHARs</c>.</para>
/// <para>
/// On output, this variable receives the size of the service's display name, in characters, excluding the null-terminating character.
/// </para>
/// <para>
/// If the buffer pointed to by lpDisplayName is too small to contain the display name, the function does not store it. When the
/// function returns, lpcchBuffer contains the size of the service's display name, excluding the null-terminating character.
/// </para>
/// </param>
/// <returns>
/// <para>If the functions succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// </returns>
/// <remarks>
/// There are two names for a service: the service name and the display name. The service name is the name of the service's key in
/// the registry. The display name is a user-friendly name that appears in the Services control panel application, and is used with
/// the <c>NET START</c> command. To map the service name to the display name, use the <c>GetServiceDisplayName</c> function. To map
/// the display name to the service name, use the GetServiceKeyName function.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-getservicedisplaynamea BOOL GetServiceDisplayNameA(
// SC_HANDLE hSCManager, LPCSTR lpServiceName, LPSTR lpDisplayName, LPDWORD lpcchBuffer );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "704812f3-134c-4161-b3b4-a955d87ff563")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetServiceDisplayName(SC_HANDLE hSCManager, string lpServiceName, StringBuilder lpDisplayName, ref uint lpcchBuffer);
/// <summary>Retrieves the service name of the specified service.</summary>
/// <param name="hSCManager">A handle to the computer's service control manager database, as returned by OpenSCManager.</param>
/// <param name="lpDisplayName">The service display name. This string has a maximum length of 256 characters.</param>
/// <param name="lpServiceName">
/// <para>A pointer to a buffer that receives the service name. If the function fails, this buffer will contain an empty string.</para>
/// <para>
/// The maximum size of this array is 4K bytes. To determine the required size, specify NULL for this parameter and 0 for the
/// lpcchBuffer parameter. The function will fail and GetLastError will return <c>ERROR_INSUFFICIENT_BUFFER</c>. The lpcchBuffer
/// parameter will receive the required size.
/// </para>
/// </param>
/// <param name="lpcchBuffer">
/// <para>
/// A pointer to variable that specifies the size of the buffer pointed to by the lpServiceName parameter, in <c>TCHARs</c>. When the
/// function returns, this parameter contains the size of the service name, in <c>TCHARs</c>, excluding the null-terminating character.
/// </para>
/// <para>
/// If the buffer pointed to by lpServiceName is too small to contain the service name, the function stores no data in it. When the
/// function returns, lpcchBuffer contains the size of the service name, excluding the NULL terminator.
/// </para>
/// </param>
/// <returns>
/// <para>If the functions succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// </returns>
/// <remarks>
/// <para>
/// There are two names for a service: the service name and the display name. The service name is the name of the service's key in
/// the registry. The display name is a user-friendly name that appears in the Services control panel application, and is used with
/// the <c>NET START</c> command. Both names are specified with the CreateService function and can be modified with the
/// ChangeServiceConfig function. Information specified for a service is stored in a key with the same name as the service name under
/// the <c>HKEY_LOCAL_MACHINE</c>&lt;b&gt;System&lt;b&gt;CurrentControlSet&lt;b&gt;Services&lt;i&gt;ServiceName registry key.
/// </para>
/// <para>
/// To map the service name to the display name, use the GetServiceDisplayName function. To map the display name to the service name,
/// use the <c>GetServiceKeyName</c> function.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-getservicekeynamea BOOL GetServiceKeyNameA( SC_HANDLE
// hSCManager, LPCSTR lpDisplayName, LPSTR lpServiceName, LPDWORD lpcchBuffer );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "d2421566-de4a-49e5-bb41-ea98c6f6d19d")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetServiceKeyName(SC_HANDLE hSCManager, string lpDisplayName, StringBuilder lpServiceName, ref uint lpcchBuffer);
/// <summary>
/// <para>[As of Windows Vista, this function is provided for application compatibility and has no effect on the database.]</para>
/// <para>
/// Requests ownership of the service control manager (SCM) database lock. Only one process can own the lock at any specified time.
/// </para>
/// </summary>
/// <param name="hSCManager">
/// A handle to the SCM database. This handle is returned by the OpenSCManager function, and must have the <c>SC_MANAGER_LOCK</c>
/// access right. For more information, see Service Security and Access Rights.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a lock to the specified SCM database.</para>
/// <para>If the function fails, the return value is NULL. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the SCM. Other error codes can be set by registry functions that are called by the SCM.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SC_MANAGER_LOCK access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is not valid.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DATABASE_LOCKED</term>
/// <term>The database is locked.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// A lock is a protocol used by setup and configuration programs and the SCM to serialize access to the service tree in the
/// registry. The only time the SCM requests ownership of the lock is when it is starting a service.
/// </para>
/// <para>
/// A program that acquires the SCM database lock and fails to release it prevents the SCM from starting other services. Because of
/// the severity of this issue, processes are no longer allowed to lock the database. For compatibility with older applications, the
/// <c>LockServiceDatabase</c> function returns a lock but has no other effect.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> Acquiring the SCM database lock prevents the SCM from starting a service until the
/// lock is released. For example, a program that must configure several related services before any of them starts could call
/// <c>LockServiceDatabase</c> before configuring the first service. Alternatively, it could ensure that none of the services are
/// started until the configuration has been completed.
/// </para>
/// <para>
/// A call to the StartService function to start a service in a locked database fails. No other SCM functions are affected by a lock.
/// </para>
/// <para>
/// The lock is held until the <c>SC_LOCK</c> handle is specified in a subsequent call to the UnlockServiceDatabase function. If a
/// process that owns a lock terminates, the SCM automatically cleans up and releases ownership of the lock.
/// </para>
/// <para>Failing to release the lock can cause system problems. A process that acquires the lock should release it as soon as possible.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-lockservicedatabase SC_LOCK LockServiceDatabase( SC_HANDLE
// hSCManager );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "87861465-c966-479a-b906-27ae36cc83c8")]
public static extern SC_LOCK LockServiceDatabase(SC_HANDLE hSCManager);
/// <summary>
/// Reports the boot status to the service control manager. It is used by boot verification programs. This function can be called
/// only by a process running in the LocalSystem or Administrator's account.
/// </summary>
/// <param name="BootAcceptable">
/// If the value is TRUE, the system saves the configuration as the last-known good configuration. If the value is FALSE, the system
/// immediately reboots, using the previously saved last-known good configuration.
/// </param>
/// <returns>
/// <para>If the BootAcceptable parameter is FALSE, the function does not return.</para>
/// <para>If the last-known good configuration was successfully saved, the return value is nonzero.</para>
/// <para>If an error occurs, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that
/// are called by the service control manager to set parameters in the configuration registry.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>
/// The user does not have permission to perform this operation. Only the system and members of the Administrator's group can do so.
/// </term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// Saving the configuration of a running system with this function is an acceptable method for saving the last-known good
/// configuration. If the boot configuration is unacceptable, use this function to reboot the system using the existing last-known
/// good configuration.
/// </para>
/// <para>
/// This function call requires the caller's token to have permission to acquire the SC_MANAGER_MODIFY_BOOT_CONFIG access right. For
/// more information, see Service Security and Access Rights.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-notifybootconfigstatus BOOL NotifyBootConfigStatus( BOOL
// BootAcceptable );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "0b2b9cd0-f897-4681-9e99-5d0bed986112")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool NotifyBootConfigStatus([MarshalAs(UnmanagedType.Bool)] bool BootAcceptable);
/// <summary>
/// Enables an application to receive notification when the specified service is created or deleted or when its status changes.
/// </summary>
/// <param name="hService">
/// <para>
/// A handle to the service or the service control manager. Handles to services are returned by the OpenService or CreateService
/// function and must have the SERVICE_QUERY_STATUS access right. Handles to the service control manager are returned by the
/// OpenSCManager function and must have the SC_MANAGER_ENUMERATE_SERVICE access right. For more information, see Service Security
/// and Access Rights.
/// </para>
/// <para>There can only be one outstanding notification request per service.</para>
/// </param>
/// <param name="dwNotifyMask">
/// The type of status changes that should be reported. This parameter can be one or more of the following values.
/// </param>
/// <param name="pNotifyBuffer">
/// <para>
/// A pointer to a SERVICE_NOTIFY structure that contains notification information, such as a pointer to the callback function. This
/// structure must remain valid until the callback function is invoked or the calling thread cancels the notification request.
/// </para>
/// <para>
/// Do not make multiple calls to <c>NotifyServiceStatusChange</c> with the same buffer parameter until the callback function from
/// the first call has finished with the buffer or the first notification request has been canceled. Otherwise, there is no guarantee
/// which version of the buffer the callback function will receive.
/// </para>
/// <para>
/// <c>Windows Vista:</c> The address of the callback function must be within the address range of a loaded module. Therefore, the
/// callback function cannot be code that is generated at run time (such as managed code generated by the JIT compiler) or native
/// code that is decompressed at run time. This restriction was removed in Windows Server 2008 and Windows Vista with SP1.
/// </para>
/// </param>
/// <returns>
/// <para>
/// If the function succeeds, the return value is ERROR_SUCCESS. If the service has been marked for deletion, the return value is
/// ERROR_SERVICE_MARKED_FOR_DELETE and the handle to the service must be closed. If service notification is lagging too far behind
/// the system state, the function returns ERROR_SERVICE_NOTIFY_CLIENT_LAGGING. In this case, the client should close the handle to
/// the SCM, open a new handle, and call this function again.
/// </para>
/// <para>If the function fails, the return value is one of the system error codes.</para>
/// </returns>
/// <remarks>
/// <para>
/// The <c>NotifyServiceStatusChange</c> function can be used to receive notifications about service applications. It cannot be used
/// to receive notifications about driver services.
/// </para>
/// <para>
/// When the service status changes, the system invokes the specified callback function as an asynchronous procedure call (APC)
/// queued to the calling thread. The calling thread must enter an alertable wait (for example, by calling the SleepEx function) to
/// receive notification. For more information, see Asynchronous Procedure Calls.
/// </para>
/// <para>
/// If the service is already in any of the requested states when <c>NotifyServiceStatusChange</c> is called, the callback function
/// is queued immediately. If the service state has not changed by the next time the function is called with the same service and
/// state, the callback function is not queued immediately; the callback function is queued the next time the service enters the
/// requested state.
/// </para>
/// <para>
/// The <c>NotifyServiceStatusChange</c> function calls the OpenThread function on the calling thread with the THREAD_SET_CONTEXT
/// access right. If the calling thread does not have this access right, <c>NotifyServiceStatusChange</c> fails. If the calling
/// thread is impersonating another user, it may not have sufficient permission to set context.
/// </para>
/// <para>
/// It is more efficient to call <c>NotifyServiceStatusChange</c> from a thread that performs a wait than to create an additional thread.
/// </para>
/// <para>
/// After the callback function is invoked, the caller must call <c>NotifyServiceStatusChange</c> to receive additional
/// notifications. Note that certain functions in the Windows API, including <c>NotifyServiceStatusChange</c> and other SCM
/// functions, use remote procedure calls (RPC); these functions might perform an alertable wait operation, so they are not safe to
/// call from within the callback function. Instead, the callback function should save the notification parameters and perform any
/// additional work outside the callback.
/// </para>
/// <para>
/// To cancel outstanding notifications, close the service handle using the CloseServiceHandle function. After
/// <c>CloseServiceHandle</c> succeeds, no more notification APCs will be queued. If the calling thread exits without closing the
/// service handle or waiting until the APC is generated, a memory leak can occur.
/// </para>
/// <para>
/// <c>Important</c> If the calling thread is in a DLL and the DLL is unloaded before the thread receives the notification or calls
/// CloseServiceHandle, the notification will cause unpredictable results and might cause the process to stop responding.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-notifyservicestatuschangea DWORD NotifyServiceStatusChangeA(
// SC_HANDLE hService, DWORD dwNotifyMask, PSERVICE_NOTIFYA pNotifyBuffer );
[DllImport(Lib.AdvApi32, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "e22b7f69-f096-486f-97fa-0465bef499cd")]
public static extern Win32Error NotifyServiceStatusChange(SC_HANDLE hService, SERVICE_NOTIFY_FLAGS dwNotifyMask, IntPtr pNotifyBuffer); // ref SERVICE_NOTIFY_2 pNotifyBuffer);
/// <summary>
/// <para>
/// Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.
/// </para>
/// </summary>
/// <param name="lpMachineName">
/// <para>
/// The name of the target computer. If the pointer is NULL or points to an empty string, the function connects to the service
/// control manager on the local computer.
/// </para>
/// </param>
/// <param name="lpDatabaseName">
/// <para>
/// The name of the service control manager database. This parameter should be set to SERVICES_ACTIVE_DATABASE. If it is NULL, the
/// SERVICES_ACTIVE_DATABASE database is opened by default.
/// </para>
/// </param>
/// <param name="dwDesiredAccess">
/// <para>The access to the service control manager. For a list of access rights, see Service Security and Access Rights.</para>
/// <para>
/// Before granting the requested access rights, the system checks the access token of the calling process against the discretionary
/// access-control list of the security descriptor associated with the service control manager.
/// </para>
/// <para>The SC_MANAGER_CONNECT access right is implicitly specified by calling this function.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a handle to the specified service control manager database.</para>
/// <para>If the function fails, the return value is NULL. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the SCM. Other error codes can be set by the registry functions that are called by the SCM.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The requested access was denied.</term>
/// </item>
/// <item>
/// <term>ERROR_DATABASE_DOES_NOT_EXIST</term>
/// <term>The specified database does not exist.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// When a process uses the <c>OpenSCManager</c> function to open a handle to a service control manager database, the system performs
/// a security check before granting the requested access. For more information, see Service Security and Access Rights.
/// </para>
/// <para>
/// If the current user does not have proper access when connecting to a service on another computer, the <c>OpenSCManager</c>
/// function call fails. To connect to a service remotely, call the LogonUser function with LOGON32_LOGON_NEW_CREDENTIALS and then
/// call ImpersonateLoggedOnUser before calling <c>OpenSCManager</c>. For more information about connecting to services remotely, see
/// Services and RPC/TCP.
/// </para>
/// <para>
/// Only processes with Administrator privileges are able to open a database handle that can be used by the CreateService function.
/// </para>
/// <para>
/// The returned handle is only valid for the process that called the <c>OpenSCManager</c> function. It can be closed by calling the
/// CloseServiceHandle function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Changing a Service's Configuration.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-openscmanagera SC_HANDLE OpenSCManagerA( LPCSTR
// lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "a0237989-e5a7-4a3a-ab23-e2474a995341")]
public static extern SafeSC_HANDLE OpenSCManager(string lpMachineName, string lpDatabaseName, ScManagerAccessTypes dwDesiredAccess);
/// <summary>
/// <para>Opens an existing service.</para>
/// </summary>
/// <param name="hSCManager">
/// <para>
/// A handle to the service control manager database. The OpenSCManager function returns this handle. For more information, see
/// Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="lpServiceName">
/// <para>
/// The name of the service to be opened. This is the name specified by the lpServiceName parameter of the CreateService function
/// when the service object was created, not the service display name that is shown by user interface applications to identify the service.
/// </para>
/// <para>
/// The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but
/// service name comparisons are always case insensitive. Forward-slash (/) and backslash () are invalid service name characters.
/// </para>
/// </param>
/// <param name="dwDesiredAccess">
/// <para>The access to the service. For a list of access rights, see Service Security and Access Rights.</para>
/// <para>
/// Before granting the requested access, the system checks the access token of the calling process against the discretionary
/// access-control list of the security descriptor associated with the service object.
/// </para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a handle to the service.</para>
/// <para>If the function fails, the return value is NULL. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Others can be set by the registry functions that are called
/// by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have access to the service.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_NAME</term>
/// <term>The specified service name is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DOES_NOT_EXIST</term>
/// <term>The specified service does not exist.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The returned handle is only valid for the process that called <c>OpenService</c>. It can be closed by calling the
/// CloseServiceHandle function.
/// </para>
/// <para>To use <c>OpenService</c>, no privileges are required aside from <c>SC_MANAGER_CONNECT</c>.</para>
/// <para>Examples</para>
/// <para>For an example, see Starting a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-openservicea SC_HANDLE OpenServiceA( SC_HANDLE hSCManager,
// LPCSTR lpServiceName, DWORD dwDesiredAccess );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "e0a42613-95ad-4d0f-a464-c6df33014064")]
public static extern SafeSC_HANDLE OpenService(SC_HANDLE hSCManager, string lpServiceName, ServiceAccessTypes dwDesiredAccess);
/// <summary>
/// Retrieves the configuration parameters of the specified service. Optional configuration parameters are available using the
/// QueryServiceConfig2 function.
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the
/// SERVICE_QUERY_CONFIG access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="lpServiceConfig">
/// A pointer to a buffer that receives the service configuration information. The format of the data is a QUERY_SERVICE_CONFIG structure.
/// <para>
/// The maximum size of this array is 8K bytes. To determine the required size, specify NULL for this parameter and 0 for the
/// cbBufSize parameter. The function will fail and GetLastError will return ERROR_INSUFFICIENT_BUFFER. The pcbBytesNeeded parameter
/// will receive the required size.
/// </para>
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpServiceConfig parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to store all the configuration information, if the function
/// fails with ERROR_INSUFFICIENT_BUFFER.
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
/// information, call GetLastError.
/// </returns>
[DllImport(Lib.AdvApi32, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[PInvokeData("winsvc.h", MSDNShortId = "ms684932")]
public static extern bool QueryServiceConfig(SC_HANDLE hService, IntPtr lpServiceConfig, uint cbBufSize, out uint pcbBytesNeeded);
/// <summary>
/// <para>Retrieves the optional configuration parameters of the specified service.</para>
/// </summary>
/// <param name="hService">
/// <para>
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// <c>SERVICE_QUERY_CONFIG</c> access right. For more information, see Service Security and Access Rights.
/// </para>
/// </param>
/// <param name="dwInfoLevel">
/// <para>The configuration information to be queried. This parameter can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_DELAYED_AUTO_START_INFO structure. Windows Server 2003 and Windows XP: This value
/// is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_DESCRIPTION 1</term>
/// <term>The lpBuffer parameter is a pointer to a SERVICE_DESCRIPTION structure.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_FAILURE_ACTIONS 2</term>
/// <term>The lpBuffer parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.</term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_FAILURE_ACTIONS_FLAG 4</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS_FLAG structure. Windows Server 2003 and Windows XP: This value is
/// not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_PREFERRED_NODE 9</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_PREFERRED_NODE_INFO structure. Windows Server 2008, Windows Vista, Windows Server
/// 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_PRESHUTDOWN_INFO 7</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_PRESHUTDOWN_INFO structure. Windows Server 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO 6</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_REQUIRED_PRIVILEGES_INFO structure. Windows Server 2003 and Windows XP: This value
/// is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_SERVICE_SID_INFO 5</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_SID_INFO structure. Windows Server 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_TRIGGER_INFO 8</term>
/// <term>
/// The lpInfo parameter is a pointer to a SERVICE_TRIGGER_INFO structure. Windows Server 2008, Windows Vista, Windows Server 2003
/// and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_CONFIG_LAUNCH_PROTECTED 12</term>
/// <term>The lpInfo parameter is a pointer a SERVICE_LAUNCH_PROTECTED_INFO structure.</term>
/// </item>
/// </list>
/// </param>
/// <param name="lpBuffer">
/// <para>
/// A pointer to the buffer that receives the service configuration information. The format of this data depends on the value of the
/// dwInfoLevel parameter.
/// </para>
/// <para>
/// The maximum size of this array is 8K bytes. To determine the required size, specify <c>NULL</c> for this parameter and 0 for the
/// cbBufSize parameter. The function fails and GetLastError returns <c>ERROR_INSUFFICIENT_BUFFER</c>. The pcbBytesNeeded parameter
/// receives the needed size.
/// </para>
/// </param>
/// <param name="cbBufSize">
/// <para>The size of the structure pointed to by the lpBuffer parameter, in bytes.</para>
/// </param>
/// <param name="pcbBytesNeeded">
/// <para>
/// A pointer to a variable that receives the number of bytes required to store the configuration information, if the function fails
/// with <c>ERROR_INSUFFICIENT_BUFFER</c>.
/// </para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Others can be set by the registry functions that are called
/// by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SERVICE_QUERY_CONFIG access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INSUFFICIENT_BUFFER</term>
/// <term>
/// There is more service configuration information than would fit into the lpBuffer buffer. The number of bytes required to get all
/// the information is returned in the pcbBytesNeeded parameter. Nothing is written to lpBuffer.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>QueryServiceConfig2</c> function returns the optional configuration information stored in the service control manager
/// database for the specified service. You can change this configuration information by using the ChangeServiceConfig2 function.
/// </para>
/// <para>
/// You can change and query additional configuration information using the ChangeServiceConfig and QueryServiceConfig functions, respectively.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Querying a Service's Configuration.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryserviceconfig2a BOOL QueryServiceConfig2A( SC_HANDLE
// hService, DWORD dwInfoLevel, LPBYTE lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "cb090e59-aeff-4420-bb7c-912a4911006f")]
public static extern bool QueryServiceConfig2(SC_HANDLE hService, ServiceConfigOption dwInfoLevel, IntPtr lpBuffer, uint cbBufSize, out uint pcbBytesNeeded);
/// <summary>Retrieves the optional configuration parameters of a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function and must have the
/// SERVICE_CHANGE_CONFIG access right.
/// </param>
/// <param name="dwInfoLevel">The configuration information to be queried.</param>
/// <param name="configInfo">
/// A variable that receives the service configuration information. The format of this data depends on the value of the dwInfoLevel parameter.
/// </param>
/// <returns>
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
/// information, call GetLastError.
/// </returns>
[PInvokeData("winsvc.h", MSDNShortId = "ms684935")]
public static bool QueryServiceConfig2<T>(SC_HANDLE hService, ServiceConfigOption dwInfoLevel, out T configInfo)
{
if (!CorrespondingTypeAttribute.CanGet(dwInfoLevel, typeof(T))) throw new ArgumentException("Type mismatch", nameof(configInfo));
var b = QueryServiceConfig2(hService, dwInfoLevel, IntPtr.Zero, 0, out var size);
configInfo = default;
if (!b && Win32Error.GetLastError() != Win32Error.ERROR_INSUFFICIENT_BUFFER) return false;
using (var buf = new SafeHGlobalHandle((int)size))
{
if (!QueryServiceConfig2(hService, dwInfoLevel, (IntPtr)buf, size, out size)) return false;
configInfo = buf.ToStructure<T>();
return true;
}
}
/// <summary>Retrieves dynamic information related to the current service start.</summary>
/// <param name="hServiceStatus">A service status handle provided by RegisterServiceCtrlHandlerEx</param>
/// <param name="dwInfoLevel">Indicates the information level.</param>
/// <param name="ppDynamicInfo">
/// A dynamic information buffer. If this parameter is valid, the callback function must free the buffer after use with the LocalFree function.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is TRUE.</para>
/// <para>
/// If the function fails, the return value is FALSE. When this happens the GetLastError function should be called to retrieve the
/// error code.
/// </para>
/// </returns>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicedynamicinformation BOOL
// QueryServiceDynamicInformation( SERVICE_STATUS_HANDLE hServiceStatus, DWORD dwInfoLevel, PVOID *ppDynamicInfo );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "499b63fd-e77b-4b90-9ee7-ff4b7b12c431")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryServiceDynamicInformation(SERVICE_STATUS_HANDLE hServiceStatus, uint dwInfoLevel, out SafeLocalHandle ppDynamicInfo);
/// <summary>
/// <para>[This function has no effect as of Windows Vista.]</para>
/// <para>Retrieves the lock status of the specified service control manager database.</para>
/// </summary>
/// <param name="hSCManager">
/// A handle to the service control manager database. The OpenSCManager function returns this handle, which must have the
/// SC_MANAGER_QUERY_LOCK_STATUS access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="lpLockStatus">
/// A pointer to a QUERY_SERVICE_LOCK_STATUS structure that receives the lock status of the specified database is returned, plus the
/// strings to which its members point.
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpLockStatus parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to return all the lock status information, if the function fails.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SC_MANAGER_QUERY_LOCK_STATUS access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INSUFFICIENT_BUFFER</term>
/// <term>
/// There is more lock status information than would fit into the lpLockStatus buffer. The number of bytes required to get all the
/// information is returned in the pcbBytesNeeded parameter. Nothing is written to lpLockStatus.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>QueryServiceLockStatus</c> function returns a QUERY_SERVICE_LOCK_STATUS structure that indicates whether the specified
/// database is locked. If the database is locked, the structure provides the account name of the user that owns the lock and the
/// length of time that the lock has been held.
/// </para>
/// <para>
/// A process calls the LockServiceDatabase function to acquire ownership of a service control manager database lock and the
/// UnlockServiceDatabase function to release the lock.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicelockstatusa BOOL QueryServiceLockStatusA(
// SC_HANDLE hSCManager, LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, DWORD cbBufSize, LPDWORD pcbBytesNeeded );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "5139d31b-65f1-41ba-852a-91eab1dc366e")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryServiceLockStatus(SC_HANDLE hSCManager, IntPtr lpLockStatus, uint cbBufSize, out uint pcbBytesNeeded);
/// <summary>
/// The <c>QueryServiceObjectSecurity</c> function retrieves a copy of the security descriptor associated with a service object. You
/// can also use the GetNamedSecurityInfo function to retrieve a security descriptor.
/// </summary>
/// <param name="hService">
/// A handle to the service control manager or the service. Handles to the service control manager are returned by the OpenSCManager
/// function, and handles to a service are returned by either the OpenService or CreateService function. The handle must have the
/// READ_CONTROL access right.
/// </param>
/// <param name="dwSecurityInformation">
/// A set of bit flags that indicate the type of security information to retrieve. This parameter can be a combination of the
/// SECURITY_INFORMATION bit flags, with the exception that this function does not support the <c>LABEL_SECURITY_INFORMATION</c> value.
/// </param>
/// <param name="lpSecurityDescriptor">
/// A pointer to a buffer that receives a copy of the security descriptor of the specified service object. The calling process must
/// have the appropriate access to view the specified aspects of the security descriptor of the object. The SECURITY_DESCRIPTOR
/// structure is returned in self-relative format.
/// </param>
/// <param name="cbBufSize">
/// The size of the buffer pointed to by the lpSecurityDescriptor parameter, in bytes. The largest size allowed is 8 kilobytes.
/// </param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to return the requested security descriptor information, if the
/// function fails.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The specified handle was not opened with READ_CONTROL access, or the calling process is not the owner of the object.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is not valid.</term>
/// </item>
/// <item>
/// <term>ERROR_INSUFFICIENT_BUFFER</term>
/// <term>
/// The security descriptor information is too large for the lpSecurityDescriptor buffer. The number of bytes required to get all the
/// information is returned in the pcbBytesNeeded parameter. Nothing is written to the lpSecurityDescriptor buffer.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>The specified security information is not valid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// When a service is created, the service control manager assigns a default security descriptor to the service object. To retrieve a
/// copy of the security descriptor for a service object, call the <c>QueryServiceObjectSecurity</c> function. To change the security
/// descriptor, call the SetServiceObjectSecurity function. For a description of the default security descriptor for a service
/// object, see Service Security and Access Rights.
/// </para>
/// <para>
/// To read the owner, group, or DACL from the security descriptor of the service object, the calling process must have been granted
/// READ_CONTROL access when the handle was opened. To get READ_CONTROL access, the caller must be the owner of the object or the
/// DACL of the object must grant the access.
/// </para>
/// <para>
/// To read the SACL from the security descriptor, the calling process must have been granted ACCESS_SYSTEM_SECURITY access when the
/// handle was opened. The correct way to get this access is to enable the SE_SECURITY_NAME privilege in the caller's current token,
/// open the handle for ACCESS_SYSTEM_SECURITY access, and then disable the privilege.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryserviceobjectsecurity BOOL QueryServiceObjectSecurity(
// SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor, DWORD cbBufSize,
// LPDWORD pcbBytesNeeded );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "5d95945f-f11b-42af-b302-8d924917b9ab")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryServiceObjectSecurity(SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor, uint cbBufSize, out uint pcbBytesNeeded);
/// <summary>
/// <para>Retrieves the current status of the specified service.</para>
/// <para>
/// This function has been superseded by the QueryServiceStatusEx function. <c>QueryServiceStatusEx</c> returns the same information
/// <c>QueryServiceStatus</c> returns, with the addition of the process identifier and additional information for the service.
/// </para>
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or the CreateService function, and it must have the
/// SERVICE_QUERY_STATUS access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="lpServiceStatus">A pointer to a SERVICE_STATUS structure that receives the status information.</param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SERVICE_QUERY_STATUS access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle is invalid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// The <c>QueryServiceStatus</c> function returns the most recent service status information reported to the service control
/// manager. If the service just changed its status, it may not have updated the service control manager yet.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicestatus BOOL QueryServiceStatus( SC_HANDLE
// hService, LPSERVICE_STATUS lpServiceStatus );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "dcd2d8a1-10ef-4229-b873-b4fc3ec9293f")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryServiceStatus(SC_HANDLE hService, out SERVICE_STATUS lpServiceStatus);
/// <summary>Retrieves the current status of the specified service based on the specified information level.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the CreateService or OpenService function, and it must have the
/// SERVICE_QUERY_STATUS access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="InfoLevel">
/// <para>
/// The service attributes to be returned. Use SC_STATUS_PROCESS_INFO to retrieve the service status information. The lpBuffer
/// parameter is a pointer to a SERVICE_STATUS_PROCESS structure.
/// </para>
/// <para>Currently, no other information levels are defined.</para>
/// </param>
/// <param name="lpBuffer">
/// <para>
/// A pointer to the buffer that receives the status information. The format of this data depends on the value of the InfoLevel parameter.
/// </para>
/// <para>
/// The maximum size of this array is 8K bytes. To determine the required size, specify NULL for this parameter and 0 for the
/// cbBufSize parameter. The function will fail and GetLastError will return ERROR_INSUFFICIENT_BUFFER. The pcbBytesNeeded parameter
/// will receive the required size.
/// </para>
/// </param>
/// <param name="cbBufSize">The size of the buffer pointed to by the lpBuffer parameter, in bytes.</param>
/// <param name="pcbBytesNeeded">
/// A pointer to a variable that receives the number of bytes needed to store all status information, if the function fails with ERROR_INSUFFICIENT_BUFFER.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>
/// If the function fails, the return value is zero. To get extended error information, call GetLastError. The following errors can
/// be returned.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SERVICE_QUERY_STATUS access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INSUFFICIENT_BUFFER</term>
/// <term>The buffer is too small for the SERVICE_STATUS_PROCESS structure. Nothing was written to the structure.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>The cbSize member of SERVICE_STATUS_PROCESS is not valid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_LEVEL</term>
/// <term>The InfoLevel parameter contains an unsupported value.</term>
/// </item>
/// <item>
/// <term>ERROR_SHUTDOWN_IN_PROGRESS</term>
/// <term>The system is shutting down; this function cannot be called.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>QueryServiceStatusEx</c> function returns the most recent service status information reported to the service control
/// manager. If the service just changed its status, it may not have updated the service control manager yet.
/// </para>
/// <para>
/// The process identifier returned in the SERVICE_STATUS_PROCESS structure is valid provided that the state of the service is one of
/// SERVICE_RUNNING, SERVICE_PAUSE_PENDING, SERVICE_PAUSED, or SERVICE_CONTINUE_PENDING. If the service is in a SERVICE_START_PENDING
/// or SERVICE_STOP_PENDING state, however, the process identifier may not be valid, and if the service is in the SERVICE_STOPPED
/// state, it is never valid.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting a Service or Stopping a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicestatusex BOOL QueryServiceStatusEx( SC_HANDLE
// hService, SC_STATUS_TYPE InfoLevel, LPBYTE lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "3fe02245-97b1-49f3-8f35-2dcd6f221547")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, IntPtr lpBuffer, uint cbBufSize, out uint pcbBytesNeeded);
/// <summary>Retrieves the current status of the specified service based on the specified information level.</summary>
/// <typeparam name="T">The type of the structure to return. This must align to the structured defined by <paramref name="InfoLevel"/>.</typeparam>
/// <param name="hService">
/// A handle to the service. This handle is returned by the CreateService or OpenService function, and it must have the
/// SERVICE_QUERY_STATUS access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="InfoLevel">
/// <para>
/// The service attributes to be returned. Use SC_STATUS_PROCESS_INFO to retrieve the service status information. The lpBuffer
/// parameter is a pointer to a SERVICE_STATUS_PROCESS structure.
/// </para>
/// <para>Currently, no other information levels are defined.</para>
/// </param>
/// <returns>
/// A variable that receives the service status information. The format of this data depends on the value of the dwInfoLevel parameter.
/// </returns>
/// <exception cref="System.ArgumentException">Type mismatch - T</exception>
public static T QueryServiceStatusEx<T>(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel = SC_STATUS_TYPE.SC_STATUS_PROCESS_INFO) where T : struct
{
if (!CorrespondingTypeAttribute.CanGet(InfoLevel, typeof(T))) throw new ArgumentException("Type mismatch", nameof(T));
var b = QueryServiceStatusEx(hService, InfoLevel, IntPtr.Zero, 0, out var size);
if (!b && Win32Error.GetLastError() != Win32Error.ERROR_INSUFFICIENT_BUFFER) Win32Error.ThrowLastError();
using (var buf = new SafeHGlobalHandle((int)size))
{
if (!QueryServiceStatusEx(hService, InfoLevel, (IntPtr)buf, size, out size)) Win32Error.ThrowLastError();
return buf.ToStructure<T>();
}
}
/// <summary>
/// <para>Registers a function to handle service control requests.</para>
/// <para>
/// This function has been superseded by the RegisterServiceCtrlHandlerEx function. A service can use either function, but the new
/// function supports user-defined context data, and the new handler function supports additional extended control codes.
/// </para>
/// </summary>
/// <param name="lpServiceName">
/// <para>
/// The name of the service run by the calling thread. This is the service name that the service control program specified in the
/// CreateService function when creating the service.
/// </para>
/// <para>
/// If the service type is SERVICE_WIN32_OWN_PROCESS, the function does not verify that the specified name is valid, because there is
/// only one registered service in the process.
/// </para>
/// </param>
/// <param name="lpHandlerProc">
/// <para>A pointer to the handler function to be registered. For more information, see Handler.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a service status handle.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>The following error codes can be set by the service control manager.</para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
/// <term>
/// Not enough memory is available to convert an ANSI string parameter to Unicode. This error does not occur for Unicode string parameters.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_NOT_IN_EXE</term>
/// <term>The service entry was specified incorrectly when the process called the StartServiceCtrlDispatcher function.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The ServiceMain function of a new service should immediately call the <c>RegisterServiceCtrlHandler</c> function to register a
/// control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when
/// it receives control requests for this service. For a list of possible control codes, see Handler. The threads of the calling
/// process can use the service status handle returned by this function to identify the service in subsequent calls to the
/// SetServiceStatus function.
/// </para>
/// <para>
/// The <c>RegisterServiceCtrlHandler</c> function must be called before the first SetServiceStatus call because
/// <c>RegisterServiceCtrlHandler</c> returns a service status handle for the caller to use so that no other service can
/// inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time
/// the service specifies the controls it accepts through the <c>SetServiceStatus</c> function.
/// </para>
/// <para>
/// When the control handler function is invoked with a control request, the service must call SetServiceStatus to report status to
/// the service control manager only if the service status has changed, such as when the service is processing stop or shutdown
/// controls. If the service status has not changed, the service should not report status to the service control manager.
/// </para>
/// <para>The service status handle does not have to be closed.</para>
/// <para>Examples</para>
/// <para>For an example, see Writing a ServiceMain Function.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-registerservicectrlhandlera SERVICE_STATUS_HANDLE
// RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpHandlerProc );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "31ec28fe-8774-48fc-91ba-6fa43108e2cc")]
public static extern SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(string lpServiceName, Handler lpHandlerProc);
/// <summary>
/// <para>Registers a function to handle extended service control requests.</para>
/// </summary>
/// <param name="lpServiceName">
/// <para>
/// The name of the service run by the calling thread. This is the service name that the service control program specified in the
/// CreateService function when creating the service.
/// </para>
/// </param>
/// <param name="lpHandlerProc">
/// <para>A pointer to the handler function to be registered. For more information, see HandlerEx.</para>
/// </param>
/// <param name="lpContext">
/// <para>
/// Any user-defined data. This parameter, which is passed to the handler function, can help identify the service when multiple
/// services share a process.
/// </para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a service status handle.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>The following error codes can be set by the service control manager.</para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
/// <term>
/// Not enough memory is available to convert an ANSI string parameter to Unicode. This error does not occur for Unicode string parameters.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_NOT_IN_EXE</term>
/// <term>The service entry was specified incorrectly when the process called the StartServiceCtrlDispatcher function.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The ServiceMain function of a new service should immediately call the <c>RegisterServiceCtrlHandlerEx</c> function to register a
/// control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when
/// it receives control requests for this service. For a list of possible control codes, see HandlerEx. The threads of the calling
/// process can use the service status handle returned by this function to identify the service in subsequent calls to the
/// SetServiceStatus function.
/// </para>
/// <para>
/// The <c>RegisterServiceCtrlHandlerEx</c> function must be called before the first SetServiceStatus call because
/// <c>RegisterServiceCtrlHandlerEx</c> returns a service status handle for the caller to use so that no other service can
/// inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time
/// the service specifies the controls it accepts through the <c>SetServiceStatus</c> function.
/// </para>
/// <para>
/// When the control handler function is invoked with a control request, the service must call SetServiceStatus to report status to
/// the service control manager only if the service status has changed, such as when the service is processing stop or shutdown
/// controls. If the service status has not changed, the service should not report status to the service control manager.
/// </para>
/// <para>The service status handle does not have to be closed.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-registerservicectrlhandlerexa SERVICE_STATUS_HANDLE
// RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName, LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "23eea346-9899-4214-88f4-9b7eb7ce1332")]
public static extern SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx(string lpServiceName, HandlerEx lpHandlerProc, [Optional] IntPtr lpContext);
/// <summary>
/// Registers a service type with the service control manager and the Server service. The Server service can then announce the
/// registered service type as one it currently supports. The NetServerGetInfo and NetServerEnum functions obtain a specified
/// machine's supported service types.
/// </summary>
/// <param name="hServiceStatus">
/// A handle to the status information structure for the service. A service obtains the handle by calling the
/// RegisterServiceCtrlHandlerEx function.
/// </param>
/// <param name="dwServiceBits">
/// <para>The service type.</para>
/// <para>
/// Certain bit flags (0xC00F3F7B) are reserved for use by Microsoft. The <c>SetServiceBits</c> function fails with the error
/// ERROR_INVALID_DATA if any of these bit flags are set in dwServiceBits. The following bit flags are reserved for use by Microsoft.
/// </para>
/// <para>SV_TYPE_WORKSTATION (0x00000001)</para>
/// <para>SV_TYPE_SERVER (0x00000002)</para>
/// <para>SV_TYPE_DOMAIN_CTRL (0x00000008)</para>
/// <para>SV_TYPE_DOMAIN_BAKCTRL (0x00000010)</para>
/// <para>SV_TYPE_TIME_SOURCE (0x00000020)</para>
/// <para>SV_TYPE_AFP (0x00000040)</para>
/// <para>SV_TYPE_DOMAIN_MEMBER (0x00000100)</para>
/// <para>SV_TYPE_PRINTQ_SERVER (0x00000200)</para>
/// <para>SV_TYPE_DIALIN_SERVER (0x00000400)</para>
/// <para>SV_TYPE_XENIX_SERVER (0x00000800)</para>
/// <para>SV_TYPE_SERVER_UNIX (0x00000800)</para>
/// <para>SV_TYPE_NT (0x00001000)</para>
/// <para>SV_TYPE_WFW (0x00002000)</para>
/// <para>SV_TYPE_POTENTIAL_BROWSER (0x00010000)</para>
/// <para>SV_TYPE_BACKUP_BROWSER (0x00020000)</para>
/// <para>SV_TYPE_MASTER_BROWSER (0x00040000)</para>
/// <para>SV_TYPE_DOMAIN_MASTER (0x00080000)</para>
/// <para>SV_TYPE_LOCAL_LIST_ONLY (0x40000000)</para>
/// <para>SV_TYPE_DOMAIN_ENUM (0x80000000)</para>
/// <para>
/// Certain bit flags (0x00300084) are defined by Microsoft, but are not specifically reserved for systems software. The following
/// are these bit flags.
/// </para>
/// <para>SV_TYPE_SV_TYPE_SQLSERVER (0x00000004)</para>
/// <para>SV_TYPE_NOVELL (0x00000080)</para>
/// <para>SV_TYPE_DOMAIN_CTRL (0x00100000)</para>
/// <para>SV_TYPE_DOMAIN_BAKCTRL (0x00200000)</para>
/// <para>
/// Certain bit flags (0x3FC0C000) are not defined by Microsoft, and their use is not coordinated by Microsoft. Developers of
/// applications that use these bits should be aware that other applications can also use them, thus creating a conflict. The
/// following are these bit flags.
/// </para>
/// <para>0x00004000</para>
/// <para>0x00008000</para>
/// <para>0x00400000</para>
/// <para>0x00800000</para>
/// <para>0x01000000</para>
/// <para>0x02000000</para>
/// <para>0x04000000</para>
/// <para>0x08000000</para>
/// <para>0x10000000</para>
/// <para>0x20000000</para>
/// </param>
/// <param name="bSetBitsOn">
/// If this value is TRUE, the bits in dwServiceBit are to be set. If this value is FALSE, the bits are to be cleared.
/// </param>
/// <param name="bUpdateImmediately">
/// If this value is TRUE, the Server service is to perform an immediate update. If this value is FALSE, the update is not be
/// performed immediately.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// </returns>
// https://docs.microsoft.com/en-us/windows/desktop/api/lmserver/nf-lmserver-setservicebits BOOL NET_API_FUNCTION SetServiceBits( IN
// SERVICE_STATUS_HANDLE hServiceStatus, IN DWORD dwServiceBits, IN BOOL bSetBitsOn, IN BOOL bUpdateImmediately );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("lmserver.h", MSDNShortId = "91a985d4-d1af-4161-ae67-a8a9d6740838")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetServiceBits([In] SERVICE_STATUS_HANDLE hServiceStatus, uint dwServiceBits, [MarshalAs(UnmanagedType.Bool)] bool bSetBitsOn, [MarshalAs(UnmanagedType.Bool)] bool bUpdateImmediately);
/// <summary>
/// <para>
/// [ <c>SetServiceObjectSecurity</c> is available for use in the operating systems specified in the Requirements section. It may be
/// altered or unavailable in subsequent versions. Instead, use the SetNamedSecurityInfo function.]
/// </para>
/// <para>The <c>SetServiceObjectSecurity</c> function sets the security descriptor of a service object.</para>
/// </summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function. The access required for this
/// handle depends on the security information specified in the dwSecurityInformation parameter.
/// </param>
/// <param name="dwSecurityInformation">
/// Specifies the components of the security descriptor to set. This parameter can be a combination of the following values. Note
/// that flags not handled by <c>SetServiceObjectSecurity</c> will be silently ignored.
/// </param>
/// <param name="lpSecurityDescriptor">A pointer to a SECURITY_DESCRIPTOR structure that contains the new security information.</param>
/// <returns>
/// <para>If the function succeeds, the function returns nonzero.</para>
/// <para>If the function fails, it returns zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The specified handle was not opened with the required access, or the calling process is not the owner of the object.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is not valid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_PARAMETER</term>
/// <term>The specified security information or security descriptor is not valid.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_MARKED_FOR_DELETE</term>
/// <term>The specified service has been marked for deletion.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The <c>SetServiceObjectSecurity</c> function sets the specified portions of the security descriptor of the service object based
/// on the information specified in the lpSecurityDescriptor buffer. This function replaces any or all of the security information
/// associated with the service object, according to the flags set in the dwSecurityInformation parameter and subject to the access
/// rights of the calling process.
/// </para>
/// <para>
/// When a service is created, the service control manager assigns a default security descriptor to the service object. To retrieve a
/// copy of the security descriptor for a service object, call the QueryServiceObjectSecurity function. For a description of the
/// default security descriptor for a service object, see Service Security and Access Rights.
/// </para>
/// <para>
/// Note that granting certain access to untrusted users (such as SERVICE_CHANGE_CONFIG or SERVICE_STOP) can allow them to interfere
/// with the execution of your service and possibly allow them to run applications under the LocalSystem account.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-setserviceobjectsecurity BOOL SetServiceObjectSecurity(
// SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "39481d9a-79d5-4bbf-8480-4095a34dddb6")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetServiceObjectSecurity(SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor);
/// <summary>
/// <para>Updates the service control manager's status information for the calling service.</para>
/// </summary>
/// <param name="hServiceStatus">
/// <para>
/// A handle to the status information structure for the current service. This handle is returned by the RegisterServiceCtrlHandlerEx function.
/// </para>
/// </param>
/// <param name="lpServiceStatus">
/// <para>A pointer to the SERVICE_STATUS structure the contains the latest status information for the calling service.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_INVALID_DATA</term>
/// <term>The specified service status structure is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The specified handle is invalid.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// A ServiceMain function first calls the RegisterServiceCtrlHandlerEx function to get the service's SERVICE_STATUS_HANDLE. Then it
/// immediately calls the <c>SetServiceStatus</c> function to notify the service control manager that its status is
/// SERVICE_START_PENDING. During initialization, the service can provide updated status to indicate that it is making progress but
/// it needs more time. A common bug is for the service to have the main thread perform the initialization while a separate thread
/// continues to call <c>SetServiceStatus</c> to prevent the service control manager from marking it as hung. However, if the main
/// thread hangs, then the service start ends up in an infinite loop because the worker thread continues to report that the main
/// thread is making progress.
/// </para>
/// <para>
/// After processing a control request, the service's Handler function must call <c>SetServiceStatus</c> if the service status
/// changes to report its new status to the service control manager. It is only necessary to do so when the service is changing
/// state, such as when it is processing stop or shutdown controls. A service can also use this function at any time from any thread
/// of the service to notify the service control manager of state changes, such as when the service must stop due to a recoverable error.
/// </para>
/// <para>A service can call this function only after it has called RegisterServiceCtrlHandlerEx to get a service status handle.</para>
/// <para>
/// If a service calls <c>SetServiceStatus</c> with the <c>dwCurrentState</c> member set to SERVICE_STOPPED and the
/// <c>dwWin32ExitCode</c> member set to a nonzero value, the following entry is written into the System event log:
/// </para>
/// <para>The following are best practices when calling this function:</para>
/// <list type="bullet">
/// <item>
/// <term>
/// Initialize all fields in the SERVICE_STATUS structure, ensuring that there are valid check-point and wait hint values for pending
/// states. Use reasonable wait hints.
/// </term>
/// </item>
/// <item>
/// <term>
/// Do not register to accept controls while the status is SERVICE_START_PENDING or the service can crash. After initialization is
/// completed, accept the SERVICE_CONTROL_STOP code.
/// </term>
/// </item>
/// <item>
/// <term>
/// Call this function with checkpoint and wait-hint values only if the service is making progress on the tasks related to the
/// pending start, stop, pause, or continue operation. Otherwise, SCM cannot detect if your service is hung.
/// </term>
/// </item>
/// <item>
/// <term>Enter the stopped state with an appropriate exit code if ServiceMain fails.</term>
/// </item>
/// <item>
/// <term>
/// If the status is SERVICE_STOPPED, perform all necessary cleanup and call <c>SetServiceStatus</c> one time only. This function
/// makes an LRPC call to the SCM. The first call to the function in the SERVICE_STOPPED state closes the RPC context handle and any
/// subsequent calls can cause the process to crash.
/// </term>
/// </item>
/// <item>
/// <term>
/// Do not attempt to perform any additional work after calling <c>SetServiceStatus</c> with SERVICE_STOPPED, because the service
/// process can be terminated at any time.
/// </term>
/// </item>
/// </list>
/// <para>Examples</para>
/// <para>For an example, see Writing a ServiceMain Function.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-setservicestatus BOOL SetServiceStatus(
// SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "bb5943ff-2814-40f2-bee0-ae7132befde9")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, in SERVICE_STATUS lpServiceStatus);
/// <summary>Starts a service.</summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the SERVICE_START
/// access right. For more information, see Service Security and Access Rights.
/// </param>
/// <param name="dwNumServiceArgs">
/// The number of strings in the lpServiceArgVectors array. If lpServiceArgVectors is NULL, this parameter can be zero.
/// </param>
/// <param name="lpServiceArgVectors">
/// <para>
/// The null-terminated strings to be passed to the ServiceMain function for the service as arguments. If there are no arguments,
/// this parameter can be NULL. Otherwise, the first argument (lpServiceArgVectors[0]) is the name of the service, followed by any
/// additional arguments (lpServiceArgVectors[1] through lpServiceArgVectors[dwNumServiceArgs-1]).
/// </para>
/// <para>Driver services do not receive these arguments.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Others can be set by the registry functions that are called
/// by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_ACCESS_DENIED</term>
/// <term>The handle does not have the SERVICE_START access right.</term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_HANDLE</term>
/// <term>The handle is invalid.</term>
/// </item>
/// <item>
/// <term>ERROR_PATH_NOT_FOUND</term>
/// <term>The service binary file could not be found.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_ALREADY_RUNNING</term>
/// <term>An instance of the service is already running.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DATABASE_LOCKED</term>
/// <term>The database is locked.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DEPENDENCY_DELETED</term>
/// <term>The service depends on a service that does not exist or has been marked for deletion.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DEPENDENCY_FAIL</term>
/// <term>The service depends on another service that has failed to start.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_DISABLED</term>
/// <term>The service has been disabled.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_LOGON_FAILED</term>
/// <term>
/// The service did not start due to a logon failure. This error occurs if the service is configured to run under an account that
/// does not have the "Log on as a service" right.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_MARKED_FOR_DELETE</term>
/// <term>The service has been marked for deletion.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_NO_THREAD</term>
/// <term>A thread could not be created for the service.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_REQUEST_TIMEOUT</term>
/// <term>
/// The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called
/// StartServiceCtrlDispatcher may be blocked in a control handler function.
/// </term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// When a driver service is started, the <c>StartService</c> function does not return until the device driver has finished initializing.
/// </para>
/// <para>
/// When a service is started, the Service Control Manager (SCM) spawns the service process, if necessary. If the specified service
/// shares a process with other services, the required process may already exist. The <c>StartService</c> function does not wait for
/// the first status update from the new service, because it can take a while. Instead, it returns when the SCM receives notification
/// from the service control dispatcher that the ServiceMain thread for this service was created successfully.
/// </para>
/// <para>The SCM sets the following default status values before returning from <c>StartService</c>:</para>
/// <list type="bullet">
/// <item>
/// <term>Current state of the service is set to SERVICE_START_PENDING.</term>
/// </item>
/// <item>
/// <term>Controls accepted is set to none (zero).</term>
/// </item>
/// <item>
/// <term>The CheckPoint value is set to zero.</term>
/// </item>
/// <item>
/// <term>The WaitHint time is set to 2 seconds.</term>
/// </item>
/// </list>
/// <para>
/// The calling process can determine if the new service has finished its initialization by calling the QueryServiceStatus function
/// periodically to query the service's status.
/// </para>
/// <para>
/// A service cannot call <c>StartService</c> during initialization. The reason is that the SCM locks the service control database
/// during initialization, so a call to <c>StartService</c> will block. After the service reports to the SCM that it has successfully
/// started, it can call <c>StartService</c>.
/// </para>
/// <para>
/// As with ControlService, <c>StartService</c> will block for 30 seconds if any service is busy handling a control code. If the busy
/// service still has not returned from its handler function when the timeout expires, <c>StartService</c> fails with
/// ERROR_SERVICE_REQUEST_TIMEOUT. This is because the SCM processes only one service control notification at a time.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting a Service.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-startservicea BOOL StartServiceA( SC_HANDLE hService, DWORD
// dwNumServiceArgs, LPCSTR *lpServiceArgVectors );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "f185a878-e1c3-4fe5-8ec9-c5296d27f985")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool StartService(SC_HANDLE hService, [Optional] int dwNumServiceArgs, [Optional] string[] lpServiceArgVectors);
/// <summary>
/// Connects the main thread of a service process to the service control manager, which causes the thread to be the service control
/// dispatcher thread for the calling process.
/// </summary>
/// <param name="lpServiceStartTable">
/// A pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service that can execute in the calling
/// process. The members of the last entry in the table must have NULL values to designate the end of the table.
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error code can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_FAILED_SERVICE_CONTROLLER_CONNECT</term>
/// <term>
/// This error is returned if the program is being run as a console application rather than as a service. If the program will be run
/// as a console application for debugging purposes, structure it such that service-specific code is not called when this error is returned.
/// </term>
/// </item>
/// <item>
/// <term>ERROR_INVALID_DATA</term>
/// <term>The specified dispatch table contains entries that are not in the proper format.</term>
/// </item>
/// <item>
/// <term>ERROR_SERVICE_ALREADY_RUNNING</term>
/// <term>The process has already called StartServiceCtrlDispatcher. Each process can call StartServiceCtrlDispatcher only one time.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// When the service control manager starts a service process, it waits for the process to call the <c>StartServiceCtrlDispatcher</c>
/// function. The main thread of a service process should make this call as soon as possible after it starts up (within 30 seconds).
/// If <c>StartServiceCtrlDispatcher</c> succeeds, it connects the calling thread to the service control manager and does not return
/// until all running services in the process have entered the SERVICE_STOPPED state. The service control manager uses this
/// connection to send control and service start requests to the main thread of the service process. The main thread acts as a
/// dispatcher by invoking the appropriate HandlerEx function to handle control requests, or by creating a new thread to execute the
/// appropriate ServiceMain function when a new service is started.
/// </para>
/// <para>
/// The lpServiceTable parameter contains an entry for each service that can run in the calling process. Each entry specifies the
/// ServiceMain function for that service. For SERVICE_WIN32_SHARE_PROCESS services, each entry must contain the name of a service.
/// This name is the service name that was specified by the CreateService function when the service was installed. For
/// SERVICE_WIN32_OWN_PROCESS services, the service name in the table entry is ignored.
/// </para>
/// <para>
/// If a service runs in its own process, the main thread of the service process should immediately call
/// <c>StartServiceCtrlDispatcher</c>. All initialization tasks are done in the service's ServiceMain function when the service is started.
/// </para>
/// <para>
/// If multiple services share a process and some common process-wide initialization needs to be done before any ServiceMain function
/// is called, the main thread can do the work before calling <c>StartServiceCtrlDispatcher</c>, as long as it takes less than 30
/// seconds. Otherwise, another thread must be created to do the process-wide initialization, while the main thread calls
/// <c>StartServiceCtrlDispatcher</c> and becomes the service control dispatcher. Any service-specific initialization should still be
/// done in the individual service main functions.
/// </para>
/// <para>Services should not attempt to display a user interface directly. For more information, see Interactive Services.</para>
/// <para>Examples</para>
/// <para>For an example, see Writing a Service Program's Main Function.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-startservicectrldispatchera BOOL
// StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *lpServiceStartTable );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winsvc.h", MSDNShortId = "8e275eb7-a8af-4bd7-bb39-0eac4f3735ad")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool StartServiceCtrlDispatcher([In, MarshalAs(UnmanagedType.LPArray)] SERVICE_TABLE_ENTRY[] lpServiceStartTable);
/// <summary>Stops a service using <see cref="ControlService"/> with <see cref="ServiceControl.SERVICE_CONTROL_STOP"/></summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the <see cref="OpenService"/> or <see cref="CreateService(SC_HANDLE, string, string, uint, ServiceTypes, ServiceStartType, ServiceErrorControlType, string, string, IntPtr, string[], string, string)"/> function. The
/// access rights required for this handle depend on the <see cref="ServiceControl"/> code requested.
/// </param>
/// <param name="lpServiceStatus">
/// A pointer to a <see cref="SERVICE_STATUS"/> structure that receives the latest service status information. The information
/// returned reflects the most recent status that the service reported to the service control manager.
/// </param>
/// <returns></returns>
public static bool StopService(SC_HANDLE hService, out SERVICE_STATUS lpServiceStatus) =>
ControlService(hService, ServiceControl.SERVICE_CONTROL_STOP, out lpServiceStatus);
/// <summary>Stops a service using <see cref="ControlServiceEx"/> with <see cref="ServiceControl.SERVICE_CONTROL_STOP"/></summary>
/// <param name="hService">
/// A handle to the service. This handle is returned by the <see cref="OpenService"/> or <see cref="CreateService(SC_HANDLE, string, string, uint, ServiceTypes, ServiceStartType, ServiceErrorControlType, string, string, IntPtr, string[], string, string)"/> function. The
/// access rights required for this handle depend on the <see cref="ServiceControl"/> code requested.
/// </param>
/// <param name="reason">A reason and comment for why the service is being stopped</param>
/// <returns></returns>
public static bool StopService(SC_HANDLE hService, ref SERVICE_CONTROL_STATUS_REASON_PARAMS reason) =>
ControlServiceEx(hService, ServiceControl.SERVICE_CONTROL_STOP, ServiceInfoLevels.SERVICE_CONTROL_STATUS_REASON_INFO, ref reason);
/// <summary>
/// <para>[This function has no effect as of Windows Vista.]</para>
/// <para>Unlocks a service control manager database by releasing the specified lock.</para>
/// </summary>
/// <param name="ScLock">The lock, which is obtained from a previous call to the LockServiceDatabase function.</param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that
/// are called by the service control manager.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>ERROR_INVALID_SERVICE_LOCK</term>
/// <term>The specified lock is invalid.</term>
/// </item>
/// </list>
/// </returns>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-unlockservicedatabase BOOL UnlockServiceDatabase( SC_LOCK
// ScLock );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winsvc.h", MSDNShortId = "3277d175-ab0b-43ce-965f-f8087d0124e4")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnlockServiceDatabase(SC_LOCK ScLock);
/// <summary>
/// Contains the name of a service in a service control manager database and information about that service. It is used by the
/// EnumDependentServices and EnumServicesStatus functions.
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_statusa typedef struct _ENUM_SERVICE_STATUSA {
// LPSTR lpServiceName; LPSTR lpDisplayName; SERVICE_STATUS ServiceStatus; } ENUM_SERVICE_STATUSA, *LPENUM_SERVICE_STATUSA;
[PInvokeData("winsvc.h", MSDNShortId = "b088bd94-5d25-44a7-93c0-80ce6588b811")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct ENUM_SERVICE_STATUS
{
/// <summary>
/// The name of a service in the service control manager database. The maximum string length is 256 characters. The service
/// control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A
/// slash (/), backslash (), comma, and space are invalid service name characters.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpServiceName;
/// <summary>
/// A display name that can be used by service control programs, such as Services in Control Panel, to identify the service. This
/// string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name
/// comparisons are always case-insensitive.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDisplayName;
/// <summary>A SERVICE_STATUS structure that contains status information for the <c>lpServiceName</c> service.</summary>
public SERVICE_STATUS ServiceStatus;
}
/// <summary>
/// Contains the name of a service in a service control manager database and information about the service. It is used by the
/// EnumServicesStatusEx function.
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_status_processa typedef struct
// _ENUM_SERVICE_STATUS_PROCESSA { LPSTR lpServiceName; LPSTR lpDisplayName; SERVICE_STATUS_PROCESS ServiceStatusProcess; }
// ENUM_SERVICE_STATUS_PROCESSA, *LPENUM_SERVICE_STATUS_PROCESSA;
[PInvokeData("winsvc.h", MSDNShortId = "6a683cc8-c2ac-4093-aed7-33e6bdd02d79")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct ENUM_SERVICE_STATUS_PROCESS
{
/// <summary>
/// The name of a service in the service control manager database. The maximum string length is 256 characters. The service
/// control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A
/// slash (/), backslash (), comma, and space are invalid service name characters.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpServiceName;
/// <summary>
/// A display name that can be used by service control programs, such as Services in Control Panel, to identify the service. This
/// string has a maximum length of 256 characters. The case is preserved in the service control manager. Display name comparisons
/// are always case-insensitive.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDisplayName;
/// <summary>A SERVICE_STATUS_PROCESS structure that contains status information for the <c>lpServiceName</c> service.</summary>
public SERVICE_STATUS_PROCESS ServiceStatusProcess;
}
/// <summary>Contains configuration information for an installed service. It is used by the QueryServiceConfig function.</summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[PInvokeData("Winsvc.h", MSDNShortId = "ms684950")]
public struct QUERY_SERVICE_CONFIG
{
/// <summary>The type of service.</summary>
public ServiceTypes dwServiceType;
/// <summary>When to start the service.</summary>
public ServiceStartType dwStartType;
/// <summary>The severity of the error, and action taken, if this service fails to start.</summary>
public ServiceErrorControlType dwErrorControl;
/// <summary>
/// The fully qualified path to the service binary file.
/// <para>
/// The path can also include arguments for an auto-start service.These arguments are passed to the service entry point
/// (typically the main function).
/// </para>
/// </summary>
public string lpBinaryPathName;
/// <summary>
/// The name of the load ordering group to which this service belongs. If the member is NULL or an empty string, the service does
/// not belong to a load ordering group.
/// <para>
/// The startup program uses load ordering groups to load groups of services in a specified order with respect to the other
/// groups.The list of load ordering groups is contained in the following registry value:
/// </para>
/// <para><c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder</c></para>
/// </summary>
public string lpLoadOrderGroup;
/// <summary>
/// A unique tag value for this service in the group specified by the lpLoadOrderGroup parameter. A value of zero indicates that
/// the service has not been assigned a tag. You can use a tag for ordering service startup within a load order group by
/// specifying a tag order vector in the registry located at:
/// <para><c>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList</c></para>
/// <para>
/// Tags are only evaluated for SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER type services that have SERVICE_BOOT_START
/// or SERVICE_SYSTEM_START start types.
/// </para>
/// </summary>
public uint dwTagID;
/// <summary>
/// A pointer to an array of null-separated names of services or load ordering groups that must start before this service. The
/// array is doubly null-terminated. If the pointer is NULL or if it points to an empty string, the service has no dependencies.
/// If a group name is specified, it must be prefixed by the SC_GROUP_IDENTIFIER (defined in WinSvc.h) character to differentiate
/// it from a service name, because services and service groups share the same name space. Dependency on a service means that
/// this service can only run if the service it depends on is running. Dependency on a group means that this service can run if
/// at least one member of the group is running after an attempt to start all members of the group.
/// </summary>
public IntPtr lpDependencies;
/// <summary>
/// If the service type is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, this member is the name of the account that
/// the service process will be logged on as when it runs. This name can be of the form Domain\UserName. If the account belongs
/// to the built-in domain, the name can be of the form .\UserName. The name can also be "LocalSystem" if the process is running
/// under the LocalSystem account.
/// <para>
/// If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this member is the driver object name(that is,
/// \FileSystem\Rdr or \Driver\Xns) which the input and output(I/O) system uses to load the device driver.If this member is NULL,
/// the driver is to be run with a default object name created by the I/O system, based on the service name.
/// </para>
/// </summary>
public string lpServiceStartName;
/// <summary>
/// The display name to be used by service control programs to identify the service. This string has a maximum length of 256
/// characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.
/// <para>This parameter can specify a localized string using the following format:</para>
/// <para>@[Path] DLLName,-StrID</para>
/// <para>The string with identifier StrID is loaded from DLLName; the Path is optional.For more information, see RegLoadMUIString.</para>
/// <para>Windows Server 2003 and Windows XP: Localized strings are not supported until Windows Vista.</para>
/// </summary>
public string lpDisplayName;
/// <summary/>
public IEnumerable<string> Dependencies => lpDependencies.ToStringEnum();
}
/// <summary>
/// Contains information about the lock status of a service control manager database. It is used by the QueryServiceLockStatus function.
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-query_service_lock_statusw typedef struct
// _QUERY_SERVICE_LOCK_STATUSW { DWORD fIsLocked; LPWSTR lpLockOwner; DWORD dwLockDuration; } QUERY_SERVICE_LOCK_STATUSW, *LPQUERY_SERVICE_LOCK_STATUSW;
[PInvokeData("winsvc.h", MSDNShortId = "de9797b7-02b0-43cb-bed3-50b7e8676f36")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct QUERY_SERVICE_LOCK_STATUS
{
/// <summary>
/// The lock status of the database. If this member is nonzero, the database is locked. If it is zero, the database is unlocked.
/// </summary>
[MarshalAs(UnmanagedType.Bool)]
public bool fIsLocked;
/// <summary>The name of the user who acquired the lock.</summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpLockOwner;
/// <summary>The time since the lock was first acquired, in seconds.</summary>
public uint dwLockDuration;
}
/// <summary>
/// <para>Represents an action that the service control manager can perform.</para>
/// </summary>
/// <remarks>
/// <para>
/// This structure is used by the <see cref="ChangeServiceConfig2"/> and <see cref="QueryServiceConfig2"/> functions, in the
/// SERVICE_FAILURE_ACTIONS structure.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_sc_action typedef struct _SC_ACTION { SC_ACTION_TYPE Type;
// DWORD Delay; } SC_ACTION, *LPSC_ACTION;
[PInvokeData("winsvc.h", MSDNShortId = "e2c355a6-affe-46bf-a3e6-f8c420422d46")]
[StructLayout(LayoutKind.Sequential)]
public struct SC_ACTION
{
/// <summary>
/// <para>
/// The action to be performed. This member can be one of the following values from the <c>SC_ACTION_TYPE</c> enumeration type.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SC_ACTION_NONE 0</term>
/// <term>No action.</term>
/// </item>
/// <item>
/// <term>SC_ACTION_REBOOT 2</term>
/// <term>Reboot the computer.</term>
/// </item>
/// <item>
/// <term>SC_ACTION_RESTART 1</term>
/// <term>Restart the service.</term>
/// </item>
/// <item>
/// <term>SC_ACTION_RUN_COMMAND 3</term>
/// <term>Run a command.</term>
/// </item>
/// </list>
/// </summary>
public SC_ACTION_TYPE Type;
/// <summary>
/// <para>The time to wait before performing the specified action, in milliseconds.</para>
/// </summary>
public uint Delay;
}
/// <summary>Provides a handle to a service.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct SC_HANDLE : IHandle
{
private IntPtr handle;
/// <summary>Initializes a new instance of the <see cref="SC_HANDLE"/> struct.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
public SC_HANDLE(IntPtr preexistingHandle) => handle = preexistingHandle;
/// <summary>Returns an invalid handle by instantiating a <see cref="SC_HANDLE"/> object with <see cref="IntPtr.Zero"/>.</summary>
public static SC_HANDLE NULL => new SC_HANDLE(IntPtr.Zero);
/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
public bool IsNull => handle == IntPtr.Zero;
/// <summary>Performs an explicit conversion from <see cref="SC_HANDLE"/> to <see cref="IntPtr"/>.</summary>
/// <param name="h">The handle.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IntPtr(SC_HANDLE h) => h.handle;
/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="SC_HANDLE"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SC_HANDLE(IntPtr h) => new SC_HANDLE(h);
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(SC_HANDLE h1, SC_HANDLE h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(SC_HANDLE h1, SC_HANDLE h2) => h1.Equals(h2);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is SC_HANDLE h ? handle == h.handle : false;
/// <inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
/// <inheritdoc/>
public IntPtr DangerousGetHandle() => handle;
}
/// <summary>Provides a handle to a service lock.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct SC_LOCK : IHandle
{
private IntPtr handle;
/// <summary>Initializes a new instance of the <see cref="SC_LOCK"/> struct.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
public SC_LOCK(IntPtr preexistingHandle) => handle = preexistingHandle;
/// <summary>Returns an invalid handle by instantiating a <see cref="SC_LOCK"/> object with <see cref="IntPtr.Zero"/>.</summary>
public static SC_LOCK NULL => new SC_LOCK(IntPtr.Zero);
/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
public bool IsNull => handle == IntPtr.Zero;
/// <summary>Performs an explicit conversion from <see cref="SC_LOCK"/> to <see cref="IntPtr"/>.</summary>
/// <param name="h">The handle.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IntPtr(SC_LOCK h) => h.handle;
/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="SC_LOCK"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SC_LOCK(IntPtr h) => new SC_LOCK(h);
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(SC_LOCK h1, SC_LOCK h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(SC_LOCK h1, SC_LOCK h2) => h1.Equals(h2);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is SC_LOCK h ? handle == h.handle : false;
/// <inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
/// <inheritdoc/>
public IntPtr DangerousGetHandle() => handle;
}
/// <summary>Contains service control parameters.</summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-service_control_status_reason_paramsa typedef struct
// _SERVICE_CONTROL_STATUS_REASON_PARAMSA { DWORD dwReason; LPSTR pszComment; SERVICE_STATUS_PROCESS ServiceStatus; }
// SERVICE_CONTROL_STATUS_REASON_PARAMSA, *PSERVICE_CONTROL_STATUS_REASON_PARAMSA;
[PInvokeData("winsvc.h", MSDNShortId = "f7213cbb-255f-4ce3-93c9-5537256e078f")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SERVICE_CONTROL_STATUS_REASON_PARAMS
{
/// <summary>
/// <para>
/// The reason for changing the service status to SERVICE_CONTROL_STOP. If the current control code is not SERVICE_CONTROL_STOP,
/// this member is ignored.
/// </para>
/// <para>This member must be set to a combination of one general code, one major reason code, and one minor reason code.</para>
/// <para>The following are the general reason codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_STOP_REASON_FLAG_CUSTOM 0x20000000</term>
/// <term>
/// The reason code is defined by the user. If this flag is not present, the reason code is defined by the system. If this flag
/// is specified with a system reason code, the function call fails. Users can create custom major reason codes in the range
/// SERVICE_STOP_REASON_MAJOR_MIN_CUSTOM (0x00400000) through SERVICE_STOP_REASON_MAJOR_MAX_CUSTOM (0x00ff0000) and minor reason
/// codes in the range SERVICE_STOP_REASON_MINOR_MIN_CUSTOM (0x00000100) through SERVICE_STOP_REASON_MINOR_MAX_CUSTOM (0x0000FFFF).
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_FLAG_PLANNED 0x40000000</term>
/// <term>The service stop was planned.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_FLAG_UNPLANNED 0x10000000</term>
/// <term>The service stop was not planned.</term>
/// </item>
/// </list>
/// <para>The following are the major reason codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_APPLICATION 0x00050000</term>
/// <term>Application issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_HARDWARE 0x00020000</term>
/// <term>Hardware issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_NONE 0x00060000</term>
/// <term>No major reason.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_OPERATINGSYSTEM 0x00030000</term>
/// <term>Operating system issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_OTHER 0x00010000</term>
/// <term>Other issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MAJOR_SOFTWARE 0x00040000</term>
/// <term>Software issue.</term>
/// </item>
/// </list>
/// <para>The following are the minor reason codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_DISK 0x00000008</term>
/// <term>Disk.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_ENVIRONMENT 0x0000000a</term>
/// <term>Environment.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_HARDWARE_DRIVER 0x0000000b</term>
/// <term>Driver.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_HUNG 0x00000006</term>
/// <term>Unresponsive.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_INSTALLATION 0x00000003</term>
/// <term>Installation.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_MAINTENANCE 0x00000002</term>
/// <term>Maintenance.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_MMC 0x00000016</term>
/// <term>MMC issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_NETWORK_CONNECTIVITY 0x00000011</term>
/// <term>Network connectivity.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_NETWORKCARD 0x00000009</term>
/// <term>Network card.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_NONE 0x00060000</term>
/// <term>No minor reason.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_OTHER 0x00000001</term>
/// <term>Other issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_OTHERDRIVER 0x0000000c</term>
/// <term>Other driver event.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_RECONFIG 0x00000005</term>
/// <term>Reconfigure.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SECURITY 0x00000010</term>
/// <term>Security issue.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SECURITYFIX 0x0000000f</term>
/// <term>Security update.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SECURITYFIX_UNINSTALL 0x00000015</term>
/// <term>Security update uninstall.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SERVICEPACK 0x0000000d</term>
/// <term>Service pack.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SERVICEPACK_UNINSTALL 0x00000013</term>
/// <term>Service pack uninstall.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE 0x0000000e</term>
/// <term>Software update.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE_UNINSTALL 0x0000000e</term>
/// <term>Software update uninstall.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_UNSTABLE 0x00000007</term>
/// <term>Unstable.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_UPGRADE 0x00000004</term>
/// <term>Upgrade.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_REASON_MINOR_WMI 0x00000012</term>
/// <term>WMI issue.</term>
/// </item>
/// </list>
/// </summary>
public SERVICE_STOP_REASON dwReason;
/// <summary>
/// An optional string that provides additional information about the service stop. This string is stored in the event log along
/// with the stop reason code. This member must be <c>NULL</c> or a valid string that is less than 128 characters, including the
/// terminating null character.
/// </summary>
public string pszComment;
/// <summary>
/// <para>
/// A pointer to a SERVICE_STATUS_PROCESS structure that receives the latest service status information. The information returned
/// reflects the most recent status that the service reported to the service control manager.
/// </para>
/// <para>
/// The service control manager fills in the structure only when ControlServiceEx returns one of the following error codes:
/// NO_ERROR, ERROR_INVALID_SERVICE_CONTROL, ERROR_SERVICE_CANNOT_ACCEPT_CTRL, or ERROR_SERVICE_NOT_ACTIVE. Otherwise, the
/// structure is not filled in.
/// </para>
/// </summary>
public SERVICE_STATUS_PROCESS serviceStatus;
}
/// <summary>
/// <para>Contains the delayed auto-start setting of an auto-start service.</para>
/// </summary>
/// <remarks>
/// <para>
/// Any service can be marked as a delayed auto-start service; however, this setting has no effect unless the service is an
/// auto-start service. The change takes effect the next time the system is started.
/// </para>
/// <para>
/// The service control manager (SCM) supports delayed auto-start services to improve system performance at boot time without
/// affecting the user experience. The SCM makes a list of delayed auto-start services during boot and starts them one at a time
/// after the delay has passed, honoring dependencies. There is no specific time guarantee as to when the service will be started. To
/// minimize the impact on the user, the ServiceMain thread for the service is started with THREAD_PRIORITY_LOWEST. Threads that are
/// started by the ServiceMain thread should also be run at a low priority. After the service has reported that it has entered the
/// SERVICE_RUNNING state, the priority of the ServiceMain thread is raised to THREAD_PRIORITY_NORMAL.
/// </para>
/// <para>
/// A delayed auto-start service cannot be a member of a load ordering group. It can depend on another auto-start service. An
/// auto-start service can depend on a delayed auto-start service, but this is not generally desirable as the SCM must start the
/// dependent delayed auto-start service at boot.
/// </para>
/// <para>
/// If a delayed auto-start service is demand-started using the StartService function shortly after boot, the system starts the
/// service on demand instead of delaying its start further. If this situation is likely to occur on a regular basis, the service
/// should not be marked as a delayed auto-start service.
/// </para>
/// <para>
/// If a client calls a delayed auto-start service before it is loaded, the call fails. Therefore, clients should be prepared to
/// either retry the call or demand start the service.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_delayed_auto_start_info typedef struct
// _SERVICE_DELAYED_AUTO_START_INFO { BOOL fDelayedAutostart; } SERVICE_DELAYED_AUTO_START_INFO, *LPSERVICE_DELAYED_AUTO_START_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "16117450-eb73-47de-8be7-c7aff3d44c81")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_DELAYED_AUTO_START_INFO
{
/// <summary>
/// <para>
/// If this member is <c>TRUE</c>, the service is started after other auto-start services are started plus a short delay.
/// Otherwise, the service is started during system boot.
/// </para>
/// <para>This setting is ignored unless the service is an auto-start service.</para>
/// </summary>
[MarshalAs(UnmanagedType.Bool)]
public bool fDelayedAutostart;
}
/// <summary>Contains a service description.</summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[PInvokeData("Winsvc.h", MSDNShortId = "ms685156")]
public struct SERVICE_DESCRIPTION
{
/// <summary>
/// The description of the service. If this member is NULL, the description remains unchanged. If this value is an empty string
/// (""), the current description is deleted.
/// <para>The service description must not exceed the size of a registry value of type REG_SZ.</para>
/// <para>This member can specify a localized string using the following format:</para>
/// <para>@[path\]dllname,-strID</para>
/// <para>The string with identifier strID is loaded from dllname; the path is optional. For more information, see RegLoadMUIString.</para>
/// <para><c>Windows Server 2003 and Windows XP:</c> Localized strings are not supported until Windows Vista.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDescription;
}
/// <summary>
/// <para>
/// Represents the action the service controller should take on each failure of a service. A service is considered failed when it
/// terminates without reporting a status of <c>SERVICE_STOPPED</c> to the service controller.
/// </para>
/// <para>To configure additional circumstances under which the failure actions are to be executed, see SERVICE_FAILURE_ACTIONS_FLAG.</para>
/// </summary>
/// <remarks>
/// <para>
/// The service control manager counts the number of times each service has failed since the system booted. The count is reset to 0
/// if the service has not failed for <c>dwResetPeriod</c> seconds. When the service fails for the Nth time, the service controller
/// performs the action specified in element [N-1] of the <c>lpsaActions</c> array. If N is greater than cActions, the service
/// controller repeats the last action in the array.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_failure_actionsa typedef struct
// _SERVICE_FAILURE_ACTIONSA { DWORD dwResetPeriod; LPSTR lpRebootMsg; LPSTR lpCommand; DWORD cActions; SC_ACTION *lpsaActions; }
// SERVICE_FAILURE_ACTIONSA, *LPSERVICE_FAILURE_ACTIONSA;
[PInvokeData("winsvc.h", MSDNShortId = "180ca6d9-f2c3-4ea1-b2c6-319d08ef88ee")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SERVICE_FAILURE_ACTIONS
{
/// <summary>
/// <para>
/// The time after which to reset the failure count to zero if there are no failures, in seconds. Specify <c>INFINITE</c> to
/// indicate that this value should never be reset.
/// </para>
/// </summary>
public uint dwResetPeriod;
/// <summary>
/// <para>
/// The message to be broadcast to server users before rebooting in response to the <c>SC_ACTION_REBOOT</c> service controller action.
/// </para>
/// <para>
/// If this value is <c>NULL</c>, the reboot message is unchanged. If the value is an empty string (""), the reboot message is
/// deleted and no message is broadcast.
/// </para>
/// <para>This member can specify a localized string using the following format:</para>
/// <para>@[path]dllname,-strID</para>
/// <para>The string with identifier strID is loaded from dllname; the path is optional. For more information, see RegLoadMUIString.</para>
/// <para><c>Windows Server 2003 and Windows XP:</c> Localized strings are not supported until Windows Vista.</para>
/// </summary>
public string lpRebootMsg;
/// <summary>
/// <para>
/// The command line of the process for the CreateProcess function to execute in response to the <c>SC_ACTION_RUN_COMMAND</c>
/// service controller action. This process runs under the same account as the service.
/// </para>
/// <para>
/// If this value is <c>NULL</c>, the command is unchanged. If the value is an empty string (""), the command is deleted and no
/// program is run when the service fails.
/// </para>
/// </summary>
public string lpCommand;
/// <summary>
/// <para>The number of elements in the <c>lpsaActions</c> array.</para>
/// <para>If this value is 0, but <c>lpsaActions</c> is not NULL, the reset period and array of failure actions are deleted.</para>
/// </summary>
public uint cActions;
/// <summary>
/// <para>A pointer to an array of SC_ACTION structures.</para>
/// <para>If this value is NULL, the <c>cActions</c> and <c>dwResetPeriod</c> members are ignored.</para>
/// </summary>
public IntPtr lpsaActions;
/// <summary/>
public SC_ACTION[] Actions => lpsaActions.ToArray<SC_ACTION>((int)cActions);
}
/// <summary>
/// <para>Contains the failure actions flag setting of a service. This setting determines when failure actions are to be executed.</para>
/// </summary>
/// <remarks>
/// <para>The change takes effect the next time the system is started.</para>
/// <para>
/// It can be useful to set this flag if your service has common failure paths where is it possible that the service could recover.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_failure_actions_flag typedef struct
// _SERVICE_FAILURE_ACTIONS_FLAG { BOOL fFailureActionsOnNonCrashFailures; } SERVICE_FAILURE_ACTIONS_FLAG, *LPSERVICE_FAILURE_ACTIONS_FLAG;
[PInvokeData("winsvc.h", MSDNShortId = "49736b26-9565-4d56-abcd-1585b692ff12")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_FAILURE_ACTIONS_FLAG
{
/// <summary>
/// <para>
/// If this member is <c>TRUE</c> and the service has configured failure actions, the failure actions are queued if the service
/// process terminates without reporting a status of SERVICE_STOPPED or if it enters the SERVICE_STOPPED state but the
/// <c>dwWin32ExitCode</c> member of the SERVICE_STATUS structure is not ERROR_SUCCESS (0).
/// </para>
/// <para>
/// If this member is <c>FALSE</c> and the service has configured failure actions, the failure actions are queued only if the
/// service terminates without reporting a status of SERVICE_STOPPED.
/// </para>
/// <para>
/// This setting is ignored unless the service has configured failure actions. For information on configuring failure actions,
/// see ChangeServiceConfig2.
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.Bool)]
public bool fFailureActionsOnNonCrashFailures;
}
/// <summary>
/// <para>Indicates a service protection type.</para>
/// </summary>
/// <remarks>
/// <para>
/// This structure is used by the ChangeServiceConfig2 function to specify the protection type of the service, and it is used with
/// QueryServiceConfig2 to retrieve service configuration information for protected services. In order to apply any protection type
/// to a service, the service must be signed with an appropriate certificate.
/// </para>
/// <para>
/// The <c>SERVICE_LAUNCH_PROTECTED_WINDOWS</c> and <c>SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT</c> protection types are reserved for
/// internal Windows use only.
/// </para>
/// <para>
/// The <c>SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT</c> protection type can be used by the anti-malware vendors to launch their
/// anti-malware service as protected. See Protecting Anti-Malware Services for more info.
/// </para>
/// <para>
/// Once the service is launched as protected, other unprotected processes will not be able to call the following APIs on the
/// protected service.
/// </para>
/// <list type="bullet">
/// <item>
/// <term>ChangeServiceConfig</term>
/// </item>
/// <item>
/// <term>ChangeServiceConfig2</term>
/// </item>
/// <item>
/// <term>ControlService</term>
/// </item>
/// <item>
/// <term>ControlServiceEx</term>
/// </item>
/// <item>
/// <term>DeleteService</term>
/// </item>
/// <item>
/// <term>SetServiceObjectSecurity</term>
/// </item>
/// </list>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_launch_protected_info typedef struct
// _SERVICE_LAUNCH_PROTECTED_INFO { DWORD dwLaunchProtected; } SERVICE_LAUNCH_PROTECTED_INFO, *PSERVICE_LAUNCH_PROTECTED_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "ECD44E9F-BE48-4038-94B4-37C8CA5C89F7")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_LAUNCH_PROTECTED_INFO
{
/// <summary>
/// <para>The protection type of the service. This member can be one of the following values:</para>
/// <para>SERVICE_LAUNCH_PROTECTED_NONE (0)</para>
/// <para>SERVICE_LAUNCH_PROTECTED_WINDOWS (1)</para>
/// <para>SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT (2)</para>
/// <para>SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT (3)</para>
/// </summary>
public uint dwLaunchProtected;
}
/// <summary>Represents service status notification information. It is used by the NotifyServiceStatusChange function.</summary>
/// <remarks>
/// <para>The callback function is declared as follows:</para>
/// <para>The callback function receives a pointer to the <c>SERVICE_NOTIFY</c> structure provided by the caller.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_notify_2a typedef struct _SERVICE_NOTIFY_2A { DWORD
// dwVersion; PFN_SC_NOTIFY_CALLBACK pfnNotifyCallback; PVOID pContext; DWORD dwNotificationStatus; SERVICE_STATUS_PROCESS
// ServiceStatus; DWORD dwNotificationTriggered; LPSTR pszServiceNames; } SERVICE_NOTIFY_2A, *PSERVICE_NOTIFY_2A;
[PInvokeData("winsvc.h", MSDNShortId = "52ede72e-eb50-48e2-b5c1-125816f6fe57")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SERVICE_NOTIFY_2
{
/// <summary>The structure version. This member must be <c>SERVICE_NOTIFY_STATUS_CHANGE</c> (2).</summary>
public uint dwVersion;
/// <summary>A pointer to the callback function. For more information, see Remarks.</summary>
public IntPtr pfnNotifyCallback;
/// <summary>Any user-defined data to be passed to the callback function.</summary>
public IntPtr pContext;
/// <summary>
/// A value that indicates the notification status. If this member is <c>ERROR_SUCCESS</c>, the notification has succeeded and
/// the <c>ServiceStatus</c> member contains valid information. If this member is <c>ERROR_SERVICE_MARKED_FOR_DELETE</c>, the
/// service has been marked for deletion and the service handle used by NotifyServiceStatusChange must be closed.
/// </summary>
public Win32Error dwNotificationStatus;
/// <summary>
/// A SERVICE_STATUS_PROCESS structure that contains the service status information. This member is only valid if
/// <c>dwNotificationStatus</c> is <c>ERROR_SUCCESS</c>.
/// </summary>
public SERVICE_STATUS_PROCESS ServiceStatus;
/// <summary>
/// If <c>dwNotificationStatus</c> is <c>ERROR_SUCCESS</c>, this member contains a bitmask of the notifications that triggered
/// this call to the callback function.
/// </summary>
public SERVICE_NOTIFY_FLAGS dwNotificationTriggered;
/// <summary>
/// <para>
/// If <c>dwNotificationStatus</c> is <c>ERROR_SUCCESS</c> and the notification is <c>SERVICE_NOTIFY_CREATED</c> or
/// <c>SERVICE_NOTIFY_DELETED</c>, this member is valid and it is a <c>MULTI_SZ</c> string that contains one or more service
/// names. The names of the created services will have a '/' prefix so you can distinguish them from the names of the deleted services.
/// </para>
/// <para>If this member is valid, the notification callback function must free the string using the LocalFree function.</para>
/// </summary>
public StrPtrAuto pszServiceNames;
}
/// <summary>
/// <para>Represents the preferred node on which to run a service.</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_preferred_node_info typedef struct
// _SERVICE_PREFERRED_NODE_INFO { USHORT usPreferredNode; BOOLEAN fDelete; } SERVICE_PREFERRED_NODE_INFO, *LPSERVICE_PREFERRED_NODE_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "aa16cc56-0a95-47e0-9390-c219b83aeeb4")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_PREFERRED_NODE_INFO
{
/// <summary>
/// <para>The node number of the preferred node.</para>
/// </summary>
public ushort usPreferredNode;
/// <summary>
/// <para>If this member is TRUE, the preferred node setting is deleted.</para>
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public bool fDelete;
}
/// <summary>
/// <para>Contains preshutdown settings.</para>
/// </summary>
/// <remarks>
/// <para>The default preshutdown time-out value is 180,000 milliseconds (three minutes).</para>
/// <para>
/// After the service control manager sends the SERVICE_CONTROL_PRESHUTDOWN notification to the HandlerEx function, it waits for one
/// of the following to occur before proceeding with other shutdown actions: the specified time elapses or the service enters the
/// SERVICE_STOPPED state. The service can continue to update its status for as long as it is in the SERVICE_STOP_PENDING state.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_preshutdown_info typedef struct
// _SERVICE_PRESHUTDOWN_INFO { DWORD dwPreshutdownTimeout; } SERVICE_PRESHUTDOWN_INFO, *LPSERVICE_PRESHUTDOWN_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "b9d2362c-e4d7-4072-88c2-5294b3838095")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_PRESHUTDOWN_INFO
{
/// <summary>
/// <para>The time-out value, in milliseconds.</para>
/// </summary>
public uint dwPreshutdownTimeout;
}
/// <summary>
/// <para>Represents the required privileges for a service.</para>
/// </summary>
/// <remarks>
/// <para>
/// The change in required privileges takes effect the next time the service is started. The SCM determines whether the service can
/// support the specified privileges when it attempts to start the service.
/// </para>
/// <para>It is best to analyze your service and use the minimum set of privileges required.</para>
/// <para>
/// If you do not set the required privileges, the SCM uses all the privileges assigned by default to the process token. If you
/// specify privileges for a service, the SCM will remove the privileges that are not required from the process token when the
/// process starts. If multiple services share a process, the SCM computes the union of privileges required by all services in the process.
/// </para>
/// <para>
/// For compatibility, the SeChangeNotifyPrivilege privilege is never removed from a process token, even if no service in the process
/// has requested the privilege. Therefore, a service need not explicitly specify this privilege.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_required_privileges_infoa typedef struct
// _SERVICE_REQUIRED_PRIVILEGES_INFOA { LPSTR pmszRequiredPrivileges; } SERVICE_REQUIRED_PRIVILEGES_INFOA, *LPSERVICE_REQUIRED_PRIVILEGES_INFOA;
[PInvokeData("winsvc.h", MSDNShortId = "15a2e042-cfd5-443e-a3b8-822f48eb9654")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SERVICE_REQUIRED_PRIVILEGES_INFO
{
/// <summary>
/// <para>A multi-string that specifies the privileges. For a list of possible values, see Privilege Constants.</para>
/// <para>
/// A multi-string is a sequence of null-terminated strings, terminated by an empty string (\0). The following is an example: .
/// </para>
/// </summary>
public string pmszRequiredPrivileges;
}
/// <summary>
/// <para>Represents a service security identifier (SID).</para>
/// </summary>
/// <remarks>
/// <para>The change takes effect the next time the system is started.</para>
/// <para>The SCM adds the specified service SIDs to the process token, plus the following additional SIDs.</para>
/// <list type="table">
/// <listheader>
/// <term>SID</term>
/// <term>Attributes</term>
/// </listheader>
/// <item>
/// <term>Logon SID</term>
/// <term>SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID | SE_GROUP_MANDATORY</term>
/// </item>
/// <item>
/// <term>Local SID</term>
/// <term>SE_GROUP_MANDATORY | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT</term>
/// </item>
/// </list>
/// <para>
/// This enables developers to control access to the objects a service uses, instead of relying on the use of the LocalSystem account
/// to obtain access.
/// </para>
/// <para>
/// Use the LookupAccountName and LookupAccountSid functions to convert between a service name and a service SID. The account name is
/// of the following form:
/// </para>
/// <para>NT SERVICE&lt;i&gt;SvcName</para>
/// <para>Note that NT SERVICE is the domain name.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_sid_info typedef struct _SERVICE_SID_INFO { DWORD
// dwServiceSidType; } SERVICE_SID_INFO, *LPSERVICE_SID_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "cb1a32bd-aafb-4e41-8d6f-673c3d747f14")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_SID_INFO
{
/// <summary>
/// <para>The service SID type.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_SID_TYPE_NONE 0x00000000</term>
/// <term>Use this type to reduce application compatibility issues.</term>
/// </item>
/// <item>
/// <term>SERVICE_SID_TYPE_RESTRICTED 0x00000003</term>
/// <term>
/// This type includes SERVICE_SID_TYPE_UNRESTRICTED. The service SID is also added to the restricted SID list of the process
/// token. Three additional SIDs are also added to the restricted SID list: One ACE that allows GENERIC_ALL access for the
/// service logon SID is also added to the service process token object. If there are multiple services hosted in the same
/// process and one service has SERVICE_SID_TYPE_RESTRICTED, all services must have SERVICE_SID_TYPE_RESTRICTED.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_SID_TYPE_UNRESTRICTED 0x00000001</term>
/// <term>
/// When the service process is created, the service SID is added to the service process token with the following attributes:
/// SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_OWNER.
/// </term>
/// </item>
/// </list>
/// </summary>
public uint dwServiceSidType;
}
/// <summary/>
[StructLayout(LayoutKind.Sequential)]
public readonly struct SERVICE_START_REASON
{
/// <summary/>
public readonly ServiceStartReason dwReason;
}
/// <summary>
/// <para>
/// Contains status information for a service. The ControlService, EnumDependentServices, EnumServicesStatus, and QueryServiceStatus
/// functions use this structure. A service uses this structure in the SetServiceStatus function to report its current status to the
/// service control manager.
/// </para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_status typedef struct _SERVICE_STATUS { DWORD
// dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD
// dwCheckPoint; DWORD dwWaitHint; } SERVICE_STATUS, *LPSERVICE_STATUS;
[PInvokeData("winsvc.h", MSDNShortId = "d268609b-d442-4d0f-9d49-ed23fee84961")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_STATUS
{
/// <summary>
/// <para>The type of service. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_FILE_SYSTEM_DRIVER 0x00000002</term>
/// <term>The service is a file system driver.</term>
/// </item>
/// <item>
/// <term>SERVICE_KERNEL_DRIVER 0x00000001</term>
/// <term>The service is a device driver.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_OWN_PROCESS 0x00000010</term>
/// <term>The service runs in its own process.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_SHARE_PROCESS 0x00000020</term>
/// <term>The service shares a process with other services.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_OWN_PROCESS 0x00000050</term>
/// <term>The service runs in its own process under the logged-on user account.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_SHARE_PROCESS 0x00000060</term>
/// <term>The service shares a process with one or more other services that run under the logged-on user account.</term>
/// </item>
/// </list>
/// <para>
/// If the service type is either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the
/// context of the LocalSystem account, the following type may also be specified.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_INTERACTIVE_PROCESS 0x00000100</term>
/// <term>The service can interact with the desktop. For more information, see Interactive Services.</term>
/// </item>
/// </list>
/// </summary>
public ServiceTypes dwServiceType;
/// <summary>
/// <para>The current state of the service. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTINUE_PENDING 0x00000005</term>
/// <term>The service continue is pending.</term>
/// </item>
/// <item>
/// <term>SERVICE_PAUSE_PENDING 0x00000006</term>
/// <term>The service pause is pending.</term>
/// </item>
/// <item>
/// <term>SERVICE_PAUSED 0x00000007</term>
/// <term>The service is paused.</term>
/// </item>
/// <item>
/// <term>SERVICE_RUNNING 0x00000004</term>
/// <term>The service is running.</term>
/// </item>
/// <item>
/// <term>SERVICE_START_PENDING 0x00000002</term>
/// <term>The service is starting.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_PENDING 0x00000003</term>
/// <term>The service is stopping.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOPPED 0x00000001</term>
/// <term>The service is not running.</term>
/// </item>
/// </list>
/// </summary>
public ServiceState dwCurrentState;
/// <summary>
/// <para>
/// The control codes the service accepts and processes in its handler function (see Handler and HandlerEx). A user interface
/// process can control a service by specifying a control command in the ControlService or ControlServiceEx function. By default,
/// all services accept the <c>SERVICE_CONTROL_INTERROGATE</c> value.
/// </para>
/// <para>
/// To accept the <c>SERVICE_CONTROL_DEVICEEVENT</c> value, the service must register to receive device events by using the
/// RegisterDeviceNotification function.
/// </para>
/// <para>The following are the control codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ACCEPT_NETBINDCHANGE 0x00000010</term>
/// <term>
/// The service is a network component that can accept changes in its binding without being stopped and restarted. This control
/// code allows the service to receive SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE,
/// and SERVICE_CONTROL_NETBINDDISABLE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PARAMCHANGE 0x00000008</term>
/// <term>
/// The service can reread its startup parameters without being stopped and restarted. This control code allows the service to
/// receive SERVICE_CONTROL_PARAMCHANGE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PAUSE_CONTINUE 0x00000002</term>
/// <term>
/// The service can be paused and continued. This control code allows the service to receive SERVICE_CONTROL_PAUSE and
/// SERVICE_CONTROL_CONTINUE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PRESHUTDOWN 0x00000100</term>
/// <term>
/// The service can perform preshutdown tasks. This control code enables the service to receive SERVICE_CONTROL_PRESHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// Windows Server 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_SHUTDOWN 0x00000004</term>
/// <term>
/// The service is notified when system shutdown occurs. This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_STOP 0x00000001</term>
/// <term>The service can be stopped. This control code allows the service to receive SERVICE_CONTROL_STOP notifications.</term>
/// </item>
/// </list>
/// <para>
/// This member can also contain the following extended control codes, which are supported only by HandlerEx. (Note that these
/// control codes cannot be sent by ControlService or ControlServiceEx.)
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ACCEPT_HARDWAREPROFILECHANGE 0x00000020</term>
/// <term>
/// The service is notified when the computer's hardware profile has changed. This enables the system to send
/// SERVICE_CONTROL_HARDWAREPROFILECHANGE notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_POWEREVENT 0x00000040</term>
/// <term>
/// The service is notified when the computer's power status has changed. This enables the system to send
/// SERVICE_CONTROL_POWEREVENT notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_SESSIONCHANGE 0x00000080</term>
/// <term>
/// The service is notified when the computer's session status has changed. This enables the system to send
/// SERVICE_CONTROL_SESSIONCHANGE notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_TIMECHANGE 0x00000200</term>
/// <term>
/// The service is notified when the system time has changed. This enables the system to send SERVICE_CONTROL_TIMECHANGE
/// notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is
/// not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_TRIGGEREVENT 0x00000400</term>
/// <term>
/// The service is notified when an event for which the service has registered occurs. This enables the system to send
/// SERVICE_CONTROL_TRIGGEREVENT notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and
/// Windows XP: This control code is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_USERMODEREBOOT 0x00000800</term>
/// <term>
/// The services is notified when the user initiates a reboot. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows
/// Vista, Windows Server 2003 and Windows XP: This control code is not supported.
/// </term>
/// </item>
/// </list>
/// </summary>
public ServiceAcceptedControlCodes dwControlsAccepted;
/// <summary>
/// <para>
/// The error code the service uses to report an error that occurs when it is starting or stopping. To return an error code
/// specific to the service, the service must set this value to <c>ERROR_SERVICE_SPECIFIC_ERROR</c> to indicate that the
/// <c>dwServiceSpecificExitCode</c> member contains the error code. The service should set this value to <c>NO_ERROR</c> when it
/// is running and on normal termination.
/// </para>
/// </summary>
public Win32Error dwWin32ExitCode;
/// <summary>
/// <para>
/// A service-specific error code that the service returns when an error occurs while the service is starting or stopping. This
/// value is ignored unless the <c>dwWin32ExitCode</c> member is set to <c>ERROR_SERVICE_SPECIFIC_ERROR</c>.
/// </para>
/// </summary>
public Win32Error dwServiceSpecificExitCode;
/// <summary>
/// <para>
/// The check-point value the service increments periodically to report its progress during a lengthy start, stop, pause, or
/// continue operation. For example, the service should increment this value as it completes each step of its initialization when
/// it is starting up. The user interface program that invoked the operation on the service uses this value to track the progress
/// of the service during a lengthy operation. This value is not valid and should be zero when the service does not have a start,
/// stop, pause, or continue operation pending.
/// </para>
/// </summary>
public uint dwCheckPoint;
/// <summary>
/// <para>
/// The estimated time required for a pending start, stop, pause, or continue operation, in milliseconds. Before the specified
/// amount of time has elapsed, the service should make its next call to the SetServiceStatus function with either an incremented
/// <c>dwCheckPoint</c> value or a change in <c>dwCurrentState</c>. If the amount of time specified by <c>dwWaitHint</c> passes,
/// and <c>dwCheckPoint</c> has not been incremented or <c>dwCurrentState</c> has not changed, the service control manager or
/// service control program can assume that an error has occurred and the service should be stopped. However, if the service
/// shares a process with other services, the service control manager cannot terminate the service application because it would
/// have to terminate the other services sharing the process as well.
/// </para>
/// </summary>
public uint dwWaitHint;
}
/// <summary>Provides a handle to a service status handle.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_STATUS_HANDLE : IHandle
{
private IntPtr handle;
/// <summary>Initializes a new instance of the <see cref="SERVICE_STATUS_HANDLE "/> struct.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
public SERVICE_STATUS_HANDLE(IntPtr preexistingHandle) => handle = preexistingHandle;
/// <summary>Returns an invalid handle by instantiating a <see cref="SERVICE_STATUS_HANDLE "/> object with <see cref="IntPtr.Zero"/>.</summary>
public static SERVICE_STATUS_HANDLE NULL => new SERVICE_STATUS_HANDLE(IntPtr.Zero);
/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
public bool IsNull => handle == IntPtr.Zero;
/// <summary>Performs an explicit conversion from <see cref="SERVICE_STATUS_HANDLE "/> to <see cref="IntPtr"/>.</summary>
/// <param name="h">The handle.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IntPtr(SERVICE_STATUS_HANDLE h) => h.handle;
/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="SERVICE_STATUS_HANDLE "/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SERVICE_STATUS_HANDLE(IntPtr h) => new SERVICE_STATUS_HANDLE(h);
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(SERVICE_STATUS_HANDLE h1, SERVICE_STATUS_HANDLE h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(SERVICE_STATUS_HANDLE h1, SERVICE_STATUS_HANDLE h2) => h1.Equals(h2);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is SERVICE_STATUS_HANDLE h ? handle == h.handle : false;
/// <inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
/// <inheritdoc/>
public IntPtr DangerousGetHandle() => handle;
}
/// <summary>
/// <para>
/// Contains status information for a service. The ControlService, EnumDependentServices, EnumServicesStatus, and QueryServiceStatus
/// functions use this structure. A service uses this structure in the SetServiceStatus function to report its current status to the
/// service control manager.
/// </para>
/// </summary>
// https://docs.microsoft.com/en-gb/windows/desktop/api/winsvc/ns-winsvc-_service_status_process typedef struct
// _SERVICE_STATUS_PROCESS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD
// dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; DWORD dwProcessId; DWORD dwServiceFlags; }
// SERVICE_STATUS_PROCESS, * LPSERVICE_STATUS_PROCESS;
[PInvokeData("winsvc.h")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_STATUS_PROCESS
{
/// <summary>
/// <para>The type of service. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_FILE_SYSTEM_DRIVER 0x00000002</term>
/// <term>The service is a file system driver.</term>
/// </item>
/// <item>
/// <term>SERVICE_KERNEL_DRIVER 0x00000001</term>
/// <term>The service is a device driver.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_OWN_PROCESS 0x00000010</term>
/// <term>The service runs in its own process.</term>
/// </item>
/// <item>
/// <term>SERVICE_WIN32_SHARE_PROCESS 0x00000020</term>
/// <term>The service shares a process with other services.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_OWN_PROCESS 0x00000050</term>
/// <term>The service runs in its own process under the logged-on user account.</term>
/// </item>
/// <item>
/// <term>SERVICE_USER_SHARE_PROCESS 0x00000060</term>
/// <term>The service shares a process with one or more other services that run under the logged-on user account.</term>
/// </item>
/// </list>
/// <para>
/// If the service type is either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the
/// context of the LocalSystem account, the following type may also be specified.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_INTERACTIVE_PROCESS 0x00000100</term>
/// <term>The service can interact with the desktop. For more information, see Interactive Services.</term>
/// </item>
/// </list>
/// </summary>
public ServiceTypes dwServiceType;
/// <summary>
/// <para>The current state of the service. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_CONTINUE_PENDING 0x00000005</term>
/// <term>The service continue is pending.</term>
/// </item>
/// <item>
/// <term>SERVICE_PAUSE_PENDING 0x00000006</term>
/// <term>The service pause is pending.</term>
/// </item>
/// <item>
/// <term>SERVICE_PAUSED 0x00000007</term>
/// <term>The service is paused.</term>
/// </item>
/// <item>
/// <term>SERVICE_RUNNING 0x00000004</term>
/// <term>The service is running.</term>
/// </item>
/// <item>
/// <term>SERVICE_START_PENDING 0x00000002</term>
/// <term>The service is starting.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOP_PENDING 0x00000003</term>
/// <term>The service is stopping.</term>
/// </item>
/// <item>
/// <term>SERVICE_STOPPED 0x00000001</term>
/// <term>The service is not running.</term>
/// </item>
/// </list>
/// </summary>
public ServiceState dwCurrentState;
/// <summary>
/// <para>
/// The control codes the service accepts and processes in its handler function (see Handler and HandlerEx). A user interface
/// process can control a service by specifying a control command in the ControlService or ControlServiceEx function. By default,
/// all services accept the <c>SERVICE_CONTROL_INTERROGATE</c> value.
/// </para>
/// <para>
/// To accept the <c>SERVICE_CONTROL_DEVICEEVENT</c> value, the service must register to receive device events by using the
/// RegisterDeviceNotification function.
/// </para>
/// <para>The following are the control codes.</para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ACCEPT_NETBINDCHANGE 0x00000010</term>
/// <term>
/// The service is a network component that can accept changes in its binding without being stopped and restarted. This control
/// code allows the service to receive SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE,
/// and SERVICE_CONTROL_NETBINDDISABLE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PARAMCHANGE 0x00000008</term>
/// <term>
/// The service can reread its startup parameters without being stopped and restarted. This control code allows the service to
/// receive SERVICE_CONTROL_PARAMCHANGE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PAUSE_CONTINUE 0x00000002</term>
/// <term>
/// The service can be paused and continued. This control code allows the service to receive SERVICE_CONTROL_PAUSE and
/// SERVICE_CONTROL_CONTINUE notifications.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_PRESHUTDOWN 0x00000100</term>
/// <term>
/// The service can perform preshutdown tasks. This control code enables the service to receive SERVICE_CONTROL_PRESHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// Windows Server 2003 and Windows XP: This value is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_SHUTDOWN 0x00000004</term>
/// <term>
/// The service is notified when system shutdown occurs. This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN
/// notifications. Note that ControlService and ControlServiceEx cannot send this notification; only the system can send it.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_STOP 0x00000001</term>
/// <term>The service can be stopped. This control code allows the service to receive SERVICE_CONTROL_STOP notifications.</term>
/// </item>
/// </list>
/// <para>
/// This member can also contain the following extended control codes, which are supported only by HandlerEx. (Note that these
/// control codes cannot be sent by ControlService or ControlServiceEx.)
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Control code</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_ACCEPT_HARDWAREPROFILECHANGE 0x00000020</term>
/// <term>
/// The service is notified when the computer's hardware profile has changed. This enables the system to send
/// SERVICE_CONTROL_HARDWAREPROFILECHANGE notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_POWEREVENT 0x00000040</term>
/// <term>
/// The service is notified when the computer's power status has changed. This enables the system to send
/// SERVICE_CONTROL_POWEREVENT notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_SESSIONCHANGE 0x00000080</term>
/// <term>
/// The service is notified when the computer's session status has changed. This enables the system to send
/// SERVICE_CONTROL_SESSIONCHANGE notifications to the service.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_TIMECHANGE 0x00000200</term>
/// <term>
/// The service is notified when the system time has changed. This enables the system to send SERVICE_CONTROL_TIMECHANGE
/// notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This control code is
/// not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_TRIGGEREVENT 0x00000400</term>
/// <term>
/// The service is notified when an event for which the service has registered occurs. This enables the system to send
/// SERVICE_CONTROL_TRIGGEREVENT notifications to the service. Windows Server 2008, Windows Vista, Windows Server 2003 and
/// Windows XP: This control code is not supported.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_ACCEPT_USERMODEREBOOT 0x00000800</term>
/// <term>
/// The services is notified when the user initiates a reboot. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows
/// Vista, Windows Server 2003 and Windows XP: This control code is not supported.
/// </term>
/// </item>
/// </list>
/// </summary>
public ServiceAcceptedControlCodes dwControlsAccepted;
/// <summary>
/// <para>
/// The error code the service uses to report an error that occurs when it is starting or stopping. To return an error code
/// specific to the service, the service must set this value to <c>ERROR_SERVICE_SPECIFIC_ERROR</c> to indicate that the
/// <c>dwServiceSpecificExitCode</c> member contains the error code. The service should set this value to <c>NO_ERROR</c> when it
/// is running and on normal termination.
/// </para>
/// </summary>
public Win32Error dwWin32ExitCode;
/// <summary>
/// <para>
/// A service-specific error code that the service returns when an error occurs while the service is starting or stopping. This
/// value is ignored unless the <c>dwWin32ExitCode</c> member is set to <c>ERROR_SERVICE_SPECIFIC_ERROR</c>.
/// </para>
/// </summary>
public uint dwServiceSpecificExitCode;
/// <summary>
/// <para>
/// The check-point value the service increments periodically to report its progress during a lengthy start, stop, pause, or
/// continue operation. For example, the service should increment this value as it completes each step of its initialization when
/// it is starting up. The user interface program that invoked the operation on the service uses this value to track the progress
/// of the service during a lengthy operation. This value is not valid and should be zero when the service does not have a start,
/// stop, pause, or continue operation pending.
/// </para>
/// </summary>
public uint dwCheckPoint;
/// <summary>
/// <para>
/// The estimated time required for a pending start, stop, pause, or continue operation, in milliseconds. Before the specified
/// amount of time has elapsed, the service should make its next call to the SetServiceStatus function with either an incremented
/// <c>dwCheckPoint</c> value or a change in <c>dwCurrentState</c>. If the amount of time specified by <c>dwWaitHint</c> passes,
/// and <c>dwCheckPoint</c> has not been incremented or <c>dwCurrentState</c> has not changed, the service control manager or
/// service control program can assume that an error has occurred and the service should be stopped. However, if the service
/// shares a process with other services, the service control manager cannot terminate the service application because it would
/// have to terminate the other services sharing the process as well.
/// </para>
/// </summary>
public uint dwWaitHint;
/// <summary>The process identifier of the service.</summary>
public uint dwProcessId;
/// <summary>
/// This member can be one of the following values. 0 = The service is running in a process that is not a system process, or it
/// is not running. If the service is running in a process that is not a system process, dwProcessId is nonzero.If the service is
/// not running, dwProcessId is zero. 1 = SERVICE_RUNS_IN_SYSTEM_PROCESS The service runs in a system process that must always be running.
/// </summary>
public uint dwServiceFlags;
}
/// <summary>
/// Specifies the ServiceMain function for a service that can run in the calling process. It is used by the
/// StartServiceCtrlDispatcher function.
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_table_entrya typedef struct _SERVICE_TABLE_ENTRYA {
// LPSTR lpServiceName; LPSERVICE_MAIN_FUNCTIONA lpServiceProc; } SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
[PInvokeData("winsvc.h", MSDNShortId = "dd40c4f0-cbbe-429f-91c0-3ba141dab702")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SERVICE_TABLE_ENTRY
{
/// <summary>
/// <para>The name of a service to be run in this service process.</para>
/// <para>
/// If the service is installed with the SERVICE_WIN32_OWN_PROCESS service type, this member is ignored, but cannot be NULL. This
/// member can be an empty string ("").
/// </para>
/// <para>
/// If the service is installed with the SERVICE_WIN32_SHARE_PROCESS service type, this member specifies the name of the service
/// that uses the ServiceMain function pointed to by the <c>lpServiceProc</c> member.
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpServiceName;
/// <summary>A pointer to a ServiceMain function.</summary>
[MarshalAs(UnmanagedType.FunctionPtr)]
public ServiceMain lpServiceProc;
/// <summary>Initializes a new instance of the <see cref="SERVICE_TABLE_ENTRY"/> struct.</summary>
/// <param name="serviceName">Name of the service.</param>
/// <param name="serviceProc">The service proc.</param>
public SERVICE_TABLE_ENTRY(string serviceName, ServiceMain serviceProc)
{
lpServiceName = serviceName;
lpServiceProc = serviceProc;
}
}
/// <summary>
/// <para>Represents a service trigger event. This structure is used by the SERVICE_TRIGGER_INFO structure.</para>
/// </summary>
/// <remarks>
/// <para>
/// On a system that is joined to a domain, security policy settings may prevent the BFE service and its dependent services from
/// being stopped or cause them to restart automatically. In this case, it is necessary to disable the services and then re-enable
/// them after the event is registered. To do this programmatically, store each service's original start type, change the service
/// start type to SERVICE_DISABLED, register the event, and then restore the service's original start type. For information about
/// changing a service's start type, see ChangeServiceConfig.
/// </para>
/// <para>
/// To disable the services using the SC command-line tool, use the command <c>sc config bfe start= disabled</c> to disable the BFE
/// service and its dependent services, then use the command <c>net stop bfe /Y</c> to stop them. To re-enable the services, use the
/// command <c>sc config bfe start= auto</c>. For more information about the SC command-line tool, see Controlling a Service Using SC.
/// </para>
/// <para>
/// If it is not possible to disable the services, it may be necessary to restart the system after installing the service that is
/// registering the event. In this case, do not disable the BFE service and its dependent services before restarting the system,
/// because the system may not work correctly if these services remain disabled.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_trigger typedef struct _SERVICE_TRIGGER { DWORD
// dwTriggerType; DWORD dwAction; GUID *pTriggerSubtype; DWORD cDataItems; PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM pDataItems; }
// SERVICE_TRIGGER, *PSERVICE_TRIGGER;
[PInvokeData("winsvc.h", MSDNShortId = "a57aa702-40a2-4880-80db-6c4f43c3e7ea")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_TRIGGER
{
/// <summary>
/// <para>The trigger event type. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_CUSTOM 20</term>
/// <term>
/// The event is a custom event generated by an Event Tracing for Windows (ETW) provider. This trigger event can be used to start
/// or stop a service. The pTriggerSubtype member specifies the event provider's GUID. The pDataItems member specifies
/// trigger-specific data defined by the provider.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL 1</term>
/// <term>
/// The event is triggered when a device of the specified device interface class arrives or is present when the system starts.
/// This trigger event is commonly used to start a service. The pTriggerSubtype member specifies the device interface class GUID.
/// These GUIDs are defined in device-specific header files provided with the Windows Driver Kit (WDK). The pDataItems member
/// specifies one or more hardware ID and compatible ID strings for the device interface class. Strings must be Unicode. If more
/// than one string is specified, the event is triggered if any one of the strings match. For example, the Wpdbusenum service is
/// started when a device of device interface class GUID_DEVINTERFACE_DISK {53f56307-b6bf-11d0-94f2-00a0c91efb8b} and a hardware
/// ID string of arrives.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_DOMAIN_JOIN 3</term>
/// <term>
/// The event is triggered when the computer joins or leaves a domain. This trigger event can be used to start or stop a service.
/// The pTriggerSubtype member specifies DOMAIN_JOIN_GUID or DOMAIN_LEAVE_GUID. The pDataItems member is not used.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT 4</term>
/// <term>
/// The event is triggered when a firewall port is opened or approximately 60 seconds after the firewall port is closed. This
/// trigger event can be used to start or stop a service. The pTriggerSubtype member specifies FIREWALL_PORT_OPEN_GUID or
/// FIREWALL_PORT_CLOSE_GUID. The pDataItems member specifies the port, the protocol, and optionally the executable path and user
/// information (SID string or name) of the service listening on the event. The "RPC" token can be used in place of the port to
/// specify any listening socket used by RPC. The "system" token can be used in place of the executable path to specify ports
/// created by and listened on by the Windows kernel. The event is triggered only if all strings match. For example, if MyService
/// hosted inside MyServiceProcess.exe is to be trigger-started when port UDP 5001 opens, the trigger-specific data would be the
/// Unicode representation of .
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_GROUP_POLICY 5</term>
/// <term>
/// The event is triggered when a machine policy or user policy change occurs. This trigger event is commonly used to start a
/// service. The pTriggerSubtype member specifies MACHINE_POLICY_PRESENT_GUID or USER_POLICY_PRESENT_GUID. The pDataItems member
/// is not used.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY 2</term>
/// <term>
/// The event is triggered when the first IP address on the TCP/IP networking stack becomes available or the last IP address on
/// the stack becomes unavailable. This trigger event can be used to start or stop a service. The pTriggerSubtype member
/// specifies NETWORK_MANAGER_FIRST_IP_ADDRESS_ARRIVAL_GUID or NETWORK_MANAGER_LAST_IP_ADDRESS_REMOVAL_GUID. The pDataItems
/// member is not used.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT 6</term>
/// <term>
/// The event is triggered when a packet or request arrives on a particular network protocol. This request is commonly used to
/// start a service that has stopped itself after an idle time-out when there is no work to do. Windows 7 and Windows Server 2008
/// R2: This trigger type is not supported until Windows 8 and Windows Server 2012. The pTriggerSubtype member specifies one of
/// the following values: RPC_INTERFACE_EVENT_GUID or NAMED_PIPE_EVENT_GUID. The pDataItems member specifies an endpoint or
/// interface GUID. The string must be Unicode. The event triggers if the string is an exact match. The dwAction member must be SERVICE_TRIGGER_ACTION_SERVICE_START.
/// </term>
/// </item>
/// </list>
/// </summary>
public ServiceTriggerType dwTriggerType;
/// <summary>
/// <para>The action to take when the specified trigger event occurs. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_TRIGGER_ACTION_SERVICE_START 1</term>
/// <term>Start the service when the specified trigger event occurs.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_ACTION_SERVICE_STOP 2</term>
/// <term>Stop the service when the specified trigger event occurs.</term>
/// </item>
/// </list>
/// </summary>
public ServiceTriggerAction dwAction;
/// <summary>
/// <para>
/// Points to a GUID that identifies the trigger event subtype. The value of this member depends on the value of the
/// <c>dwTriggerType</c> member.
/// </para>
/// <para>
/// If <c>dwTriggerType</c> is SERVICE_TRIGGER_TYPE_CUSTOM, <c>pTriggerSubtype</c> is the GUID that identifies the custom event provider.
/// </para>
/// <para>
/// If <c>dwTriggerType</c> is SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL, <c>pTriggerSubtype</c> is the GUID that identifies
/// the device interface class.
/// </para>
/// <para>If <c>dwTriggerType</c> is SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, <c>pTriggerSubtype</c> is one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>NAMED_PIPE_EVENT_GUID 1F81D131-3FAC-4537-9E0C-7E7B0C2F4B55</term>
/// <term>
/// The event is triggered when a request is made to open the named pipe specified by pDataItems. The dwTriggerType member must
/// be SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT. The dwAction member must be SERVICE_TRIGGER_ACTION_SERVICE_START.
/// </term>
/// </item>
/// <item>
/// <term>RPC_INTERFACE_EVENT_GUID BC90D167-9470-4139-A9BA-BE0BBBF5B74D</term>
/// <term>
/// The event is triggered when an endpoint resolution request arrives for the RPC interface GUID specified by pDataItems. The
/// dwTriggerType member must be SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT. The dwAction member must be SERVICE_TRIGGER_ACTION_SERVICE_START.
/// </term>
/// </item>
/// </list>
/// <para>For other trigger event types, <c>pTriggerSubType</c> can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>DOMAIN_JOIN_GUID 1ce20aba-9851-4421-9430-1ddeb766e809</term>
/// <term>The event is triggered when the computer joins a domain. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_DOMAIN_JOIN.</term>
/// </item>
/// <item>
/// <term>DOMAIN_LEAVE_GUID ddaf516e-58c2-4866-9574-c3b615d42ea1</term>
/// <term>The event is triggered when the computer leaves a domain. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_DOMAIN_JOIN.</term>
/// </item>
/// <item>
/// <term>FIREWALL_PORT_OPEN_GUID b7569e07-8421-4ee0-ad10-86915afdad09</term>
/// <term>The event is triggered when the specified firewall port is opened. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT.</term>
/// </item>
/// <item>
/// <term>FIREWALL_PORT_CLOSE_GUID a144ed38-8e12-4de4-9d96-e64740b1a524</term>
/// <term>
/// The event is triggered approximately 60 seconds after the specified firewall port is closed. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT.
/// </term>
/// </item>
/// <item>
/// <term>MACHINE_POLICY_PRESENT_GUID 659FCAE6-5BDB-4DA9-B1FF-CA2A178D46E0</term>
/// <term>The event is triggered when the machine policy has changed. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_GROUP_POLICY.</term>
/// </item>
/// <item>
/// <term>NETWORK_MANAGER_FIRST_IP_ADDRESS_ARRIVAL_GUID 4f27f2de-14e2-430b-a549-7cd48cbc8245</term>
/// <term>
/// The event is triggered when the first IP address on the TCP/IP networking stack becomes available. The dwTriggerType member
/// must be SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY.
/// </term>
/// </item>
/// <item>
/// <term>NETWORK_MANAGER_LAST_IP_ADDRESS_REMOVAL_GUID cc4ba62a-162e-4648-847a-b6bdf993e335</term>
/// <term>
/// The event is triggered when the last IP address on the TCP/IP networking stack becomes unavailable. The dwTriggerType member
/// must be SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY.
/// </term>
/// </item>
/// <item>
/// <term>USER_POLICY_PRESENT_GUID 54FB46C8-F089-464C-B1FD-59D1B62C3B50</term>
/// <term>The event is triggered when the user policy has changed. The dwTriggerType member must be SERVICE_TRIGGER_TYPE_GROUP_POLICY.</term>
/// </item>
/// </list>
/// </summary>
public IntPtr pTriggerSubtype;
/// <summary>
/// <para>The number of SERVICE_TRIGGER_SPECIFIC_DATA_ITEM structures in the array pointed to by pDataItems.</para>
/// <para>
/// This member is valid only if the <c>dwDataType</c> member is SERVICE_TRIGGER_TYPE_CUSTOM,
/// SERVICE_TRIGGER_TYPE_DEVICE_ARRIVAL, SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, or SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT.
/// </para>
/// </summary>
public uint cDataItems;
/// <summary>
/// <para>A pointer to an array of SERVICE_TRIGGER_SPECIFIC_DATA_ITEM structures that contain trigger-specific data.</para>
/// </summary>
public IntPtr pDataItems;
/// <summary/>
public Guid TriggerSubType => pTriggerSubtype.ToStructure<Guid>();
/// <summary/>
public SERVICE_TRIGGER_SPECIFIC_DATA_ITEM[] DataItems => pDataItems.ToArray<SERVICE_TRIGGER_SPECIFIC_DATA_ITEM>((int)cDataItems);
}
/// <summary>
/// <para>
/// Contains trigger event information for a service. This structure is used by the ChangeServiceConfig2 and QueryServiceConfig2 functions.
/// </para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_trigger_info typedef struct _SERVICE_TRIGGER_INFO {
// DWORD cTriggers; PSERVICE_TRIGGER pTriggers; PBYTE pReserved; } SERVICE_TRIGGER_INFO, *PSERVICE_TRIGGER_INFO;
[PInvokeData("winsvc.h", MSDNShortId = "8de46056-1ea5-46f2-a260-ad140fd77bc1")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_TRIGGER_INFO
{
/// <summary>
/// <para>The number of triggers in the array of SERVICE_TRIGGER structures pointed to by the <c>pTriggers</c> member.</para>
/// <para>
/// If this member is 0 in a <c>SERVICE_TRIGGER_INFO</c> structure passed to ChangeServiceConfig2, all previously configured
/// triggers are removed from the service. If the service has no triggers configured, <c>ChangeServiceConfig2</c> fails with ERROR_INVALID_PARAMETER.
/// </para>
/// </summary>
public uint cTriggers;
/// <summary>
/// <para>
/// A pointer to an array of SERVICE_TRIGGER structures that specify the trigger events for the service. If the <c>cTriggers</c>
/// member is 0, this member is not used.
/// </para>
/// </summary>
public IntPtr pTriggers;
/// <summary>
/// <para>This member is reserved and must be NULL.</para>
/// </summary>
public IntPtr pReserved;
/// <summary/>
public SERVICE_TRIGGER[] Triggers => pTriggers.ToArray<SERVICE_TRIGGER>((int)cTriggers);
}
/// <summary>
/// <para>
/// Contains trigger-specific data for a service trigger event. This structure is used by the SERVICE_TRIGGER structure for
/// SERVICE_TRIGGER_TYPE_CUSTOM, SERVICE_TRIGGER_TYPE_DEVICE_ARRIVAL, SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, or
/// SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT trigger events.
/// </para>
/// </summary>
/// <remarks>
/// <para>The following table lists trigger-specific data by trigger event type.</para>
/// <list type="table">
/// <listheader>
/// <term>Event type</term>
/// <term>Trigger-specific data</term>
/// </listheader>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_CUSTOM</term>
/// <term>Specified by the Event Tracing for Windows (ETW) provider that defines the custom event.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL</term>
/// <term>
/// A SERVICE_TRIGGER_DATA_TYPE_STRING string that specifies a hardware ID or compatible ID string for the device interface class.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_DOMAIN_JOIN</term>
/// <term>Not applicable.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT</term>
/// <term>
/// A SERVICE_TRIGGER_DATA_TYPE_STRING multi-string that specifies the port, the protocol, and optionally the executable path and
/// name of the service listening on the event.
/// </term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_GROUP_POLICY</term>
/// <term>Not applicable.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY</term>
/// <term>Not applicable.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT</term>
/// <term>A SERVICE_TRIGGER_DATA_TYPE_STRING that specifies the port, named pipe, or RPC interface for the network endpoint.</term>
/// </item>
/// </list>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_trigger_specific_data_item typedef struct
// _SERVICE_TRIGGER_SPECIFIC_DATA_ITEM { DWORD dwDataType; DWORD cbData; PBYTE pData; } SERVICE_TRIGGER_SPECIFIC_DATA_ITEM, *PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM;
[PInvokeData("winsvc.h", MSDNShortId = "670e6c49-bbc0-4af6-9e47-6c89801ebb45")]
[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_TRIGGER_SPECIFIC_DATA_ITEM
{
/// <summary>
/// <para>The data type of the trigger-specific data pointed to by <c>pData</c>. This member can be one of the following values.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SERVICE_TRIGGER_DATA_TYPE_BINARY 1</term>
/// <term>The trigger-specific data is in binary format.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_DATA_TYPE_STRING 2</term>
/// <term>The trigger-specific data is in string format.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_DATA_TYPE_LEVEL 3</term>
/// <term>The trigger-specific data is a byte value.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY 4</term>
/// <term>The trigger-specific data is a 64-bit unsigned integer value.</term>
/// </item>
/// <item>
/// <term>SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL 5</term>
/// <term>The trigger-specific data is a 64-bit unsigned integer value.</term>
/// </item>
/// </list>
/// </summary>
public ServiceTriggerDataType dwDataType;
/// <summary>
/// <para>The size of the trigger-specific data pointed to <c>pData</c>, in bytes. The maximum value is 1024.</para>
/// </summary>
public uint cbData;
/// <summary>
/// <para>
/// A pointer to the trigger-specific data for the service trigger event. The trigger-specific data depends on the trigger event
/// type; see Remarks.
/// </para>
/// <para>If the <c>dwDataType</c> member is SERVICE_TRIGGER_DATA_TYPE_BINARY, the trigger-specific data is an array of bytes.</para>
/// <para>
/// If the <c>dwDataType</c> member is SERVICE_TRIGGER_DATA_TYPE_STRING, the trigger-specific data is a null-terminated string or
/// a multistring of null-terminated strings, ending with two null-terminating characters. For example: .
/// </para>
/// <para>Strings must be Unicode; ANSI strings are not supported.</para>
/// </summary>
public IntPtr pData;
}
/// <summary>Provides a <see cref="SafeHandle"/> to a service that releases a created SC_HANDLE instance at disposal using CloseServiceHandle.</summary>
public class SafeSC_HANDLE : SafeHANDLE
{
/// <summary>Initializes a new instance of the <see cref="SC_HANDLE"/> class and assigns an existing handle.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
/// <param name="ownsHandle">
/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
/// </param>
public SafeSC_HANDLE(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
/// <summary>Initializes a new instance of the <see cref="SC_HANDLE"/> class.</summary>
private SafeSC_HANDLE() : base() { }
/// <summary>Performs an implicit conversion from <see cref="SafeSC_HANDLE"/> to <see cref="SC_HANDLE"/>.</summary>
/// <param name="h">The safe handle instance.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SC_HANDLE(SafeSC_HANDLE h) => h.handle;
/// <inheritdoc/>
protected override bool InternalReleaseHandle() => CloseServiceHandle(this);
}
}
}