当服务控制程序请求运行新服务时,服务控制管理器(SCM)启动服务并向控制调度程序发送启动请求。控制调度程序创建一个新线程来执行服务的ServiceMain功能。有关示例,请参阅编写ServiceMain函数。
ServiceMain函数应执行以下任务:
1、初始化所有全局变量。
2、立即调用RegisterServiceCtrlHandler函数以注册Handler函数来处理服务的控制请求。 RegisterServiceCtrlHandler的返回值是一个服务状态句柄,将在调用中用于通知SCM服务状态。
3、执行初始化。如果预期初始化代码的执行时间非常短(小于一秒),则可以直接在ServiceMain中执行初始化。
如果预计初始化时间超过一秒,则服务应使用以下初始化技术之一:
- 调用SetServiceStatus函数报告SERVICE_RUNNING,但在初始化完成之前不接受任何控制。该服务通过在SERVICE_STATUS结构中调用SetServiceStatus并将dwCurrentState设置为SERVICE_RUNNING并将dwControlsAccepted设置为0来执行此操作。这可确保SCM在服务准备就绪之前不会向服务发送任何控制请求,并释放SCM以管理其他服务。建议使用这种初始化方法来提高性能,尤其是对于自动启动服务。
- 报告SERVICE_START_PENDING,不接受任何控件,并指定等待提示。如果服务的初始化代码执行预期花费的时间超过初始等待提示值的任务,则代码必须定期调用SetServiceStatus函数(可能带有修订的等待提示)以指示正在进行的进度。确保仅在初始化进行时调用SetServiceStatus。否则,SCM可以等待您的服务进入SERVICE_RUNNING状态,假设您的服务正在取得进展并阻止其他服务启动。除非您确定执行初始化的线程确实正在取得进展,否则不要从单独的线程调用SetServiceStatus。
- 使用此方法的服务还可以指定检查点值,并在冗长的初始化期间定期递增值。启动该服务的程序可以调用QueryServiceStatus或QueryServiceStatusEx以从SCM获取最新的检查点值,并使用该值向用户报告增量进度。
初始化完成后,调用SetServiceStatus将服务状态设置为SERVICE_RUNNING,并指定服务准备接受的控件。有关控件列表,请参阅SERVICE_STATUS结构。
执行服务任务,或者,如果没有挂起的任务,则将控制权返回给调用者。服务状态的任何更改都需要调用SetServiceStatus来报告新的状态信息。
如果在服务初始化或运行时发生错误,则服务应调用SetServiceStatus以将服务状态设置为SERVICE_STOP_PENDING(如果清理将很长)。清理完成后,调用SetServiceStatus将服务状态从最后一个线程设置为SERVICE_STOPPED以终止。请务必设置SERVICE_STATUS结构的dwServiceSpecificExitCode和dwWin32ExitCode成员以识别错误。