background image

分派器启动一个新线程,该线程运行分派表中每个服务的

 ServiceMain 函数(本文例子中

只有一个服务)分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从

 SCM 

传给服务。

注意:如果

 StartServiceCtrlDispatcher 函数 30 秒没有被调用,便会报错,为了避免这种情

况,我们必须在

 ServiceMain 函数中(参见本文例子)或在非主函数的单独线程中初始化

服务分派表。本文所描述的服务不需要防范这样的情况。

  分派表中所有的服务执行完之后(例如,用户通过

“服务”控制面板程序停止它们),

或者发生错误时。

StartServiceCtrlDispatcher 调用返回。然后主进程终止。

第二步:

ServiceMain 函数

  

Listing 1 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程

当中,这个线程是由控制分派器创建的。

ServiceMain 应该尽可能早早为服务注册控制处理

器。这要通过调用

 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数:服

务名和指向

 ControlHandlerfunction 的指针。

  它指示控制分派器调用

 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之

后,获得状态句柄(

hStatus)。通过调用 SetServiceStatus 函数,用 hStatus 向 SCM 报告服

务的状态。
Listing 1 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构,ServiceStatus 
结构的每个域都有其用途:

dwServiceType:指示服务类型,创建 Win32 服务。赋值 SERVICE_WIN32;
dwCurrentState:指定服务的当前状态。因为服务的初始化在这里没有完成,所以这里的状
态为

 SERVICE_START_PENDING;

dwControlsAccepted : 这 个 域 通 知   SCM  服 务 接 受 哪 个 域 。 本 文 例 子 是 允 许   STOP  和

 

SHUTDOWN 请求。处理控制请求将在第三步讨论;
dwWin32ExitCode 和 dwServiceSpecificExitCode:这两个域在你终止服务并报告退出细节时
很有用。初始化服务时并不退出,因此,它们的值为

 0;

dwCheckPoint 和 dwWaitHint:这两个域表示初始化某个服务进程时要 30 秒以上。本文例子
服务的初始化过程很短,所以这两个域的值都为

 0。

    调 用

  SetServiceStatus  函 数 向   SCM  报 告 服 务 的 状 态 时 。 要 提 供   hStatus  句 柄 和

 

ServiceStatus  结构。注意 ServiceStatus  一个全局变量,所以你可以跨多个函数使用它 。
ServiceMain 函数中,你给结构的几个域赋值,它们在服务运行的整个过程中都保持不变,
比如:

dwServiceType。

  在报告了服务状态之后,你可以调用

 InitService 函数来完成初始化。这个函数只是添加

一个说明性字符串到日志文件。如下面代码所示:

// 服务初始化
int InitService()
{
    int result;