当前位置: 首页 > news >正文

Windows服务(Service)安装及启动停止方案

目录

一、创作背景

二、问题解决

2.1 安装Windows service服务

2.2 主方法Main()主方法改写

2.3 安装service服务/卸载service服务

2.4 服务启停

2.5 服务调用运行

2.6 关于权限的提升

三、资源分享

3.1 引入组件

3.2 新手使用


一、创作背景

今天,我们完成了一个应用程序的开发,我们要将其设置成开机自启程序,继上篇文章介绍有两种方式。

一种,开机启动目录下创建应有程序的快捷方式;

另一种,写Windows服务;我们现在采用“服务方式自启程序”。

因为用户不具备管理员权限,为了安全考虑,我们方便监控管理。最终确认方案二。

先说说我们面临的问题,或者说是待解决的问题:

①安装服务,通过咱新开发的C#应用软件安装,不希望借助第三方工具(installutil.exe),因为面向人群非科班出身,操作越简单越好。

②开启、停止服务,不希望出现【黑色命令框】弹窗,看着就烦,用户体验不好。

③不希望出现Windows权限不够的提示框,因为用户是普通用户,不具备“管理员操作权限”,本程序有一些敏感操作,有需要最高权限,不要出现“权限不够,哪怕是否确认授权”消息提示框。

怎么样?需求是不是很变态,需要同时满足以上三点,网上很多技术教程已经不适用。变态需求即是挑战,下面我将介绍本文解决方案,彻底解决以上问题,希望可以帮助面临同样困状的你们。

二、问题解决

2.1 安装Windows service服务

点击【是否开机自启】,安装Windows service服务,并实现服务启停。

2.2 主方法Main()主方法改写

Program.cs文件Main()有两种运行方式

①客户端方式启动,最常用的方式,相当于鼠标双击可执行程序

②服务service方式启动,采用Windows service安装,默认含有参数。

因此我们可以通过参数args区分两种方式,如下图代码所示,其中客户端启动参用“单例模式”,我这里使用了全局信号量卡控,一次只能运行一个程序客户端。

 static void Main(string[] args){//ProcessExec processExec = new ProcessExec();//string aa = "";//processExec.MediaServiceStart("", out aa);if (args.Length > 0){var serviceName = Const.ct_strServiceName;var host = HostFactory.New(x =>{x.EnableShutdown();x.Service<ServiceCtrl>();x.RunAsLocalSystem();x.SetDescription(Const.ct_strProjName);x.SetDisplayName(serviceName);x.SetServiceName(serviceName);});LogHelper.Info("***********主程序运行(服务方式)**********");host.Run();}else{bool createNew;//使用用互斥量(System.Threading.Mutex)只运行一个实列using (System.Threading.Mutex mutex = new System.Threading.Mutex(true, Application.ProductName, out createNew)){if (createNew){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);LogHelper.Info("***********主程序运行(客户端方式)**********");Application.Run(new FormMain());}else{System.Threading.Thread.Sleep(1000);System.Environment.Exit(1);}}}}

2.3 安装service服务/卸载service服务

①添加新项-->Windows服务--AutoPlayerService.cs

 ②右键空白处,【添加安装程序】,它会自动创建ProjectInstaller.cs文件,打开该文件有两个组件serviceProcessInstaller1、serviceInstaller1

网上大部分文章,教你们在属性中填写 服务信息,这种方式存在缺陷,常常服务不能够自动注入,需要借助第三方工具写入注册表,我教你们另外一种方式,如下图所示:

 ③我的方式,通过使用底层入口实现。

添加以下4行代码。

        [DllImport("kernel32.dll")]public static extern int WinExec(string CmdLine, int ShowCmd);[DllImport("shell32.dll")]public static extern int ShellExecute(IntPtr hWnd, string Operation, string FileName,string Parameters, string Directory, int ShowCmd);

 ④实现方法

安装服务

                string cmd = Application.ExecutablePath;cmd += " install";WinExec(cmd, 1);MessageBox.Show("服务安装完毕!");ShellExecute(this.Handle, "open", "Services.msc", "", "", 1);

卸载方法

                    ServiceStop(Const.ct_strServiceName);//停止服务string cmd = Application.ExecutablePath;cmd += " uninstall";WinExec(cmd, 1);MessageBox.Show("服务卸载完毕!");

2.4 服务启停

①创建服务类ServiceCtrl.cs ,实现接口ServiceControl。

  public class ServiceCtrl : ServiceControl{MainTimer m_MainTimer;public ServiceCtrl(){try{m_MainTimer = new MainTimer(21600);//6小时检查一次m_MainTimer.InitTimer();}catch (Exception err){LogHelper.Error("初始化服务发生错误:" + err.ToString());}}/// <summary>/// 服务启动时执行/// </summary>/// <param name="c"></param>/// <returns></returns>public bool Start(Topshelf.HostControl c){try{m_MainTimer.StartTimer();string l_strMsgError = "";if (SysParameter.shutdown_tag == "T"){ProcessExec exec = new ProcessExec();exec.StartShutDown(out l_strMsgError);}return true;}catch (Exception err){LogHelper.Error("启动服务发生错误:" + err.ToString());return false;}}/// <summary>/// 服务关闭时执行/// </summary>/// <param name="c"></param>/// <returns></returns>public bool Stop(Topshelf.HostControl c){try{m_MainTimer.StopTimer();return true;}catch (Exception err){LogHelper.Error("停止服务发生错误:" + err.ToString());return false;}}}

②服务启动

        //启动服务public static void ServiceStart(string serviceName){using (ServiceController control = new ServiceController(serviceName)){if (control.Status == ServiceControllerStatus.Stopped){control.Start();}}}

③服务停止

      //停止服务public static void ServiceStop(string serviceName){using (ServiceController control = new ServiceController(serviceName)){if (control.Status == ServiceControllerStatus.Running){control.Stop();}}}

④判断服务是否在运行状态(可选)

        //判断服务状态public static bool IsServiceRuning(string serviceName){ServiceController[] services = ServiceController.GetServices();foreach (ServiceController sc in services){if (sc.ServiceName.ToLower() == serviceName.ToLower()){if (sc.Status == ServiceControllerStatus.Running){return true;}else{return false;}}}return false;}

2.5 服务调用运行

以上基本完成了服务的开发,关于服务调用我给一个案例:我这里鼠标右键点击,自动启动服务,开始执行主方法。

 //启动服务(Windows服务运行)private void BTN_ServiceRun_Click(object sender, EventArgs e){m_service.Start(null);try{BTN_ServiceRun.Enabled = false;//ToDo:采用服务式,无dos黑框//string cmd = Const.ct_strServiceName;//cmd = "net start " + cmd;//FormSet.WinExec(cmd, 1);FormSet.ServiceStart(Const.ct_strServiceName);if (DataOperation.UpdateStateType("正在运行")){GC_Main.DataSource = DataOperation.SelectData();GC_Main.RefreshDataSource();}}finally{BTN_ServiceStop.Enabled = true;}}//停止服务(Windows服务停止)private void BTN_ServiceStop_Click(object sender, EventArgs e){m_service.Stop(null);try{BTN_ServiceStop.Enabled = false;FormSet.ServiceStop(Const.ct_strServiceName);if (DataOperation.UpdateStateType("已停止")){GC_Main.DataSource = DataOperation.SelectData();GC_Main.RefreshDataSource();}}finally{BTN_ServiceRun.Enabled = true;}}

2.6 关于权限的提升

有时,你或许没有管理员权限,毕竟公司电脑嘛,每次服务开启都会有弹窗提示“权限不足”,很是厌烦,而且我们还要再次人工干预,这时你需要再程序中增加用户权限配置清单。

创建app.manifest应用程序清单文件。

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity version="1.0.0.0" name="MyApplication.app"/><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><!-- UAC 清单选项如果想要更改 Windows 用户帐户控制级别,请使用以下节点之一替换 requestedExecutionLevel 节点。n<requestedExecutionLevel  level="asInvoker" uiAccess="false" /><requestedExecutionLevel  level="requireAdministrator" uiAccess="false" /><requestedExecutionLevel  level="highestAvailable" uiAccess="false" />指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此元素。--><requestedExecutionLevel  level="requireAdministrator" uiAccess="false" /></requestedPrivileges></security></trustInfo><compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application><!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的Windows 版本的列表。取消评论适当的元素,Windows 将自动选择最兼容的环境。 --><!-- Windows Vista --><!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />--><!-- Windows 7 --><!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />--><!-- Windows 8 --><!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />--><!-- Windows 8.1 --><!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />--><!-- Windows 10 --><!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />--></application></compatibility><!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。--><!--<application xmlns="urn:schemas-microsoft-com:asm.v3"><windowsSettings><dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware></windowsSettings></application>--><!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) --><!--<dependency><dependentAssembly><assemblyIdentitytype="win32"name="Microsoft.Windows.Common-Controls"version="6.0.0.0"processorArchitecture="*"publicKeyToken="6595b64144ccf1df"language="*"/></dependentAssembly></dependency>--></assembly>

<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />这句代码帮你以管理员身份运行,这样就不会弹窗了。

三、资源分享

3.1 引入组件

你需要引入最强大的组件库 Geyc.Utils.dll,我已经本文介绍的方法封装了,本组件包含大量实战项目的操作类、底层库、UI控件等,定期更新补充。

倘若你在项目引用过程中,发现组件中的错误,或是库不支持,或是组件适配环境性问题,请联系我修改封装底层库文件。

链接:https://pan.baidu.com/s/1sEO9aH2_re7Xwa-WDL_V7w?pwd=l6d0 
提取码:l6d0

3.2 新手使用

我已将方法封装,你也只需要几行代码就可以实现本文阐述的功能。

//判断服务是否运行
IsServiceRuning(string serviceName)//安装服务
InstallService(string serviceFilePath)//卸载服务
UninstallService(string serviceFilePath)//启动服务
ServiceStart(string serviceName)//停止服务
ServiceStop(string serviceName)


http://www.taodudu.cc/news/show-4974478.html

相关文章:

  • Windows 服务介绍(本地系统、网络服务、本地服务以及相关的power shell命令
  • windows服务ServiceProcess
  • Windows 服务
  • js 解析json数据实现快递包裹的查询
  • 12、 一键查快递
  • 已知顺丰快递既可以发陆运,也可以发空运;EMS只能发空运,圆通只能发陆运。 小明现在发送快递,为其设计两个方法,分别用来发空运和陆运。
  • valgrind 工具使用
  • valgrind 工具介绍和简单的使用
  • valgrind 简介(内存检查工具)
  • 工具:valgrind学习
  • Win10下CS231n assignment1 环境配置
  • cs231n assignment2 PyTorch
  • Stanford cs231n'18 课程及作业详细解读
  • CS231n第一节
  • cs231n笔记总结
  • 【实验小结】cs231n assignment1 knn 部分
  • CS231n 两层神经网络反向传播实现
  • 【深度学习】cs231n计算机视觉 CNN(卷积神经网络)
  • FreeCAD错误:没有激活的实体 解决办法
  • springboot 整合mysql clickhouse 多数据源
  • 自定义数据源 整合 Mybatis-Plus-多租户
  • 2020FME博客大赛——FME在数据整合中的应用
  • 从零开始Tableau | 2.数据整合
  • 代码分析 | 单细胞转录组数据整合详解
  • 怎样的数据报表才能将公司全部业务数据整合在一起
  • 数据仓库、数据整合、ETL、ELT和EII之间的区别?
  • 生物信息学|MOLI:基于深度神经网络进行多组学数据整合并用于药物反应预测
  • 数据清洗 Chapter04 | 数据整合
  • 分享一篇 Science 里不同批次的单细胞数据整合及批次校正方法
  • 数据库数据整合