• .NET进程守护服务


    一、新建一个Windows服务项目,取名ProcessDaemonServiceTest

    用到是.NET Framework 4的框架 

    新建后的样式:

     二、右击Service1.cs文件查看代码

    三、添加应用程序配置文件App.config,在文件里增加如下配置

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <configuration>
    3. <startup>
    4. <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    5. </startup>
    6. <appSettings>
    7. <add key="Time" value="3000"/>
    8. <add key="Path1" value="D:\Test1\Test1.exe"/>
    9. <add key="Path2" value="D:\Test2\Test2.exe"/>
    10. </appSettings>
    11. </configuration>

     四、在Service1.cs代码文件中引入【Cjwdev.WindowsApi】程序集

    using Cjwdev.WindowsApi;

    五、编写服务

    1、在构造函数里处理配置消息,读取配置的路径

    1. //存放路径的数组
    2. private static string[] appStartPath = new string[] { };
    3. NameValueCollection appsettings = ConfigurationManager.AppSettings;
    4. string[] names = ConfigurationManager.AppSettings.AllKeys;
    5. public Service1()
    6. {
    7. List<string> asp = appStartPath.ToList();
    8. for (int i = 0; i < appsettings.Count; i++)
    9. {
    10. string key = names[i];
    11. if (key.Contains("Path"))
    12. {
    13. string path = ConfigurationManager.AppSettings[key];
    14. asp.Add(path);
    15. }
    16. }
    17. appStartPath = asp.ToArray();
    18. InitializeComponent();
    19. }

    2、编写打开exe程序的事件方法

    1. private void OpenExe(object sender, System.Timers.ElapsedEventArgs e)
    2. {
    3. //句柄
    4. IntPtr userTokenHandle = IntPtr.Zero;
    5. ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
    6. ApiDefinitions.PROCESS_INFORMATION procInfo = new ApiDefinitions.PROCESS_INFORMATION();
    7. ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
    8. startInfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startInfo);
    9. //使用循环,校验程序是否以及打开(exe程序名与进程名需要一致),如果未打开则调用方法CreateProcessAsUser打开
    10. for (int i = 0; i < appStartPath.Length; i++)
    11. {
    12. string appName = appStartPath[i].Split('\\')[appStartPath[i].Split('\\').Length - 1].Split('.')[0];
    13. //是否打开的标志位
    14. bool runFlag = false;
    15. Process[] myProcesses = Process.GetProcesses();
    16. //进程名是否存在
    17. foreach (Process myProcess in myProcesses)
    18. {
    19. if (myProcess.ProcessName.CompareTo(appName) == 0)
    20. {
    21. runFlag = true;
    22. }
    23. }
    24. if (!runFlag)
    25. {
    26. ApiDefinitions.CreateProcessAsUser(
    27. userTokenHandle,//句柄
    28. appStartPath[i],//路径
    29. "",//命令
    30. IntPtr.Zero,
    31. IntPtr.Zero,
    32. false,
    33. 0,
    34. IntPtr.Zero,
    35. null,
    36. ref startInfo,
    37. out procInfo);
    38. }
    39. }
    40. if (userTokenHandle != IntPtr.Zero)
    41. //关闭句柄
    42. ApiDefinitions.CloseHandle(userTokenHandle);
    43. }

    3、在OnStart方法中创建Timer定时器,添加事件,调用OpenExe方法,并启动

    1. protected override void OnStart(string[] args)
    2. {
    3. //定时器
    4. System.Timers.Timer timer;
    5. timer = new System.Timers.Timer();
    6. //设置计时器事件间隔执行时间
    7. timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["Time"]);
    8. //添加绑定事件,达到间隔时发生
    9. timer.Elapsed += new System.Timers.ElapsedEventHandler(OpenExe);
    10. //启动定时器
    11. timer.Enabled = true;
    12. }

    Service1.cs完整代码:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using System.Linq;
    5. using System.ServiceProcess;
    6. using Cjwdev.WindowsApi;
    7. using System.Configuration;
    8. using System.Collections.Specialized;
    9. namespace ProcessDaemonServiceTest
    10. {
    11. public partial class Service1 : ServiceBase
    12. {
    13. private static string[] appStartPath = new string[] { };
    14. NameValueCollection appsettings = ConfigurationManager.AppSettings;
    15. string[] names = ConfigurationManager.AppSettings.AllKeys;
    16. //定时器
    17. System.Timers.Timer timer = new System.Timers.Timer();
    18. public Service1()
    19. {
    20. List<string> asp = appStartPath.ToList();
    21. for (int i = 0; i < appsettings.Count; i++)
    22. {
    23. string key = names[i];
    24. if (key.Contains("Path"))
    25. {
    26. string path = ConfigurationManager.AppSettings[key];
    27. asp.Add(path);
    28. }
    29. }
    30. appStartPath = asp.ToArray();
    31. InitializeComponent();
    32. }
    33. protected override void OnStart(string[] args)
    34. {
    35. //设置计时器事件间隔执行时间
    36. timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["Time"]);
    37. //添加绑定事件,达到间隔时发生
    38. timer.Elapsed += new System.Timers.ElapsedEventHandler(OpenExe);
    39. //启动定时器
    40. timer.Enabled = true;
    41. }
    42. protected override void OnStop()
    43. {
    44. timer.Enabled = false;
    45. }
    46. private void OpenExe(object sender, System.Timers.ElapsedEventArgs e)
    47. {
    48. //句柄
    49. IntPtr userTokenHandle = IntPtr.Zero;
    50. ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
    51. ApiDefinitions.PROCESS_INFORMATION procInfo = new ApiDefinitions.PROCESS_INFORMATION();
    52. ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
    53. startInfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startInfo);
    54. //使用循环,校验程序是否以及打开(exe程序名与进程名需要一致),如果未打开则调用方法CreateProcessAsUser打开
    55. for (int i = 0; i < appStartPath.Length; i++)
    56. {
    57. string appName = appStartPath[i].Split('\\')[appStartPath[i].Split('\\').Length - 1].Split('.')[0];
    58. //是否打开的标志位
    59. bool runFlag = false;
    60. Process[] myProcesses = Process.GetProcesses();
    61. //进程名是否存在
    62. foreach (Process myProcess in myProcesses)
    63. {
    64. if (myProcess.ProcessName.CompareTo(appName) == 0)
    65. {
    66. runFlag = true;
    67. }
    68. }
    69. if (!runFlag)
    70. {
    71. ApiDefinitions.CreateProcessAsUser(
    72. userTokenHandle,//句柄
    73. appStartPath[i],//路径
    74. "",//命令
    75. IntPtr.Zero,
    76. IntPtr.Zero,
    77. false,
    78. 0,
    79. IntPtr.Zero,
    80. null,
    81. ref startInfo,
    82. out procInfo);
    83. }
    84. }
    85. if (userTokenHandle != IntPtr.Zero)
    86. ApiDefinitions.CloseHandle(userTokenHandle);
    87. }
    88. }
    89. }

    Program.cs程序入口:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.ServiceProcess;
    5. using System.Text;
    6. namespace ProcessDaemonServiceTest
    7. {
    8. static class Program
    9. {
    10. /// <summary>
    11. /// 应用程序的主入口点。
    12. /// </summary>
    13. static void Main()
    14. {
    15. ServiceBase[] ServicesToRun;
    16. ServicesToRun = new ServiceBase[]
    17. {
    18. new Service1()
    19. };
    20. ServiceBase.Run(ServicesToRun);
    21. }
    22. }
    23. }

    六、为服务添加安装程序

    点击Service1.cs,在左侧界面内右击,选择“添加安装程序”

    会生成ProjectInstaller.cs文件,同时生产serviceProcessInstaller1和serviceInstaller1两个组件

    1、设置serviceInstaller1组件的属性,右击它选择属性

    默认属性如下:

     

    其中:

            Name:表示控件的名称

            Description:是安装后的描述

            DisplayName:显示的名称

            ServiceName: 指示系统用于标识此服务的名称。此属性必须与要安装的服务的 ServiceBase.ServiceName 相同

            StartType:表示服务的启动方式。默认为 Manual,指定在重新启动后服务将不会自动启动。Automatic:自动启动。Disabled:禁用

    设置 StartType 来指定该服务是在重新启动后自动启动,还是必须由用户手动启动。服务还可以被禁用,指定在启用以前不能被手动或以编程方式启动。

     2、设置serviceProcessInstaller1的属性,右击它选择属性

     

            其中:        

            Account:获取或设置运行该服务应用程序时所使用的帐户类型 

            LocalService:充当本地计算机上非特权用户的帐户,该帐户将匿名凭据提供给所有远程服务器

            NetworkService:提供广泛的本地特权的帐户,该帐户将计算机的凭据提供给所有远程服务器

            LocalSystem:服务控制管理员使用的帐户,它具有本地计算机上的许多权限并作为网络上的计算机

            User:由网络上特定的用户定义的帐户。如果为 ServiceProcessInstaller.Account 成员指定 User,则会使系统在安装服务时提示输入有效的用户名和密码,除非您为 ServiceProcessInstaller 实例的 Username 和 Password 这两个属性设置值

    七、注册、启动、停止和卸载服务

    使用CMD调用安装程序工具【InstallUtil.exe】注册服务,需要以管理员身份运行CMD

    1、注册服务 

    使用指令:InstallUtil.exe ProcessDaemonServiceTest.exe

     2、启动服务

    使用命令:net start 服务名

     

    3、 停止服务

    使用命令:net stop 服务名

    4、卸载服务

    使用指令:InstallUtil.exe -u ProcessDaemonServiceTest.exe

     

  • 相关阅读:
    Fiddler Everywhere 3.2.1 Crack
    docker部署项目
    uni-app —— 小程序实现左右菜单联动
    MySQL数据库入门到大牛_05_排序ORDER BY与分页LIMIT
    十二、【机器学习】【监督学习】- 岭回归 (Ridge Regression)
    (尚硅谷)2021 版 SpringMVC 教程笔记
    TLP2168
    深度学习--全连接层、高阶应用、GPU加速
    dubbo-admin安装以及dubbo-admin简单使用
    洛谷 P1438 无聊的数列(线段树,差分)
  • 原文地址:https://blog.csdn.net/weixin_50478033/article/details/133275528