WindowsService(简称服务,下同)是目前做客户端软件后台运行功能的非常好的选择,本文基本解决了服务的创建和编写,代码控制服务的安装、卸载、启动、停止等,为服务传递参数,其他注意事项等。
1 服务的创建和编写
①在Add Project
选择Windows Service
创建项目,同时添加一个Windows Service类,在这里以IFUploaderService.cs
为例
②在设计器中右键选择Add Installer
,如图
③在生成的ProjectInstaller的设计器中设置
serviceProcessInstaller控件的属性 Account:LocalSystem (这样不论是以哪个用户登录的系统,服务总会启动)
serviceInstaller控件的属性
- DisplayName:在系统服务管理界面显示的服务名称,根据你的程序命名,如图
- Description:在系统服务管理界面显示的服务描述,根据你的程序填写
- ServiceName:服务的真实名称,在系统中应该是唯一的,这也是接下来用程序控制服务的关键
- StartType:服务的启动类型,有自动、手动、和禁用
④打开IFUploaderService.cs
,代码中的OnStart和OnStop事件将在服务开启和结束时执行
为了实现定时执行的功能,你可以在OnStart中添加一个Timer,比如我要在每天8点执行自动上传功能,代码如下
1 | protected override void OnStart(string[] args) |
⑤Build项目,注意服务项目不能直接执行,接下来手动安装服务:
- 复制Build生成的exe文件的完整路径
- 打开Visual Studio Command Prompt(VS命令提示符),执行installutil Build后的exe文件路径,比如
installutil D:\EGFIS_IF\Eland.GEPS.POSIF.WinService\bin\Debug\Eland.GEPS.POSIF.WinService.exe
同理,卸载服务的命令是installutil /u Build后的exe文件路径
⑥调试时只需要在vs中附加项目生成的服务exe的进程即可
2 代码控制服务的安装、卸载、开启、关闭等
1 | using System; |
3 为服务传递参数
有时,我们在启动服务时需要设定一些参数,但这些参数如何从调用服务的程序传递给服务呢?
细心的朋友可能已经发现,在第2节中的启动服务方法,需要传递参数param,这是因为ServiceController.Start
有两个重载,一个无参数,一个可以传递字符串数组作为参数,这个参数将在服务启动时被OnStart方法接收,这样就实现了为服务传递参数。
4 其他注意事项
①服务安装后被安装的exe文件就被锁定,此时再Build项目将报错,正确的方法是先卸载手动服务,再重新build
②首先明确概念:
- 当前工作目录——进行某项操作的目的目录,会随着openfiledialog、filestream等对象所确定的目录而改变。
- 当前执行目录——该进程从中启动的目录,即文件自身所在目录。
工作目录与执行目录可以不同,例如一个人住在北京,但他的工作地点不一定在北京,可能在天津。
服务安装后其工作目录将变为C:\Windows\system32
,因此如果要使用OpenFileDialog
、FileStream
等System.IO
命名空间下的类和方法,并且使用相对路径,请先将工作目录设置到你想要的位置。而此时执行目录还是exe文件所在的文件夹,所以可以赋值给工作目录。
③服务中使用工具箱生成的Timer控件,其事件将不会被触发,因此应该手写Timer控件及其事件,如本文第1节中的代码
④服务已经安装,但服务的执行文件发生了变化,此时可能出现卸载不掉的情况
可以以管理员方式打开CMD,执行以下命令卸载服务:sc delete 服务名