(三)对服务的深入讨论之下
现在我们还剩下一个函数可以在细节上讨论,那就是服务的CtrlHandler函数。
当调用RegisterServiceCtrlHandler函数时,SCM得到并保存这个回调函数的地址。一个SCP调一个告诉SCM如何去控制服务的Win32函数,现在已经有10个预定义的控制请求:
Control code |
Meaning |
---|---|
SERVICE_CONTROL_STOP | Requests the service to stop. The hService handle must have SERVICE_STOP access. |
SERVICE_CONTROL_PAUSE | Requests the service to pause. The hService handle must have SERVICE_PAUSE_CONTINUE access. |
SERVICE_CONTROL_CONTINUE | Requests the paused service to resume. The hService handle must have SERVICE_PAUSE_CONTINUE access. |
SERVICE_CONTROL_INTERROGATE | Requests the service to update immediately its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access. |
SERVICE_CONTROL_SHUTDOWN | Requests the service to perform cleanup tasks, because the system is shutting down. For more information, see Remarks. |
SERVICE_CONTROL_PARAMCHANGE | Windows 2000: Requests the service to reread its startup parameters. The hService handle must have SERVICE_PAUSE_CONTINUE access. |
SERVICE_CONTROL_NETBINDCHANGE | Windows 2000: Requests the service to update its network binding. The hService handle must have SERVICE_PAUSE_CONTINUE access. |
SERVICE_CONTROL_NETBINDREMOVE | Windows 2000: Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component. |
SERVICE_CONTROL_NETBINDENABLE | Windows 2000: Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding. |
SERVICE_CONTROL_NETBINDDISABLE | Windows 2000: Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding. |
上表中标有Windows 2000字样的就是2000中新添加的控制代码。除了这些代码之外,服务也可以接受用户定义的,范围在128-255之间的代码。
当CtrlHandler函数收到一个SERVICE_CONTROL_STOP、SERVICE_CONTROL_PAUSE、 SERVICE_CONTROL_CONTINUE控制代码的时候,SetServiceStatus必须被调用去确认这个代码,并指定你认为服务处理这个状态变化所需要的时间。
例如:你的服务收到了停止请求,首先要把SERVICE_STATUS结构的dwCurrentState成员设置成SERVICE_STOP_PENDING,这样可以使SCM确定你已经收到了控制代码。当一个服务的暂停或停止操作正在执行的时候,必须指定你认为这种操作所需要的时间:这是因为一个服务也许不能立即改变它的状态,它可能必须等待一个网络请求被完成或者数据被刷新到一个驱动器上。指定时间的方法就像我上一章说的那样,用成员dwCheckPoint和dwWaitHint来指明它完成状态改变所需要的时间。如果需要,可以用增加dwCheckPoint成员的值和设置dwWaitHint成员的值去指明你期待的服务到达下一步的时间的方式周期性的报告进展情况。
当整个启动的过程完成之后,要再一次调用SetServiceStatus。这时就要把SERVICE_STATUS结构的dwCurrentState成员设置成SERVICE_STOPPED,当报告状态代码的同时,一定要把成员dwCheckPoint和dwWaitHint设置为0,因为服务已经完成了它的状态变化。暂停或继续服务的时候方法也一样。
当CtrlHandler函数收到一个SERVICE_CONTROL_INTERROGATE控制代码的时候,服务将简单的将dwCurrentState成员设置成服务当前的状态,同时,把成员dwCheckPoint和dwWaitHint设置为0,然后再调用SetServiceStatus就可以了。
在操作系统关闭的时候,CtrlHandler函数收到一个SERVICE_CONTROL_SHUTDOWN控制代码。服务根本无须回应这个代码,因为系统即将关闭。它将执行保存数据所需要的最小行动集,这是为了确定机器能及时关闭。缺省时系统只给很少的时间去关闭所有的服务,MSDN里面说大概是20秒的时间,不过那可能是Windows NT 4的设置,在我的Windows 2000 Server里这个时间是10秒,你可以手动的修改这个数值,它被记录在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control子键里面的WaitToKillServiceTimeout,单位是毫秒。