服务控制处理程序函数

每个服务都有一个控制处理程序,即 处理程序 函数,当服务进程从服务控制程序收到控件请求时,该函数由控制调度程序调用。 因此,此函数在控件调度程序上下文中执行。 有关示例,请参阅 编写控件处理程序函数

服务调用 RegisterServiceCtrlHandlerRegisterServiceCtrlHandlerEx 函数来注册其服务控制处理程序函数。

调用服务控制处理程序时,服务必须调用 SetServiceStatus 函数,仅当处理控制代码会导致服务状态更改时,才能将其状态报告给 SCM。 如果处理控制代码不会导致服务状态更改,则无需调用 SetServiceStatus

服务控制程序可以使用 ControlService 函数发送控制请求。 所有服务都必须接受并处理 SERVICE_CONTROL_INTERROGATE 控制代码。 可以通过调用 SetServiceStatus来启用或禁用接受其他控制代码。 若要接收 SERVICE_CONTROL_DEVICEEVENT 控制代码,必须调用 RegisterDeviceNotification 函数。 服务还可以处理其他用户定义的控制代码。

如果服务接受 SERVICE_CONTROL_STOP 控制代码,则必须在收到后停止,转到 SERVICE_STOP_PENDINGSERVICE_STOPPED 状态。 SCM 发送此控制代码后,它不会发送其他控制代码。

Windows XP: 如果服务返回 NO_ERROR 并继续运行,它将继续接收控制代码。 此行为从 Windows Server 2003 开始更改,Windows XP 与 Service Pack 2 (SP2) 一起发生更改。

控制处理程序必须在 30 秒内返回,或者 SCM 返回错误。 如果服务在执行控制处理程序时必须执行较长的处理,则应创建一个辅助线程来执行较长的处理,然后从控制处理程序返回。 这可以防止服务将控制调度程序绑起来。 例如,处理需要很长时间的服务的停止请求时,请创建另一个线程来处理停止进程。 控件处理程序应只使用 SERVICE_STOP_PENDING 消息调用 SetServiceStatus 并返回。

当用户关闭系统时,所有调用 SetServiceStatus 的控件处理程序SERVICE_ACCEPT_PRESHUTDOWN 控件代码都会收到 SERVICE_CONTROL_PRESHUTDOWN 控制代码。 服务控制管理器会等待服务停止或指定的预超时超时值过期(此值可以使用 ChangeServiceConfig2 函数进行设置)。 此控制代码应仅在特殊情况下使用,因为处理此通知的服务会阻止系统关闭,直到服务停止或预暂停超时间隔过期。

完成预决通知后,所有调用 SetServiceStatusSERVICE_ACCEPT_SHUTDOWN 控件代码的控件处理程序都会收到 SERVICE_CONTROL_SHUTDOWN 控制代码。 按照安装服务数据库中显示的顺序通知他们。 默认情况下,在系统关闭之前,服务大约需要 20 秒来执行清理任务。 此时间过后,无论服务关闭是否完成,系统关闭都会继续。 请注意,如果系统处于关闭状态(未重启或关闭),服务将继续运行。

如果服务需要更多时间来清理,它会发送 STOP_PENDING 状态消息以及等待提示,因此服务控制器知道在向系统报告服务关闭完成之前要等待多长时间。 但是,为了防止服务停止关闭,服务控制器等待的时间有限制。 如果服务通过服务管理单元关闭,则限制为 125 秒或 125,000 毫秒。 如果作系统正在重新启动,则会在以下注册表项的 WaitToKillServiceTimeout 值(以毫秒为单位)中指定时间限制:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

重要

服务不应尝试通过修改此值来增加时间限制。 如果需要手动设置 WaitToKillServiceTimeout,该值应为毫秒。

客户需要快速关闭作系统。 例如,如果在 UPS 电源上运行的计算机在 UPS 断电之前无法完成关闭,则数据可能会丢失。 因此,服务应尽快完成其清理任务。 最好是定期保存数据、跟踪保存到磁盘的数据,以及仅在关闭时保存未保存的数据,从而最大程度地减少未保存的数据。 由于计算机正在关闭,因此不要花时间释放分配的内存或其他系统资源。 如果需要通知服务器你正在退出,请尽量减少等待回复所用的时间,因为网络问题可能会延迟服务的关闭。

请注意,在服务关闭期间,默认情况下,SCM 不会考虑依赖项。 SCM 枚举正在运行的服务列表,并发送 SERVICE_CONTROL_SHUTDOWN 命令。 因此,服务可能会失败,因为它依赖的另一个服务已停止。

若要手动设置服务的关闭顺序,请创建一个多字符串注册表值,该值包含应关闭服务名称的顺序,并将其分配给控制键的 PreshutdownOrder 值,如下所示:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PreshutdownOrder="Shutdown Order“

若要从应用程序设置从属服务的关闭顺序,请使用 SetProcessShutdownParameters 函数。 SCM 使用此函数为其处理程序提供0x1E0优先级。 当调用其控制处理程序时,SCM 将发送 SERVICE_CONTROL_SHUTDOWN 通知,并等待服务退出,然后再从其控制处理程序返回。

编写控制处理程序函数