一、新建一个Windows服务项目,取名ProcessDaemonServiceTest
用到是.NET Framework 4的框架
新建后的样式:
三、添加应用程序配置文件App.config,在文件里增加如下配置
四、在Service1.cs代码文件中引入【Cjwdev.WindowsApi】程序集
using Cjwdev.WindowsApi;
五、编写服务
1、在构造函数里处理配置消息,读取配置的路径
//存放路径的数组
private static string[] appStartPath = new string[] { };
NameValueCollection appsettings = ConfigurationManager.AppSettings;
string[] names = ConfigurationManager.AppSettings.AllKeys;
public Service1()
{
List asp = appStartPath.ToList();
for (int i = 0; i < appsettings.Count; i++)
{
string key = names[i];
if (key.Contains("Path"))
{
string path = ConfigurationManager.AppSettings[key];
asp.Add(path);
}
}
appStartPath = asp.ToArray();
InitializeComponent();
}
2、编写打开exe程序的事件方法
private void OpenExe(object sender, System.Timers.ElapsedEventArgs e)
{
//句柄
IntPtr userTokenHandle = IntPtr.Zero;
ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
ApiDefinitions.PROCESS_INFORMATION procInfo = new ApiDefinitions.PROCESS_INFORMATION();
ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
startInfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startInfo);
//使用循环,校验程序是否以及打开(exe程序名与进程名需要一致),如果未打开则调用方法CreateProcessAsUser打开
for (int i = 0; i < appStartPath.Length; i++)
{
string appName = appStartPath[i].Split('\\')[appStartPath[i].Split('\\').Length - 1].Split('.')[0];
//是否打开的标志位
bool runFlag = false;
Process[] myProcesses = Process.GetProcesses();
//进程名是否存在
foreach (Process myProcess in myProcesses)
{
if (myProcess.ProcessName.CompareTo(appName) == 0)
{
runFlag = true;
}
}
if (!runFlag)
{
ApiDefinitions.CreateProcessAsUser(
userTokenHandle,//句柄
appStartPath[i],//路径
"",//命令
IntPtr.Zero,
IntPtr.Zero,
false,
0,
IntPtr.Zero,
null,
ref startInfo,
out procInfo);
}
}
if (userTokenHandle != IntPtr.Zero)
//关闭句柄
ApiDefinitions.CloseHandle(userTokenHandle);
}
3、在OnStart方法中创建Timer定时器,添加事件,调用OpenExe方法,并启动
protected override void OnStart(string[] args)
{
//定时器
System.Timers.Timer timer;
timer = new System.Timers.Timer();
//设置计时器事件间隔执行时间
timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["Time"]);
//添加绑定事件,达到间隔时发生
timer.Elapsed += new System.Timers.ElapsedEventHandler(OpenExe);
//启动定时器
timer.Enabled = true;
}
Service1.cs完整代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using Cjwdev.WindowsApi;
using System.Configuration;
using System.Collections.Specialized;
namespace ProcessDaemonServiceTest
{
public partial class Service1 : ServiceBase
{
private static string[] appStartPath = new string[] { };
NameValueCollection appsettings = ConfigurationManager.AppSettings;
string[] names = ConfigurationManager.AppSettings.AllKeys;
//定时器
System.Timers.Timer timer = new System.Timers.Timer();
public Service1()
{
List asp = appStartPath.ToList();
for (int i = 0; i < appsettings.Count; i++)
{
string key = names[i];
if (key.Contains("Path"))
{
string path = ConfigurationManager.AppSettings[key];
asp.Add(path);
}
}
appStartPath = asp.ToArray();
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//设置计时器事件间隔执行时间
timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["Time"]);
//添加绑定事件,达到间隔时发生
timer.Elapsed += new System.Timers.ElapsedEventHandler(OpenExe);
//启动定时器
timer.Enabled = true;
}
protected override void OnStop()
{
timer.Enabled = false;
}
private void OpenExe(object sender, System.Timers.ElapsedEventArgs e)
{
//句柄
IntPtr userTokenHandle = IntPtr.Zero;
ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
ApiDefinitions.PROCESS_INFORMATION procInfo = new ApiDefinitions.PROCESS_INFORMATION();
ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
startInfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startInfo);
//使用循环,校验程序是否以及打开(exe程序名与进程名需要一致),如果未打开则调用方法CreateProcessAsUser打开
for (int i = 0; i < appStartPath.Length; i++)
{
string appName = appStartPath[i].Split('\\')[appStartPath[i].Split('\\').Length - 1].Split('.')[0];
//是否打开的标志位
bool runFlag = false;
Process[] myProcesses = Process.GetProcesses();
//进程名是否存在
foreach (Process myProcess in myProcesses)
{
if (myProcess.ProcessName.CompareTo(appName) == 0)
{
runFlag = true;
}
}
if (!runFlag)
{
ApiDefinitions.CreateProcessAsUser(
userTokenHandle,//句柄
appStartPath[i],//路径
"",//命令
IntPtr.Zero,
IntPtr.Zero,
false,
0,
IntPtr.Zero,
null,
ref startInfo,
out procInfo);
}
}
if (userTokenHandle != IntPtr.Zero)
ApiDefinitions.CloseHandle(userTokenHandle);
}
}
}
Program.cs程序入口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace ProcessDaemonServiceTest
{
static class Program
{
///
/// 应用程序的主入口点。
///
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
六、为服务添加安装程序
点击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
使用命令:net start 服务名
3、 停止服务
使用命令:net stop 服务名
4、卸载服务
使用指令:InstallUtil.exe -u ProcessDaemonServiceTest.exe