Windows服务程序开发介绍

来源:互联网 发布:赖昌星 红楼 知乎 编辑:程序博客网 时间:2024/04/30 15:45

一、什么是服务程序?

Windows Service 是主要用于服务器环境而长期运行的应用程序, 这类程序不需要有用户界面或者任何模拟输出。 任何的用户消息通常都是记录在Windows 事件日志里。
Windows Service可以在操作系统启动的时候开始,一直在后台运行;当有需要时也可以手动启动,我们可以通过管理工具里面的服务进行统一管理;也可以通过程序控制服务程序的启动与停止。

二、服务程序的三个关键函数

main()函数

服务程序像必须提供一个入口函数,就是通常所说的main()函数。main()可以提供安装或者卸载服务的功能,也可以不提供。

但main()函数必须调用StartServiceCtrlDispatcher()这个API函数来注册服务主函数ServiceMain ()函数。
调用完成之后,main()函数应该返回而不是调用while(TURE)循环进行等待(在普通程序中调用while(TURE)可防止进程结束)。原因是main()函数返回之后,服务控制器(SCM)会调用服务进程注册的ServiceMain ()函数。

服务程序必须实现ServiceMain ()函数。这个函数由服务控制器(SCM)调用,SCM会创建一个新进程,然后转到ServiceMain()开始执行,所以ServiceMain()函数中必须调用while(TRUE)函数进行循环,否则进程很快就会退出。

ServiceMain()函数

ServiceMain()函数应该RegisterServiceCtrlHandler注册ServiceCtrlHandler()函数。SCM要求ServiceMain()函数的线程在一秒钟内调用RegisterServiceCtrlHandler函数,否则SCM会认为服务已经失败。
ServiceMain()函数应该调用SetServiceStatus(SERVICE_RUNNING)这个API函数,将服务状态设置为正在运行,并且应该在ServiceMain()函数中尽快完成(大多数系统上是30秒,这个值记录在记录在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control 子键里面的
WaitToKillServiceTimeout,单位是毫秒。 )。因为在启动服务后,SCM会在一定时间内(大多数系统上是30秒)等待服务状态变为SERVICE_RUNNING状态。若规定时间内服务状态未改变,SCM就会引发ERROR_SERVICE_REQUEST_TIMEOUT错误,然后终止相关服务进程。

ServiceCtrlHandler()函数

像ServiceMain()一样,ServiceCtrlHandler()也是一个回调函数,用户必须为它的服务程序中每一个服务写一个单独的ServiceCtrlHandler()函数。SCM可以调用ServiceCtrlHandler()函数来进行服务状态的切换。比如在SERVICE_CONTROL_CONTINUE、SERVICE_CONTROL_STOP、SERVICE_CONTROL_PAUSE之间进行切换。

三、服务的安装过程

如果要安装一个服务,可以调用CreateService ()这个API函数,其参数含义如下:

lpServiceName 是服务的名字,lpDisplayName 是服务在“服务”管理工具里显示的名字。

dwDesiredAccess 也是访问的权限,选项有很多,具体可以查MSDN 。要安装服务,简单的传递SC_MANAGER_ALL_ACCESS。

dwServiceType 是指你的服务是否和其它的进程相关联,
SERVICE_WIN32_OWN_PROCESS,表示ServiceMain ()函数单独运行一个新进程中。如果设置成SERVICE_WIN32_SHARE_PROCESS,表示ServiceMain ()函数与其它服务共同运行在一个进程中。SERVICE_KERNEL_DRIVER和SERVICE_FILE_SYSTEM_DRIVER这两个参数表示安装的是内核驱动程序,与服务没有太大关系。

dwStartType 是服务的启动方式。服务有三种启动方式,分别是“自动(SERVICE_AUTO_START)”“手
动(SERVICE_DEMAND_START)”和“禁用(SERVICE_DISABLED)”。
还有另外的两种方式SERVICE_BOOT_START和SERVICE_SYSTEM_START,只能用于驱动程序安装。

dwErrorControl 决定服务如果在系统启动的时候启动失败的话要怎么办。
值 意义
SERVICE_ERROR_IGNORE 启动程序记录错误发生,但继续启动。
SERVICE_ERROR_NORMAL 启动程序记录错误发生,并弹出一个消息框,但仍继续启动
SERVICE_ERROR_SEVERE 启动程序记录错误发生,如果是以last-known-good
configuration 启动的话,启动会继续。否则会以
last-known-good configuration 重新启动计算机。
SERVICE_ERROR_CRITICAL 启动程序记录错误发生,如果可能的话。如果是以

last-known-good configuration启动的话,启动会失败。否则
会以last-known-good configuration重新启动计算机。

lpBinaryPathName是服务程序的路径。MSDN里面特别提到如果服务路径里面有空格的话一定要将
路径用引号引起来。例如”d:\my share\myservice.exe”就一定要指定为”\”d:\my share\myservice.exe\”“。

lpLoadOrderGroup的意义在于,如果有一组服务要按照一定的顺序启动的话,这个参数用于指定一个
组名用于标志这个启动顺序组,不过我还没有用过这个参数。你的服务如果不属于任何启动顺序组,只要
传递NULL或者一个空的字符串就行了。

lpdwTagId是应用了上面的参数之后要指定的值,专用于驱动程序,与本文内容无关。传递NULL。

lpDependencies标示一个字符串数组,用于指明一串服务的名字或者一个启动顺序组。当与一个启动
顺序组建立关联的时候,这个参数的含义就是只有你指定的启动顺序组里有至少一个经过对整个组里所有
的成员已经全部尝试过启动后,有至少一个成员成功启动,你的服务才能启动。不需要建立依存关系的话,
仍是传递NULL或者一个空的字符串。但如果你要指定启动顺序组的话,必须为组名加上
SC_GROUP_IDENTIFIER前缀,因为组名和服务名是共享一个命名空间的。

lpServiceStartName是服务的启动账号,如果你设置你的服务的关联类型是
SERVICE_WIN32_OWN_PROCESS的话,你需要以DomainName\UserName的格式指定用户名,如果
这个账户在你本机的话,用.\UserName就可以指定。如果传递NULL的话,会以本地的系统账户登陆。如
果是Win NT 4.0或更早的版本的话,如果你指定了SERVICE_WIN32_SHARE_PROCESS,就必须传
递.\System指定服务使用本地的系统账户。最后,如果你指定了SERVICE_INTERACTIVE_PROCESS,
你必须使服务运行在本机系统账户。

CreateService ()这个API函数调用成功之后,会在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\ 下面添加与服务相关的新子项,保存了服务的相关信息。如果安装的是内核驱动,也会在这个位置生成新的子项。

0 0