Windows Vista 的服务

来源:互联网 发布:淘宝店铺打折工具 编辑:程序博客网 时间:2024/04/21 00:27

Windows Vista 的服务

2006-8-9

本文档提供了一些Windows Vista服务的相关信息。对于想在这个版本的Windows上面开发服务程序的开发者们,本文档也提供了一些最优方法。

这些信息应用在Windows操作系统上。

微软可能会随时更改本文档内容,可在以下地址获取最新的英文版本。

http://go.microsoft.com/fwlink/?LinkId=71280

Windows 服务概述

MicrosoftWindows服务就是程序,通常,它们虽Windows一起启动,并在后台运行,直到被关闭。严格一点说,服务就是所有用服务API实现的Windows程序。通常,服务处理一些低级别的任务,这些任务很少需要和用户交互。

尽管服务对于用户通常是不可见的,但Windows功能又离不开他们。服务处理许多重要的操作系统功能,包括:

1、联网。很多系统服务支持联网。比如动态主机配置协议(DynamicHost Configuration Protocol, DHCP)客户端服务通过存储和更新系统的IP地址来管理网络配置。

2、硬件。即插即用服务(Plug and Play)使计算机可以识别硬件配置的变化并做出响应,例如用户添加或者卸载了一个硬件。

3、远程访问。终端服务(TerminalServices)允许用户在远程登陆计算机。

除了Windows自带的服务,大部分计算机还会运行很多第三方的服务。见到最多的就是防火墙和防病毒程序。

服务怎样运行

服务和一般程序最主要的区别是,服务被服务控制管理器(ServiceControl Manager ,SCM)管理。使用服务API实现服务,这些API处理服务和SCM之间的交互。SCM维护一个数据库,这个数据库放置了所有已安装服务的信息,并提供一个统一的方法来控制这些服务:

1、开始和停止服务。

2、管理正在运行的服务。

3、维护服务相关的状态信息。

服务有三种状态:已运行,已停止,已暂停。

1、已运行是服务的一般运行状态。

2、已停止的服务已经完全关闭,必须经过一个启动过程,才能再次进入已运行的状态。

3、已暂停服务中止处理,但是还驻留在内存中,并且继续响应控制请求。以暂停的服务可以跳过启动过程直接进入以运行的状态。

服务的一个关键的特征是它怎样被启动。SCM管理的数据库里有这样的信息。有三种启动模式:

1、自动。在系统引导中,SCM自动启动这些服务。

2、手动。想启动这类服务,必须利用控制面板中的管理工具。

3、禁用。这些服务不能被启动。要想启动这类服务,用户必须把启动模式调整为自动或者手动

当服务启动后,SCM利用控制请求来管理服务的状态。比如,SCM向服务发送控制请求,通知服务暂停,继续运行,或者准备关闭。SCM的数据库也包含了服务的安全设置。这些设置控制服务有多少权限去访问系统资源,也使得系统管理者可以控制每个服务的权限。

Windows Vista中Windows服务的变化

多年来,服务已经成为Windows一个重要的组成部分。它使得开发者们可以创建长时间运行的程序:

1、可以随计算机自动启动。

2、可以被暂停和重开。

3、无论用户登陆与否,都能运行。

4、可以运行在一个独立的账户环境下,这个账户可以不同于已登陆的账户和默认账户。

这些特点使得服务可以长时间的运行,而不干扰在同一计算机上工作的用户。自从服务概念的引入,服务的运行环境已经发生了很大的变化。这些变化已经带来了一些很多问题:安全性、可靠性、性能、操作和管理。

这一节,讨论一下对于Windows Vista做出的改进。

安全性增强

近些年,服务已经成为那些病毒制造者们的目标。最近的例子有:“Blaster”、“ Sasser”、和“Code Red”。对于这个现象,有很多原因:

1、服务基本上都在长时间运行。通常,从系统启动到关闭,它们都在运行。

2、服务通常都是面向网络的,这使得他们极易受到远程攻击。

3、服务基本上以高权限账户运行,比如LocalSystem。

这一节,讨论一下对于Windows Vista做出的改进,这些改进为了缓和服务的安全问题。这些改变有两个重要的目的:

1、限制用户程序访问服务。会话0隔离(Session 0 isolation)要求服务和用户程序运行在隔离的会话里。

2、“固化”服务使不安全服务破系统的可能性降低。有以下两个互补的方法来达到这个目的:

l  最小权限,使得服务运行在它所需要的权限范围内,做不了其他的事情。

l  服务隔离,利用唯一的服务标识,使服务如其他服务和程序隔离开。服务可以利用这个标识来限制其他服务和程序对它的资源的访问,也可以限制自己对其他服务和程序的资源访问。比如,服务隔离允许防病毒服务维护签名定义文件的专门入口。

以最小权限运行

Windows服务通常以LocalSystem账户运行,这个账户具有系统的最高权限。这样的服务成为病毒制造者很有吸引力目标。理想情况下,服务应该以低权限级的LocalService 或者NetworkService账户运行,从而减小对系统潜在的破坏。但是,很多服务需要的一些权限只有LocalSystem能够支持。在Windows Vista之前就用的“all-or-nothing”模型意思是,服务得到了一些LocalSystem的权限后,它也同时具有了LocalSystem的所有其他权限。这意味着很多时候,服务所具有的权限不是它所需要的,产生对系统潜在的破坏性。

Windows Vista允许服务以最小权限运行,解决了这个问题。服务不会再被标准账户支持的默认权限所限制。服务可以选择账户,这个账户有他们需要的权限,之后,服务还可以去掉所有它不需要的权限。这个功能可以用于所有的账户类型:LocalService, NetworkService,LocalSystem,一个域,或者一个本地账户。

服务利用一些机制来声明他们所需要的权限,这些机制将在之后讨论。当SCM启动服务时:

1、对于独立的服务,SCM逆着对照进程标记符检查权限需求列表,所有没有被要求的权限都会被从进程标识符上去掉。

2、对于共享的服务,例如svchost的服务宿主,在这个组里的所有服务需要的权限合并成权限列表。SCM只将没有任何一个成员服务需要的权限从进程标识符上删除。

3、如果服务没有申明需要的权限,SCM假设服务需要与账户相关的所有权限。这样确保了向后兼容性。但是,如果服务组中有一个这样的服务,组中的其他服务也都以账户默认的一组权限运行。

如果进程标识符里没有服务要求的权限,SCM不会启动这个服务。比如,以NetworkService账户运行的程序可以将SeTcbPrivilege指定为需要的权限。但是,NetworkService进程标识符不支持SeTcbPrivilege,所以启动失败。

怎么指定所需权限

1、Sc.exe——管理服务的命令行工具——有两个新命令,支持为服务指定所需权限。

l  privs 这个命令为服务设定一个权限。privs 的语法是:

sc <server> privs [Privileges]

l   qprivs这个命令查询服务需要的权限,qprivs的语法是:

sc <server> qprivs [service name] buffersize

Privileges是一个字符串,包含权限列表,以斜杠分开(/)。例如,指定备份和恢复权限,将Privileges设置成“SeBackupPrivilege/SeRestorePrivilege”。

2、利用程序指定需要的权限,以下面的值为参数调用ChangeServiceConfig2:

l  将dwInfo参数设置为

SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO

l  使lpInfo指向一个SERVICE_REQUIRED_PRIVILEGES_INFO结构。这个结构包含了一个字符串,字符串列出了需要的权限。

使用QueryServiceConfig2查询服务需要的权限。

权限的变化将在服务下一次启动时生效。注意一点,不管是命令行工具还是函数,都会检查列表中的权限是否有效,但是它们不能确定服务是否支持指定的权限。这个工作是由SCM在试图启动一个服务的时候做的。

注意:权限列表只能被那些具有SERVICE_CHANGE_CONFIG权限的调用程序更改。默认情况下,只有本地管理员,权力用户和服务器操作员可以在远程或者本地取得得到这个权限。具有SERVICE_QUERY_CONFIG权限的调用程序可以查询需要的权限的列表。默认情况下,只有本地管理员,权力用户和服务器操作员可以在远程取得得到这个权限,服务和交互的用户可以在本地取得这个权限。

服务隔离

许多服务需要访问一些特定的对象,而这些对象只有高权限账户才能访问。比如,服务可能要向注册表写值,而注册表只有管理员能够访问。在WindowsVista以前的系统中,服务以象LocalSystem这样的高权限账户运行,从而得到访问这些对象的权限。还有一个做法,就是降低这些对象的安全性,使具有低权限的服务已可以访问它们。

这两个方式都有可能使攻击者或病毒得到系统的控制权。对于管理员,唯一可以降低这个风险的方法是,建立一个服务的专有账户,只让这个账户具有访问这些对象的权限。但是,这样又带来了管理效率的问题:大量的密码管理,因为管理员再也利用不到使用系统内置账户的好处了。

为了缓和这个问题,Windows Vista引入了服务隔离,它给服务提供了一个访问特定对象的方法,既不需要以高权限运行,又不需要降低对象的安全。例如,服务隔离允许一个反病毒服务运行在比LocalSystem权限更低的账户下,但这个反病毒服务还能完全访问它的特征定义文件或者注册表,通常这些只有管理员可以访问。

服务隔离是一个专门用来保护资源(比如访问文件或者注册表的访问)的对象,它有一个包含服务安全ID(service security ID , SID)的权限控制表。我们把这个ID叫做“per-service SID”,它来源于服务的名字,对于服务是唯一的。

SID被分配给服务之后,服务的所有者就可以更改所需的对象的权限控制列表(access control lists, ACLs),使得服务可以访问这个对象。例如,具有管理权限的服务才能够访问注册表键值HKEY_LOCAL_MACHINE\SOFTWARE。把per-service SID添加到这个键值的ACL里,服务就可以运行在权限更低的账户下,但还可以访问这个键值。

如果per-serviceSID被启用,它被添加到服务的进程标识符里。注意,在服务的进程被添加到进程标识符里的同时,必须启用per-service SID。per-service SID也允许,向进程标识符里添加几个SID之后,把进程标识符转换成一个限制标识符。

利用受限SID减少潜在破坏

使用per-service SID,提供了良好的隔离程度,并且允许服务运行在更低的权限账户下。但是,它并不阻止服务访问账户可以访问的资源,因为进程标识符包含了账户的SID。考虑下面的情况:

X服务以LocalService账户运行,并且启用了SID。除了可以访问已经明确给予它访问权限的那些对象,它还可以访问LocalService账户可以访问的所有对象。如果这个服务涉及安全问题,攻击者可能利用它访问与这个服务不相关的资源,从而破坏系统。

为了缓和这个问题,降低涉及安全问题的服务对系统造成破坏的可能性,Windows Vista结合写限制标识符(write-restrictedtokens)和per-service SID为服务引入受限SID。

服务启用受限SID时,服务的SID被添加到写限制服务进程标识符的正常和受限SID列表中。这样保证了,只有明确地将对象的写权限赋予受限列表中的SID时,服务才可以写对象。回到上面的例子,启用受限SID,X服务将没有权限写入访问LocalService账户可以访问的对象,因为服务X的per-service SID没有被明确地赋予这些对象的写权限。

怎样指定per-service SID

1、要指定per-service SID,SID的种类必须设定为SERVICE_SID_TYPE_UNRESTRICTED。如果服务不需要SID,可以不设置SID类型,或者把它设置为SERVICE_SID_TYPE_NONE。设置了类型之后,SID在下一次进程创建的时候被添加到进程标识符里。可用以下两种属性激活SID:

l  SE_GROUP_ENABLED_BY_DEFAULT

l  SE_GROUP_OWNER

存取控制表也扩充了服务的进程标识符,它为服务登陆SID提供GENERIC_ALL权限。这就允许在服务启动或者停止的时候,激活或者禁用进程标识符中服务的SID。

SID被添加到进程标识符之后,它就不能被去掉了。SID的类型必须改变,之后进程必须被重新利用。这个改变只会发生在进程重开的时候。

2、要把进程标识符设置成写入限制的。SID必须设置成为SERVICE_SID_TYPE_RESTRICTED。使用SERVICE_SID_TYPE_RESTRICTED类型,必须要考虑几个问题。

l  如果进程包含多个服务,所有的这些服务都必须设置成SERVICE_SID_TYPE_RESTRICTED。否则,设置成为SERVICE_SID_TYPE_RESTRICTED的服务都会启动失败。

l  三个SID被自动地加入到受限列表:

Ø  通用SID(World SID)(S-1-1-0)。这个SID为服务提供所有ACL支持通用SID的对象的写权限。通用SID提供访问装载路径中的一些动态连接库的权限。

Ø  服务登陆SID。这个SID提供那些连接服务进程和SCM的命名管道的写权限。

Ø  写限制SID(S-1-5-33)。这个SID允许对象拥有一个ACL,使得所有写限制的服务进程可以写入对象。一个常见的例子就是Windows的事件跟踪对象(event tracing for Windows (ETW) objects)。

3、Sc.exe有两个支持per-service SID的新命令:

Sidtype。这个命令改变服务的SID。命令的语法为:

sc <server> sidtype [service name] [type]

Qsidtype。这个命令找回服务的SID设置。命令的语法为:

      sc<server> qsidtype [service name]

4、如果要编程设置这个标志,调用ChangeServiceConfig2,用下面的属性值作参数。在系统下一次启动时,改变将会生效:

l  将dwInfo设置为SERVICE_CONFIG_SERVICE_SID_INFO。

l  使lpInfo指向一个SERVICE_SID_INFO结构。这个结构包含一个DWORD成员,这个成员包含SID类型。

5、两个关联的公共函数对于服务所有者也很有用:

LookupAccountName,传入SID,返回相关的服务名。

LookupAccountSID,传入服务名,返回相关的SID。

6、也可使用Sc.exe来得到指定的服务的服务SID。下面的命令返回一个服务的SID。

       Sc showsid [service name]

注意:调用者必须拥有SERVICE_CHANGE_CONFIG权限才能改变这些设置。默认情况下,只有管理员,权力用户,服务器操作员可以在远程或者本地得到这个权限。另外,服务和交互用户可以在本地得到SERVICE_CHANGE_CONFIG权限。

受限的网络访问

很多服务都是面向网络的,使得他们很容易受到远程攻击。服务固化在WindowsVista和Microsoft Windows Server® CodeName "Longhorn"中,这样允许开发者减少服务对网络资源的访问,这些资源包括端口、协议、网络通信方向。比如,DHCP服务——更新系统的IP地址——可以把它自己限制到本地68端口,入站的用户数据报协议通信在远程的67端口。打开或者监听其他端口的企图,都会被Windows Vista和Windows Server Longhorn的防火墙阻止。

Windows Vista和WindowsServer Longhorn支持下面这几种服务网络限制的情况:

情况

举例

限制

无网络权限

Shell 硬件检测服务 (ShellHWDetection)

服务不可能监听或者连接到网络

监听静态的TCP或者UDP端口

远程过程调用服务(Rpcss),在135端口上

服务只能监听指定的终端

监听可配置的TCP或者UPD端口

域名服务(DNS)

服务可以监听配置的终端

服务网络限制和per-service SIDS一起使用。这个机制有点像用于限制服务的文件或注册表的权限,这在“服务隔离”中讨论过了。WindowsVista和Windows Server Longhorn的防火墙API已经被加强,提供这些必要的支持。INetFwServiceRestriction接口包含了限制服务网络权限的方法。要取得更多信息,请看“因特网连接共享和因特网连接防火墙”,在本文档最后的“资源”一章。

下面的MicrosoftVisual Basic脚本使用防火墙API,把6to4服务限制到端口500,只接受入站。

'requirevariable declarations

optionexplicit

'handleerrors

on errorresume next

'direction

ConstNET_FW_DIRECTION_IN = 1

' Createthe FwPolicy2 object.

DimfwPolicy2

SetfwPolicy2 = CreateObject("HNetCfg.FwPolicy2")

DimFwSvcRestr

SetFwSvcRestr = fwPolicy2.ServiceRestriction

'restrictservice

FwSvcRestr.RestrictService"6to4", "c:\windows\system32\svchost.exe", TRUE, TRUE

 

'Create anew restriction rule

DimNewRule

setNewRule = CreateObject("HNetCfg.FwRule")

NewRule.Name= "6to4 500"

NewRule.Description= "Allow 6to4 to receive TCP traffic on port 500"

NewRule.ApplicationName= "c:\windows\system32\svchost.exe"

NewRule.ServiceName= "6to4"

NewRule.Protocol= 6

NewRule.LocalPorts= "500"

NewRule.Direction= NET_FW_DIRECTION_IN

NewRule.Enabled= TRUE

'Add thebehavior rule to the WSH store.

fwPolicy2.ServiceRestriction.Rules.AddNewRule

会话0隔离

Windows把每个同时登陆的用户放到不同的会话里面,从而提供多用户登陆功能。系统启动中建立会话0,如果需要,还会建立更多会话。在Windows Vista之前的系统中,服务总是运行在会话0中,用户程序也可以运行在会话0中。比如,Windows XP激活快速用户切换(Fast User Switching, FUS)后,第一个登陆的用户被分配到会话0,这个用户的所有程序也运行在会话0下。第二个登陆到系统的用户就被分配到会话1上,如此等等。

1、服务和用户程序运行在同一个会话里,造成了很多安全问题。为了解决这个问题,WindowsVista对会话0作了两个重要的改变。

l  会话0被留用给那些所有与交互用户会话没有关系的服务和其他程序。用户程序必须运行在会话1上,或更高的会话上。

l  会话0不支用户界面。详细点说,运行在会话0上的程序没有权限使用图形硬件,不会在显示器上显示用户界面。

2、对于服务,会话0隔离还有很多隐含的意义,包括:

l  服务不能使用PostMessage或者SendMessage向用户程序发送消息。运行在会话1和其他会话上的程序都有不同的消息队列。同理,程序也不能向服务发送Windows消息。服务要给程序发送消息,必须利用一些类似于远程过程调用或者命名管道的机制。

l  具有用户界面的服务——比如有一个对话框——不能在Windows Vista中直接显示出来。服务只能间接的处理和用户的交互。对于简单的交互,服务可以调用WTSSendMessage,在用户的会话上显示一个消息窗。对于复杂的交互,服务必须调用CreateProcessAsUser或使用其他方法,在用户的会话上创建一个用户界面程序。这个界面程序处理用户的交互,并且使用远程过程调用户或者命名管道来个服务通信。

要取得更多有关Windows Vista中会话0的信息,以及编写WindowsVista服务的指导信息,请看本文档末尾“WindowsVista服务和驱动的会话0隔离带来的影响”一章。

性能的增强

延时自动启动

在WindowsVista之前,有两个启动服务的方法:自动启动和按需启动。自动启动的服务在系统引导的时候启动。有几种方法可以启动按需启动的服务,但这些都需要用户手动崇启这些服务。

1、把一个服务定义成自动启动服务,主要原因有两个:

l  这个服务必须在引导程序中较早的启动,因为其他服务依赖它。

l  管理员通常需要一些没有用户交互的服务无人值守地启动。这样保证在需要时,服务总是可用的。

自动启动服务的问题是,它们数量不断增加,影响了系统启动的速度。但是,很多服务属于上面两种原因中的第二种。它们并不需要成为系统引导队列的一部分;只是在系统启动完成之后,它们可以无人值守地启动,并且在需要时随时可用。

Windows Vista提供了一个不同的自动启动模式——延时启动,解决了在引导过程中,服务对性能的影响。被指定成为延时自动启动的服务会在系统启动完成后,自动启动。他们不会在系统引导的过程中自动启动,只是在系统引导完成后稍短的时间内启动。这样不仅提高了系统引导性能,还可以使服务无人值守地启动。

2、在把服务指定为延时自动启动之前,开发人员和管理员们应该考虑下面几个问题:

l  了解服务的依赖。如果因为另一个必须在引导过程中启动的服务依赖这个服务,就不要把这个服务标记成为延时启动服务。SCM会忽略标记设置而在引导过程中启动这个服务。

l  对于延时启动服务,没有明确的延时时间。如果用户程序在延时服务启动之前试图使用它,将会失败。如果用户程序依赖一个延时启动服务,它就应该处理这种失败情况,或者一段时间后重试,或者调用StartService启动服务。如果这样的失败情况总是发生,可能把服务设置成延时启动并不是一个好选择。

l  延时启动服务不属于装载顺序组(load-order group)。它们属于独立组(stand-alone)。

怎样服务指定为延时自动启动

要将创建一个延时自动启动服务,就设置延时自动启动标志。虽然所有服务都能设置这个标志,但它只对自动启动服务有效。如果自动启动服务被设置成为延时自动启动,那么在引导队列完成以后,它才会被启动。其他启动类型会忽略这个标志。

1、Sc.exe有两个支持延时自动启动的命令

delayflag。这个命令改变延时自动启动标志的设置。命令的语法为:

sc server delayflag [service name] [flag]

qdelayflag。这个命令查询延时自动启动标志的设置。命令的语法为:

sc server qdelayflag [service name]

2、通过程序设置延时自动启动标志,可以使用ChangeServiceConfig2函数,用下面的制作参数。改动会在下一次系统引导的时候生效。

l  将dwInfo设置为SERVICE_CONFIG_DELAYED_AUTO_START_INFO。

l  使lpInfo指向一个SERVICE_DELAYED_AUTO_START_INFO结构。这个结构包含一个布尔型变量,设置或者清除延时自动启动标志。

注意:具有SERVICE_CHANGE_CONFIG权限的调用者才可以修改延时自动启动标志。默认的,只有本地管理员,权力用户和服务器操作员能在远程取得这个权限。服务和交互用户可以在本地取得SERVICE_CHANGE_CONFIG权限。

服务状态改变的通知

在Windows Vista之前,使用服务查询API,比如QueryServiceStatusEx函数,来确定一个服务状态的变化,是被创建还是被删除;重复查询服务的状态。不断重复查询会降低系统的性能,所以它不是最好的方法。另外,重复查询也成为一个重要资源的BUG。

WindowsVista引入了一个新的函数,NotifyServiceStatusChange,这个函数允许SCM在服务被创建、删除、状态改变的时候给客户程序发出通知。

怎样在服务状态改变的时候得到通知

通过注册来取得状态变化通知,客户程序通过调用NotifyServiceStatusChange指定服务,改变它想要得到通知的服务。它们也向SCM提供了一个回调函数。

1、下面列出了一些使用NotifyServiceStatusChange应该注意的一项事项:

l  本地和远程客户程序都可以使用NotifyServiceStatusChange

l  回调函数只被调用一次。如果客户端想继续得到变化的通知,它必须再次调用NotifyServiceStatusChange,注册回调函数。

l  客户程序可以利用CloseServiceHandle关闭服务句柄,从而取消通知。

l  在回调函数被调用或者通知被取消之前,不要中止调用了NotifyServiceStatusChange的线程,否则将会发生内存泄漏。

l  如果有一个或几个服务持有一个服务的打开句柄,那么直到下一次系统启动,这个服务才会被删除。在这个情况下,不会发送删除通知。

注意:必须拥有SERVICE_QUERY_STATUS权限才能调用NotifyServiceStatusChange。默认的,只有管理员,权力用户和服务器操作员可以在远程取得这个权限。服务和交互用户可以在本地取得这个权限。

其他增强

WindowsVista还包含了一些其他的服务增强机制,它们增强了可靠性,使管理变得更加简单。

预关闭通知和关闭顺序

在Windows Vista之前,系统通知SCM计算机要关闭了。在系统中止SCM进程(services.exe)之前,SCM有大约20秒的时间去关闭所有运行中的服务。通常因为这个过程,服务都没有及时地关闭自己。

1、当SCM收到关闭通知以后,它以一个随机的顺序依次向每一个服务发送关闭请求。每一个服务都有一个等待时间点(wait hint),这个时间点指定SCM应该等待多长时间后,直接关闭这个服务。当SCM等待的时间超过这个等待时间点时,SCM就直接将服务关闭。这种关闭模式给服务带来了两个问题:

l  关闭顺序是随机的。如果有一个服务需要其他服务以一个特定的顺序关闭,那么,它可能不会被正确地关闭。

l  一些服务可能没有足够的时间作充分的清理工作。这个清理工作常常需要在服务再次启动的时候完成,这又会导致服务启动时间过长,或者数据不一致。

2、Windows Vista用两个方法来处理这些服务关闭问题:

l  SCM在发送真正的关闭通知之前先发送一个预关闭通知。预处理通知使得服务的关闭处理有了更长的时间,从而正确的关闭。

l  那些依赖于服务关闭顺序的服务,可以向全局依赖列表里添加任何依赖。

预关闭通知的工作方式和关闭通知很像。SCM以一个随机的顺序向注册过的服务发送预关闭通知。发送通知之后,SCM会在一个指定的时间量内等待服务停止,超过这个指定的时间量,SCM就认为服务没有响应。默认情况下,这个时间量为3分钟,但服务为了满足特别需要,也可以配置这个时间量。要取得更多信息,请看本文当最后“资源”中的“服务控制句柄和函数”一章。

服务可以在一个全局的依赖列表里面指定关闭依赖,在关闭一个服务之前,SCM首先尝试关闭依赖服务。要利用这个特点,就要为服务注册一个预关闭通知。

如果服务指定了依赖,关闭程序也会同时进行。比如,一个服务按照顺序指定对服务“A”、“B”、“C”的依赖。SCM向“A”发送一个通知后,等待它停止或超时。接着给“B”发送通知等等。如果这些服务中的任何一个没有注册预关闭通知或者没有正确关闭,SCM会直接处理下一个服务。

怎样注册一个预关闭通知

服务在它们的状态块中设置SERVICE_ACCEPT_PRESHUTDOWN来注册预关闭通知。预关闭通知只会发送给正在运行的并且已经注册了通知的服务,不会发送给处于SERVICE_STOPPED或者 SERVICE_STOP_PENDING状态的服务。

要设置超时时间值,调用ChangeServiceConfig2函数,并使用下面的参数:

       dwInfoLevel把这个参数设置成为SERVICE_CONFIG_PRESHUTDOWN_INFO

       lpInfo 让这个参数指向SERVICE_PRESHUTDOWN_INFO结构体,结构体中的dwPreshutdownTimeout成员就是超时时间值,毫秒级。

怎样声明关闭顺序

要声明关闭顺序,创建一个多字符值,这个值应该包含服务的名称,他们应该按照关闭的顺序排列。把这个多字符值赋给控制键的PreshutdownOrder,类似下面这样:

HKEY_LOCAL_MACHINE

  System

    CurrentControlSet

      Control

       PreshutdownOrder="Shutdown Order"

错误检测及恢复

如果一个服务启动失败了,SCM会进行一个错误处理(failure action),比如重新启动这个出错的服务,使之从错误中恢复。在WindowsVista之前的版本中,服务错误的定义仅限于,进程在任意状态下崩溃(不包含SERVICE_STOPPED状态)。在Windows Vista中,如果服务发现了一个不是致命的错误,比喻说内存泄漏。服务可以不必停止。它可以通知SCM做一些错误处理,从而恢复。

怎样配置错误处理

只有在服务显式的声明之后,SCM才会不断尝试错误处理。最常见的就是“重新启动这个服务”。这个动作需要两个值:

l  恢复时间(recovery interval):单位是毫秒,SCM在这个指定的时间过后,开始恢复动作。

l  重置时间(reset period):单位是秒,SCM在这个指定的时间过后,将错误计数置零。

配置错误处理的一个方法是利用sc.exe。下面的例子给出典型的语法:

sc.exe"failure" option, reset=300,

actions=restart/60000/restart/120000/restart/none

这条命令告诉SCM:

l  在第一次错误发生后,等待60秒,重新启动服务

l  在第二次服务发生后,等待120秒,重新启动服务

l  在第三次错误发生后,什么都不做。这时,另一个常用的错误处理是重新启动系统。要想重启系统,把"restart/none" 换成h "reboot/reboot_interval",SCM在等待reboot_interval毫秒后,重启系统。通常是60000。

l  在成功完成错误处理300秒后,将错误计数置零。如果reset被设置成为INFINITE,错误计数不会被重置。

编程配置错误处理,调用ChangeServiceConfig2函数,传递以下参数。配置将在下一次系统启动时生效。

l  将dwInfo属性设置成为SERVICE_CONFIG_FAILURE_ACTIONS

l  令lpInfo指向结构体SERVICE_FAILURE_ACTIONS。这个结构体包含一些错误处理的说明。

怎样使SCM不断尝试错误处理

WindowsVista包含一个新的标志:FailureActionsOnNonCrashFailures。如果服务想要SCM不断的尝试错误处理,就要设置这个标志。

要使用Windows Vista之前的模式,将FailureActionsOnNonCrashFailures设置为零。服务在非SERVICE_STOPPED状态发生错误时,SCM才会开始错误处理。

FailureActionsOnNonCrashFailures设置成1,告诉SCM对一个服务不断尝试错误处理:

l  服务进入SERVICE_STOPPED状态,并且将SetServiceExitCode的参数dwWin32ExitCode设置成ERROR_SUCCESS以外的值后,SCM开始错误处理。

l  如果服务在非SERVICE_STOPPED状态时崩溃,SCM依照WindowsVista之前的模式开始错误处理。

注意:要使FailureActionsOnNonCrashFailures生效,必须配置服务的错误处理。

Sc.exe有两条新命令可以设置FailureActionsOnNonCrashFailures:

Failureflag,这条命令设置FailureActionsOnNonCrashFailures标志,语法如下:

sc server failureflag [service name] [flag]

qfailureflag,这条命令取得FailureActionsOnNonCrashFailures的值。语法如下:

sc server -qfailureflag [service name]

编程设置FailureActionsOnNonCrashFailures标志,调用ChangeServiceConfig2函数,传递以下参数:配置将在下一次系统启动时生效。

l  将dwInfo设置成SERVICE_CONFIG_FAILURE_ACTIONS_FLAG

l  令lpInfo指向结构体SERVICE_FAILURE_ACTIONS_FLAG。这个结构体只有一个布尔类型的成员fFailureActionsOnNonCrashFailures,设置或清除错误处理标志。

注意:程序有SERVICE_CHANGE_CONFIG权限时,才能改变FailureActionsOnNonCrashFailures标志。


资源

下面链接提供了Windows服务以及相关的信息。

MSDNWindows服务文档

http://go.microsoft.com/fwlink/?LinkId=71274

Windows Vista中,Session0隔离对服务和驱动带来的影响

http://go.microsoft.com/fwlink/?LinkId=71275

因特网连接共享与因特网连接防火墙

http://go.microsoft.com/fwlink/?LinkId=71277

NotifyServiceStatusChange

http://go.microsoft.com/fwlink/?LinkId=71279

服务控制处理程序

http://go.microsoft.com/fwlink/?LinkId=71282

0 0