编写Windows服务疑问1:操作过程

Windows 服务开发平时不太受人关注,毕竟那是高大上的项目类型,平常需求也用不上,很多老掉牙的家伙也只知有WinForm,仍不知有WPF,更别说Windows 服务了,正如淘渊明所写的,“不知有汉,无论魏晋”。

通常,就算要让程序开机启动,多数也只考虑设置一个启动项,也很少去想到开发Windows服务。如果程序需要自动启动,并且希望在后台完成一些东东,其实使用Windows服务也不错的。

正因为用的人少,那么说的人更少了,使得不了解它,想学又找不到资料的人也多。没事,老周没什么资本,唯一值得骄傲就是颜值低,尤其是脸皮长得稍厚一些,所以,就让老周写几篇烂博客,看看能不能给大家解惑,传道授业愧不敢当,解几个简单的惑还是可以的。

其实,Windows服务也是一个Windows标准程序,也是编译为.exe的,运行时在任务管理器中也是有进程的,但它与一般的可执行文件也有不同,至少你不能直接双击运行服务。服务隶属于系统对象,因此在你运行服务前,需要向系统注册它。就好比你坐公交要先买票一样(包括刷卡,无人售票等),当然,个别另类人种是不买票的,后门上再从后门下。

一个服务项目可以包含多个服务,就是说你建立一个应用程序项目,你可以在里面根据你的需要,声明多个服务。实现服务的方法是从ServiceBase派生出一个自定义的类,然后重写相关的虚方法,来定义你的代码,当然,不是全部虚方法都要重写,你只写你觉得需要的方法。不要问我ServiceBase类在哪个命名空间,自己打开“对象浏览器”去找,“对象浏览器”是个好用的东西,老周每天都会看它一眼,特别好看,比你到网上下载的那些文笔拙劣的垃圾小说好看,不信你去看看。

举个地球人都知道的例子,假设你需要在服务启动时打开某个端口,去监听客户端的连接请求,那么,你可以重写OnStart方法;当服务被停止时关闭监听,重写OnStop方法;当服务被暂停时向所有客户端发送一条服务器放假的消息,请重写OnPause方法;如果你希望在关机的时候做一些处理,比如清空犯罪痕迹,可以重写OnShutdown方法,当系统即将关机,并且你的服务还在运行的时候,这个方法就会被调用。

扯的太空洞了,是吧,那就来点年货,反正也快过年了。咱们就从头到尾做一遍,看看你能不能掌握。

要上厕所的赶紧上,下面开始干活。

1、在VS中新项一个空项目,我知道VS中就有Windows服务的项目模板,但,为了让大伙伴能够更好地理解,咱们从空白开始。

2、因为项目是空的,所以里面连毛都没有,为了让项目看起来比较像样,先来设置一下项目的基本属性,估计这个很少人会注意,因为平时我们建项目时,连属性文件都由VS帮我们建好了。在项目节点上右击,选择属性。然后在应用程序页上,填好需要的东西,你可以随便填,不用客气。

注意,在输出类型那里选择“Windows应用程序”,不要选控制台应用程序,因为服务是没有界面的,就是一个进程。而且,在Win 7以上的系统中(其实是Vista时代就是了),是禁止服务和桌面交互的。我也赞成这样做,老周特别讨厌那些服务动不动就弹出个窗口,相当恶心。服务进程就是做逻辑处理的,BS有UI的服务。

3、点击“程序集信息”按钮,填上相关信息,自己喜欢填什么就填什么。

填完后确定,就会自动生成AssemblyInfo.cs文件。然后保存并关闭项目属性窗口。

4、添加下面三个引用,不用我教了。先加这么几个,等不够用时再加。

5、好,现在可以开始了,我们来做第一个服务,服务名称叫HuiJi,显示名为“灰机”.

    public class HuiJiService : ServiceBase
    {
        public HuiJiService()
        {
            ServiceName = "HuiJi";
        }

        protected override void OnStart(string[] args)
        {
            Trace.WriteLine($"{this.ServiceName} - 正在起飞。");
        }

        protected override void OnStop()
        {
            Trace.WriteLine($"{this.ServiceName} - 正在降落。");
        }
    }

由于ServiceName属性是ServiceBase类的公共属性,所以,你可以像我这样,在类的构造函数中设置,也可以不设置,等到在Main入口点中实例化HuiJiService时再赋值,公共属性在类外部可以访问。

6、好,这么个简单的服务做好了,然后我们要在Main入口点中运行它。

        static void Main()
        {
            SV.HuiJiService hj = new SV.HuiJiService();
            // 调用静态方法运行指定服务
            ServiceBase.Run(hj);
        }

一定要记住,在Main中要调用Run静态方法来运行你想要运行的服务,这个很重要,不要忘了。如果只有一个服务,就只传一个服务实例给它,如果你要运行N个服务,就传一个服务数组进去。

那么,是不是这样就能运行了呢。非也,虽然我们写好了服务,但操作系统不知道你这是啥玩意儿,你得写安装程序类,这样在向系统注册时,安装工具才会去查找安装器,对服务进行安装。

7、服务需要两个(至少)安装器,一个是安装服务本身,另一个用来安装服务进程。要注意的是,服务和服务进程是不同的,服务就是我们刚刚写的从ServiceBase类派生的那个,而服务进程就是我们这个应用的.exe文件运行时的进程。

哪怕你只有一个服务,至少也有两个安装器——服务和服务进程。如果有三个服务要安装,就要定义四个安装器(三个服务安装,一个进程安装),每个服务安装器只能对应一个服务。

正因为要>=2安装器,所以要从Installer类派生出来一个类,在里面实例化好各种安装器,然后统一加入到Installers集合中,这样,在安装服务时,安装工具就会自动扫描这个集合里面的安装器,逐个进行安装。

    public class MyInstaller : Installer
    {
        ServiceInstaller svinstaller = null; //服务安装器
        ServiceProcessInstaller processinstaller = null; //进程安装器
        public MyInstaller()
        {
            // 实例化安装器
            svinstaller = new ServiceInstaller();
            // 设置的服务名称必须和自定义服务的名字相同
            svinstaller.ServiceName = "HuiJi";
            // 服务描述
            svinstaller.Description = "23世纪触发式新型飞机。";
            // 设置显示名称
            svinstaller.DisplayName = "飞机";
            // 启动方式为自动
            svinstaller.StartType = ServiceStartMode.Automatic;
            // 实例化进程安装器
            processinstaller = new ServiceProcessInstaller();
            // 设置帐户类型为本地系统,通常用这个
            // 如果是远程服务,应指定登录的用户名和密码
            processinstaller.Account = ServiceAccount.LocalSystem;

            // 把安装器添加到集合中
            this.Installers.Add(svinstaller);
            this.Installers.Add(processinstaller);
        }
    }

安装服务用ServiceInstaller,而且,必须必须注意,安装器上ServiceName指定的服务名字,必须要和刚才在Main中运行的服务的名字相同,不然,无法正确安装,也无法启动服务。

刚才我们定义服务的名字叫 HuiJi,所以这里也要指明为 HuiJi。

服务进程要用 ServiceProcessInstaller 来安装,实例化后,要指定它的帐户类型,对于在本机运行的服务,用LocalSystem就可以了(本地系统帐户)。一个应用程序用一个ServiceProcessInstaller就可以了,你用多个也没用,不信你可以试试在 Installers 集合中添加N个 ServiceProcessInstaller 实例,最后你发现,只有第一个进去的才会有效,其他的靠边站。而且,一个应用程序安装多个服务进程也没什么用。

最后,不要忘了把两个安装器添加进 Installers 集合中。

8、最关键一步,在刚铡定义的自定义安装类上应用RunInstaller特性,并且把参数设为true,这样做表示这个类是用于给安装工具发现,并且扫描安装的,这一步不能少,少了就无法安装。

    [RunInstaller(true)]
    public class MyInstaller : Installer
    {

好了,包含一个服务的应用程序做好了,下面看看如何注册和运行它了。

首先,生成应用项目,不要直接运行,因为它不是普通的.exe。

然后,要知道,安装服务用到一个叫 InstallUtil.exe 的工具,这个工具在 C: \ Windows \ Microsoft.NET \ Framework 下面,自己去找。找到了随便你怎么弄,最把这个exe所在目录加入到系统变量path中,这样,你就很轻松地用了。

到项目生成目录 \ bin \ Debug 下面,确认已成功生成了.exe 文件,然后在文件管理器左上角的菜单中 文件 ,“打开命令提示符” -- 以管理员身份打开命令提示符。

然后输入installUtil xxxx.exe ,回车。如图。

看到提示安装成功,说明服务已经装上了。现在打开系统的本地服务管理器窗口,可以看到刚才的服务了。

现在,你可以启动和停止服务了。

我们刚刚是通过Trace来输出跟踪信息的,那如何调试呢。

首先,关掉VS,再以管理员身份运行VS,然后再打开你的项目。

接着,到服务管理器中,启动服务。

回到VS,执行菜单 调试 -- 附加到进程。选择我们服务应用程序的进程。

然后附加调试器,接着再把服务停止,再启动,你就会看到 输出 窗口中的跟踪信息了。

测试完后,可以把刚刚的服务卸载掉,你可以用 sc delete 服务名 命令来删掉。不过,最好还是用刚才的 installUtil 工具来卸载。很简单,只要加一个 /u 参数就可以了。比如:installUtil /u xxxx.exe。

然后,你再到服务管理器窗口刷新一下,刚刚的服务就不见了,被卸载了。

做完这个练习后,你应该知道 Windows 服务怎么耍了,至少基本的步骤你懂了。

示例源代码  :http://files.cnblogs.com/files/tcjiaan/sampleServiceapp.zip

时间: 2024-10-29 19:11:22

编写Windows服务疑问1:操作过程的相关文章

编写Windows服务疑问2:探索服务与安装器的关系

首先,来弄两个服务,一个叫“飞机”,一个叫“火车”. public class FeiJiService : ServiceBase { public FeiJiService() { ServiceName = "Fei_ji"; } } public class HuoCheService : ServiceBase { public HuoCheService() { ServiceName = "Huo_che"; } } 用于演示,服务很单,接着,匹配安装

使用C语言编写windows服务一般框架

原文:使用C语言编写windows服务一般框架 编写windows服务和编写windows应用程序一样,有一些回调函数必须填写且向windows 服务管理器(service manager)进行注册,否则会导致服务启动失败.因近期写个服务,其中遇到一些有问题,有部分内容想和大家分享一下,请大家指正. windows服务一般框架代码如下: #include <Windows.h> #include <tchar.h> VOID WINAPI ServiceHandler(DWORD

c# 编写windows 服务,并制作安装包

对服务的认识有很多个阶段. 第一阶段:当时还在用c++,知道在一个进程里while(True){},然后里面做很多很多事情,这就叫做服务了,界面可能当时还用Console控制台程序. 第二阶段:知道了服务要在后台执行,一般不会有界面显示,并且开机自启动,于是隐藏Console控制台界面,并且通过使用SC CREATE 将exe变为服务,并且达到开机自启动的目的.这时候还是c++ 阶段. 第三阶段:因项目需求接触c#,发现有个叫项目模板专门制作windows 服务,尝试了下,感觉还不错,省事了许多

用c语言编写windows服务

主要是根据从www.vcbase.com上看到的一篇文章来做这个windows服务的.但是这篇文章一些关键代码并没有贴出来,然而有心人根据作者的描述实现了代码,并且完整的贴了出来,地址是在 http://www.2cto.com/kf/201111/111990.html 我创建的是一个空项目,这个默认的应该是控制台项目.服务的主函数是main而不是winmain,要写一个服务首先要初始化一个SERVICE_TABLE_ENTRY 分派表结构体的列表,然后调用StartServiceCtrlDi

C#编写Windows服务

一.Windows服务介绍: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一 般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式.这些启动方式包括了自动启动和手动启动两种.对于自动启动的Windows服务程序,它 们在Windows启动或是重启之后用户登录之前就开始执行了.只要你将相应的Windows服务程序注册到服务控制管理器(Service Control Manager)中,并将其启动类别

C# 编写Windows服务并设置为“允许服务与桌面交互”

本文信息来源于网络,本人只是汇总. VS创建项目,项目类型选择Window服务 为服务创建安装程序 1.. 返回到 Service1 的"设计"视图. 2.. 单击设计器的背景以选择服务本身,而不是它的任何内容. 3.. 在"属性"窗口中,单击属性列表下面灰色区域中的"添加安装程序"链接. 默认情况下,向您的项目添加包含两个安装程序的组件类.将该组件命名为 ProjectInstaller,它包含的安装程序分别是服务的安装程序和服务关联进程的安装

【JavaService】使用Java编写部署windows服务

如果你玩windows系统,你对服务这个东西并不会陌生,服务可以帮我们做很多事情,在不影响用户正常工作的情况下,可以完成很多我们需要的需求. 众所周知,微软的visio studio内置的Service类可以编写windows服务,对于一个Java开发人员来说,想要编写一个windows服务部署到服务器里面, 还要在自己的开发环境装一个visio studio,那太麻烦了. 那么问题来了,我想用java编写一个windows服务,这个想法可行吗?答案是肯定的,可行! 开源的JavaService

使用C#创建及调用WCF完整实例 (Windows服务宿主)

关于WCF的概念.原理.优缺点等,在这里就不多说了,网上很多,可以自行搜索,比我解释的要专业的多. 这里直接说使用Windows 服务(Windows Service)作为宿主如何实现,其它方式不在此次教程之内 文章最后有本例的下载连接,包含源代码.说明教程.编译后文件 实例环境:Windows Server 2008 R2 + VS 2010(C#) 打开 VS 2010,选择 新建项目,选择 ”WCF”|”WCF 服务库 ”,注意这里是”WCF 服务库 ”,不是"WCF 服务应用程序&quo

Windows服务(system权限)程序显示界面与用户交互,Session0通知Session1里弹出对话框(真的很牛) good

源码资源下载:http://download.csdn.net/detail/stony1980/4512984 1.VC2008中编写“Windows服务”(Windows Service)程序 vc2008下新建一个 ATL 项目-> 选择创建一个“服务”类型的ATL 项目TestService,将生成如下代码, class CTestServiceModule : public CAtlServiceModuleT< CTestServiceModule, IDS_SERVICENAME