服务控制处理程序函数
每个服务都有一个控制处理程序, 即 Handler 函数,当服务进程收到来自服务控制程序的控制请求时,控制调度程序将调用该处理程序。 因此,此函数在控件调度程序的上下文中执行。 有关示例,请参阅 编写控件处理程序函数。
服务调用 RegisterServiceCtrlHandler 或 RegisterServiceCtrlHandlerEx 函数来注册其服务控制处理程序函数。
调用服务控制处理程序时,服务必须调用 SetServiceStatus 函数,以便仅当处理控制代码导致服务状态更改时,才向 SCM 报告其状态。 如果处理控制代码不会导致服务状态更改,则无需调用 SetServiceStatus。
服务控制程序可以使用 ControlService 函数发送控制请求。 所有服务都必须接受并处理 SERVICE_CONTROL_INTERROGATE 控制代码。 可以通过调用 SetServiceStatus 启用或禁用接受其他控制代码。 若要接收 SERVICE_CONTROL_DEVICEEVENT 控制代码,必须调用 RegisterDeviceNotification 函数。 服务还可以处理用户定义的其他控制代码。
如果服务接受 SERVICE_CONTROL_STOP 控制代码,则必须在收到后停止,进入 SERVICE_STOP_PENDING 或 SERVICE_STOPPED 状态。 SCM 发送此控制代码后,不会发送其他控制代码。
Windowsxp: 如果服务返回 NO_ERROR 并继续运行,它将继续接收控制代码。 从 Windows Server 2003 和 Windows XP service Pack 2 (SP2) 开始,此行为已更改。
控制处理程序必须在 30 秒内返回,否则 SCM 返回错误。 如果服务在执行控件处理程序时必须执行冗长处理,则它应创建一个辅助线程来执行冗长的处理,然后从控件处理程序返回。 这可以防止服务将控制调度程序绑起来。 例如,处理某个服务需要很长时间的停止请求时,请创建另一个线程来处理停止进程。 控件处理程序应仅使用SERVICE_STOP_PENDING消息调用 SetServiceStatus 并返回。
当用户关闭系统时,使用SERVICE_ACCEPT_PRESHUTDOWN控制代码调用 SetServiceStatus 的所有控件处理程序都会接收SERVICE_CONTROL_PRESHUTDOWN控件代码。 服务控制管理器将等待服务停止或指定的预关闭超时值过期, (可以使用 ChangeServiceConfig2 函数) 设置此值。 此控制代码应仅在特殊情况下使用,因为处理此通知的服务会阻止系统关闭,直到服务停止或预关闭超时间隔过期。
完成预暂停通知后,使用SERVICE_ACCEPT_SHUTDOWN控件代码调用 SetServiceStatus 的所有控件处理程序都会接收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 通知,并等待服务退出,然后从其控制处理程序返回。
相关主题