ServiceMain 函数

当服务控制程序请求新服务运行时,服务控制管理器(SCM)将启动服务并向控制调度程序发送启动请求。 控制调度程序创建一个新线程,用于为服务执行 ServiceMain 函数。 有关示例,请参阅 编写 ServiceMain 函数

ServiceMain 函数应执行以下任务:

  1. 初始化所有全局变量。

  2. 立即调用 RegisterServiceCtrlHandler 函数,以注册 处理程序 函数来处理服务的控制请求。 RegisterServiceCtrlHandler 的返回值是 服务状态句柄,用于调用以通知 SCM 服务状态。

  3. 执行初始化。 如果初始化代码的执行时间预计非常短(小于 1 秒),则可以在 serviceMain中直接执行初始化。

    如果初始化时间预计超过一秒,服务应使用以下初始化技术之一:

    • 调用 SetServiceStatus 函数来报告SERVICE_RUNNING,但在初始化完成之前不接受任何控件。 该服务通过调用 SetServiceStatusdwCurrentState 设置为 SERVICE_RUNNING,dwControlsAccepted 设置为 SERVICE_STATUS 结构中的 0 来执行此作。 这可确保 SCM 在准备就绪之前不会向服务发送任何控制请求,并释放 SCM 来管理其他服务。 对于性能,建议使用此方法进行初始化,尤其是对于自动启动服务。

    • 报告SERVICE_START_PENDING,不接受任何控件,并指定等待提示。 如果服务的初始化代码执行的任务预期比初始等待提示值长,则代码必须定期调用 SetServiceStatus 函数(可能带有修订的等待提示),以指示正在进行进度。 请确保仅在初始化正在进行时调用 SetServiceStatus。 否则,SCM 可以等待服务进入SERVICE_RUNNING状态,前提是服务正在进行,并阻止其他服务启动。 请勿从单独的线程调用 SetServiceStatus,除非确定执行初始化的线程确实正在进行。

      使用此方法的服务还可以指定检查点值,并在长时间初始化期间定期递增值。 启动服务的程序可以调用 QueryServiceStatusQueryServiceStatusEx 以获取 SCM 的最新检查点值,并使用该值向用户报告增量进度。

  4. 初始化完成后,调用 SetServiceStatus 将服务状态设置为SERVICE_RUNNING并指定服务准备接受的控件。 有关控件列表,请参阅 SERVICE_STATUS 结构。

  5. 执行服务任务,或者如果没有挂起的任务,请向调用方返回控制权。 服务状态的任何更改都要求调用 SetServiceStatus 来报告新的状态信息。

  6. 如果服务正在初始化或运行时发生错误,则服务应调用 SetServiceStatus 来将服务状态设置为SERVICE_STOP_PENDING(如果清理时间较长)。 清理完成后,调用 SetServiceStatus,将服务状态设置为从最后一个线程SERVICE_STOPPED终止。 请务必设置 dwServiceSpecificExitCodedwWin32ExitCodeSERVICE_STATUS 结构的成员来标识错误。

编写 ServiceMain 函数