公司服务器在每天启动时,并没有登录系统,因此想要运行特定的程序,只有把它作为Windows服务启动
要求不修改原来的程序,但是又需要与SCM(服务控制管理器)通信,需要另建一个windows服务程序,让其调用我们的目标程序
网上一些所谓可以把exe注册为服务的工具(如srvinstw.exe, instsrv.exe, srvany.exe等)实际并没有效果,或者说只对本身具有与SCM通信功能的程序有作用
以下为C#的windows服务实现
在ServiceBase的派生类中实现虚函数OnStart和OnStop即可
1 using System; 2 using System.Configuration; 3 using System.Diagnostics; 4 using System.ServiceProcess; 5 using System.Threading; 6 7 namespace MyWindowsService 8 { 9 public partial class MyService : ServiceBase 10 { 11 private static EventLog log = new EventLog(); 12 private static Thread thread = null; 13 private static Process proc = null; 14 private string exePath = null; 15 16 public MyService() 17 { 18 InitializeComponent(); 19 log.Source = "app.log"; //记录日志,使用WriteEntry写入windows事件 20 string dir = System.AppDomain.CurrentDomain.BaseDirectory; 21 ExeConfigurationFileMap map = new ExeConfigurationFileMap(); 22 map.ExeConfigFilename = dir + "App.config"; //读取和服务程序同一目录下的配置文件,其中设置了目标程序的路径 23 Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 24 exePath = config.AppSettings.Settings["exePath"].Value; //读取key为exePath的值 25 } 26 27 protected override void OnStart(string[] args) 28 { 29 try 30 { 31 if (thread == null) 32 { 33 thread = new Thread(startExe); //新线程中启动程序 34 } 35 thread.Start(); 36 } 37 catch(Exception e) 38 { 39 log.WriteEntry(e.ToString()); 40 } 41 } 42 43 protected override void OnStop() 44 { 45 try 46 { 47 if (proc != null && !proc.HasExited) 48 { 49 proc.Kill(); //停止服务时关闭程序 50 } 51 if (thread != null && thread.ThreadState == System.Threading.ThreadState.Running) 52 { 53 thread.Abort(); //关闭线程 54 } 55 } 56 catch (Exception e) 57 { 58 log.WriteEntry(e.ToString()); 59 } 60 } 61 62 private void startExe() 63 { 64 try 65 { 66 proc = new Process(); 67 ProcessStartInfo startInfo = new ProcessStartInfo(exePath); //设置程序路径 68 proc.StartInfo = startInfo; 69 proc.Start(); 70 } 71 catch (Exception e) 72 { 73 log.WriteEntry(e.ToString()); 74 } 75 } 76 } 77 }
其中注意几个问题:
1.启动目标程序时候需要使用新线程,如果在service线程中启动,会阻塞服务与SCM的通信,造成服务启动失败
2.OnStart和OnStop中所有可能抛出的异常都需要捕获,否则启动时如果有异常,则会提示服务启动又停止了
3.启动的目标程序只能以SYSTEM账户运行,因此看不到程序界面
4.服务程序也可使用C++实现,同样最少实现OnStart和OnStop两个虚函数即可
服务的安装,两个办法:
1.编写安装/卸载程序,调用windows API中的函数,CreateService()和DeleteService()
2.使用.Net Framework自带的工具InstallUtil.exe,一般位于%SystemRoot%\Microsoft.NET\Framework\版本号\
安装服务:installuitl [服务程序路径]
卸载服务:installuitl /u [服务程序路径]