分派器启动一个新线程,该线程运行分派表中每个服务的
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;