Service ServiceMain 函数

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

ServiceMain 函数应执行以下任务:

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

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

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

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

    • 调用 SetServiceStatus 函数以报告SERVICE_RUNNING但在初始化完成之前不接受任何控件。 该服务通过调用 SetServiceStatus 来执行此操作,其中 dwCurrentState 设置为 SERVICE_RUNNING, dwControlsAcceptedSERVICE_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。 请务必设置SERVICE_STATUS结构的 dwServiceSpecificExitCodedwWin32ExitCode 成员以识别错误。

编写 ServiceMain 函数