![f5c4e31cdc157d09bedb8a185e5326eb.png](https://img-blog.csdnimg.cn/img_convert/f5c4e31cdc157d09bedb8a185e5326eb.png)
移花接木
在上一篇文章《限制程序只能同时启动一个实例-唯一》中,我们详细讨论了在Windows中,将软件设置为开机启动的方法。从而实现保护程序开机的时候自动保护服务的运行。
有的时候,我们没有某个控制台程序的源代码,但是我们需要一直运行这个控制台程序。而且这个控制台程序是静默运行的,不需要用户参与任何交互。
比如我们需要用到其提供的某些功能,并且不能停止运行。
这个时候,如果我们以控制台的形式启动这个程序,会有两个问题:
- 控制台窗口,容易被关掉
- 如果不小心选中了控制台里面的内容,程序会暂停运行
那如何解决这个问题呢?
编写简单的控制台程序
先来创建一个C#控制台项目:
![109f98cfd76384616bcd891b075c1c32.png](https://img-blog.csdnimg.cn/img_convert/109f98cfd76384616bcd891b075c1c32.png)
创建项目
我们就用上次的保护进程的逻辑代码,来演示控制台程序转服务。
控制台程序代码如下:
![445b98740ea7b3a9e97f9aba47a39e59.png](https://img-blog.csdnimg.cn/img_convert/445b98740ea7b3a9e97f9aba47a39e59.png)
程序代码
经过外老师测试,控制台程序内部,不管是不是使用了后台线程,都不影响转服务。只要控制台程序在运行即可。采用后台线程运行的时候,通过Console.ReadKey类似的方式,保持程序持续运行即可。
同样,因为我们这个控制台程序需要启动服务,所以也需要管理员权限。我们在项目的【属性】中,在【安全性】选项卡里面,启用【Click Once 安全设置】,再关闭【Click Once 安全设置】,最后修改其配置文件【app.manifest】:
![d8cc4e5bfe8420371760b3772c663044.png](https://img-blog.csdnimg.cn/img_convert/d8cc4e5bfe8420371760b3772c663044.png)
请求管理员权限
这样我们的程序启动之后,就可以启动服务了。
我们编译程序,然后直接运行,检验一下是否可以正常守护服务:
![b595406aade92b8577b89b2e7b29c36f.png](https://img-blog.csdnimg.cn/img_convert/b595406aade92b8577b89b2e7b29c36f.png)
正常启动
然后结束掉服务进程,看进程能否重启:
![bcf5f46273650eea9ca9c83a26f9165f.png](https://img-blog.csdnimg.cn/img_convert/bcf5f46273650eea9ca9c83a26f9165f.png)
检验保护效果
经过外老师测试,功能正常。那么我们的控制台程序就写好了。
控制台转服务
现在来想办法将上面的控制台程序转换为服务运行。外老师尝试了3种办法,最后才成功:
- sc create 直接创建服务
- 使用srvany来转换
- 使用一个开源项目RunAsService来转换
前面两种,最终未能成功,但是第三种,终于成功了。前面两种失败的过程,在后面的踩坑记录里面简单介绍,这里我们重点介绍第三种!
由于第二种svrany是比较常用的方法,但是经过我一番尝试,最终失败。
无奈只好求助于程序员的万能朋友圈github,最后找到一个项目【RunAsService】,经过尝试,最后终于成功!
![da4c73c2057b05a21bd6e5ab376f8927.png](https://img-blog.csdnimg.cn/img_convert/da4c73c2057b05a21bd6e5ab376f8927.png)
RunAsService
将这个仓库克隆下来,然后编译,然后研究了一下其运行方式:
RunAsService也需要先以服务的形式运行起来:
![20b4f5f9153fcbb2942d1d563883ee1a.png](https://img-blog.csdnimg.cn/img_convert/20b4f5f9153fcbb2942d1d563883ee1a.png)
安装RunAsService服务
然后在【RunAsService.xml】中配置需要转换为服务的控制台程序:
![61e58b2294a691b4c9c253bf37769495.png](https://img-blog.csdnimg.cn/img_convert/61e58b2294a691b4c9c253bf37769495.png)
配置程序
其中的【CmdLine】为最重要的控制台程序启动命令。再配置好服务的描述和启动方式。然后就可以启动【RunAsService】服务来启动这里配置的控制台程序了:
![72e1143dc84fc944b6be44b9dba028f3.png](https://img-blog.csdnimg.cn/img_convert/72e1143dc84fc944b6be44b9dba028f3.png)
启动RunAsService
然后我们再测试,是否能够保护服务:
![5e507344f4c736271016aead8ddcdd7b.png](https://img-blog.csdnimg.cn/img_convert/5e507344f4c736271016aead8ddcdd7b.png)
保护测试
测试结果正常,结束掉进程【TestService】之后,迅速重启。
这里外老师还发现一个小惊喜,就是【RunAsService】本身,也具备保护进程的效果。它可以保护【TestConsole】这个控制台程序。
不得不说【RunAsService】功能还是蛮强大的。后面有机会,给大家分享一下其源代码,探索一下其背后的深层原理。
踩坑记录
刚开始尝试了网上的一种办法,使用 sc create 来创建服务:
sc create SvcProtectorConsole binpath= F:WeMedia01付费专栏C#-Windows服务全面开发win-serviceSrcTestServiceTestConsolebinDebugTestConsole.exe type= own start= auto displayname= SvcProtectorCsl
但是经过测试,这种方法,只适用于以服务的形式编写的程序,对于普通的控制台程序,并不适用。
普通程序,在启动服务的时候会报错。
当然不排除有解决的办法,但是目前外老师还没找到方法。
srvany尝试失败,目前原因未知
参考:https://wangye.org/blog/archives/42/
下期预告
RunAsService背后的原理
敬请期待。。。
下一篇文章《控制台转服务背后的秘诀》,欢迎检阅!