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

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

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

    首先,来弄两个服务,一个叫“飞机”,一个叫“火车”. public class FeiJiService : ServiceBase { public FeiJiService() { Service ...

  2. C#编写windows服务

    项目要求: 数据库用有一张表,存放待下载文件的地址,服务需要轮训表将未下载的文件下载下来. 表结构如下: 过程: VS--文件-->新建项目-->windows-->windows服 ...

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

    原文:使用C语言编写windows服务一般框架 编写windows服务和编写windows应用程序一样,有一些回调函数必须填写且向windows 服务管理器(service manager)进行注册, ...

  4. C#编写Windows 服务

    C#编写Windows 服务 Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时 ...

  5. python实现编写windows服务

    使用python编写windows服务 最近测试服务器上经常发生磁盘空间不足,每次手动清除比较麻烦,所以写个windows服务定时清理下.中间也遇到过几个坑,一起记录下来. 1.python实现win ...

  6. C# 编写windows服务及服务的安装、启动、删除、定时执行任务

    一.编写windows服务 1.VS2017  - 创建服务Myservice 2.创建好项目之后 --- >> 双击 Service1.cs  ---- >>  出现一个设计 ...

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

    对服务的认识有很多个阶段. 第一阶段:当时还在用c++,知道在一个进程里while(True){},然后里面做很多很多事情,这就叫做服务了,界面可能当时还用Console控制台程序. 第二阶段:知道了 ...

  8. 手把手教用C#编写Windows服务 并控制服务 安装、启动、停止、卸载

    Windows服务 Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时自动启动, ...

  9. 第八篇--编写Windows服务

    编写service服务参考网址:https://blog.csdn.net/nodeathphoenix/article/details/24181509 vc获得显示器状态(捕获息屏.亮屏网址):h ...

随机推荐

  1. 漫扯:从polling到Websocket

    Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...

  2. SSH实战 · 唯唯乐购项目(上)

    前台需求分析 一:用户模块 注册 前台JS校验 使用AJAX完成对用户名(邮箱)的异步校验 后台Struts2校验 验证码 发送激活邮件 将用户信息存入到数据库 激活 点击激活邮件中的链接完成激活 根 ...

  3. Web APi之认证(Authentication)两种实现方式【二】(十三)

    前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...

  4. 谈谈JS中的函数节流

    好吧,一直在秋招中,都没怎么写博客了...今天赶紧来补一补才行...我发现,在面试中,讲到函数节流好像可以加分,尽管这并不是特别高深的技术,下面就聊聊吧! ^_^ 备注:以下内容部分来自<Jav ...

  5. [原][Docker]特性与原理解析

    Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...

  6. 在.NET Core之前,实现.Net跨平台之Mono+CentOS+Jexus初体验

    准备工作 本篇文章采用Mono+CentOS+Jexus的方式实现部署.Net的Web应用程序(实战,上线项目). 不懂Mono的请移步张善友大神的:国内 Mono 相关文章汇总 不懂Jexus为何物 ...

  7. RabbitMQ + PHP (一)入门与安装

    RabbitMQ: 1.是实现AMQP(高级消息队列协议)的消息中间件的一种. 2.主要是为了实现系统之间的双向解耦而实现的.当生产者大量产生数据时,消费者无法快速消费,那么需要一个中间层.保存这个数 ...

  8. 我的屌丝giser成长记-工作篇之B公司

    从A公司跳槽到B公司,岗位还是webgis开发方向,但是具体实现的技术完全变了,从flex转换js,这也是我要离开A公司的最重要的原意之一:A公司的arcgis for flex框架采用了flexvi ...

  9. SharePoint 2016 入门视频教程

    之前一直有朋友让自己录一些SharePoint的入门视频,之前没有太多时间,一个巧合的机会收到CSDN学院的邮件,可以在CSDN上发布视频教程,自己就录了一些.说起录视频也是蛮辛苦的,每天下班吃完饭要 ...

  10. 关于Linux和Windows下部署mysql.data.dll的注册问题

    mysql ado.net connector下载地址: http://dev.mysql.com/downloads/connector/net/ 选择版本: Generally Available ...