Windows服务是您能够创建在它们自己的Windows会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停或重新启动而且不显示任何用户界面。这些服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户账户或默认计算机账户的安全上下文中运行服务。
下面我们来一步步如何创建Windows服务应用程序:
1、新建项目。
2、项目创建后,界面如下所示:
一个简单的Windows服务应用程序基本的准备工作已完成,那么它到底可以做什么呢? 比如:我想每隔5分钟自动运行程序来实现一个小功能,那么首先肯定会想到Timer控件,可是.NET Framework为我们提供了三种Timer:
System.Windows.Forms.Timer
System.Timers.Timer
System.Threading.Timer
究竟该使用那种,那么就先了解一下它们的区别吧!
System.Windows.Forms.Timer实现按用户定义的时间间隔引发事件的计时器。此计时器最宜用于Windows窗体应用程序中,并且必须在窗口中使用。它是使用比较多的Timer,Timer Start之后定时(按设定的Interval)调用挂接在Tick事件上的EventHandler。在这种Timer的EventHandler中可以直接获取和修改UI元素而不会出现问题-因为这种Timer实际上就是在UI线程自身上调用的。也正是因为这个原因,导致了在Timer的EventHandler里面进行长时间的阻塞调用,将会阻塞界面的响应。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace ConsoleApplication1 { class Program { static Timer myTimer = new Timer(); static int alarmCounter = 1; static bool exitFlag = false; private static void TimerEventProcessor(Object myObject, EventArgs e) { myTimer.Stop(); if(MessageBox.Show("Continue running?", "Count is: " + alarmCounter, MessageBoxButtons.YesNo) == DialogResult.Yes) { alarmCounter += 1; myTimer.Enabled = true; } else { exitFlag = true; } } public static void Main(string[] args) { myTimer.Tick += new EventHandler(TimerEventProcessor); myTimer.Interval = 5000; myTimer.Start(); while(exitFlag == false) { Application.DoEvents(); } } } }
System.Timers.Timer在应用程序中生成定期事件,获取基于服务器的计时器功能。它是在.NET的Thread Pool上面运行的,所以这种Timer的EventHandler里面进行耗时较长的计算也不会导致UI失去响应。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Timers; namespace ConsoleApplication1 { class Program { private static Timer aTimer; static void Main(string[] args) { aTimer = new Timer(10000); aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); aTimer.Interval = 2000; aTimer.Enabled = true; Console.WriteLine("Press the Enter key to exit the program."); Console.ReadLine(); } private static void OnTimedEvent(object sender, ElapsedEventArgs e) { Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime); } } }
System.Threading.Timer是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于Windows窗体,因为其回调不在用户界面线程上进行。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ConsoleApplication1 { class Program {
/*
* 线程通过调用AutoResetEvent上的WaitOne方法来等待信号。如果AutoResetEvent处于非终止状态,则
* 该线程阻塞,并等待当前控制资源的线程通过调用Set方法发出资源可用的信号。调用Set向AutoResetEvent
* 发信号以释放等待线程。AutoResetEvent将保持终止状态,直到一个正在等待的线程被释放,然后自动
* 返回非终止状态。如果没有任何线程在等待,则状态将无限期地保持为终止状态。
*/
static void Main(string[] args) { AutoResetEvent autoEvent = new AutoResetEvent(false);
StatusChecker statusChecker = new StatusChecker(10); TimerCallback timerDelegate = new TimerCallback(statusChecker.CheckStatus); Console.WriteLine("{0} Creating timer./n", DateTime.Now.ToString("h:mm:ss.fff")); Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, 250); autoEvent.WaitOne(5000, false); stateTimer.Change(0, 500); Console.WriteLine("/nChanging period./n"); autoEvent.WaitOne(5000, false); stateTimer.Dispose(); Console.WriteLine("/nDestroying timer."); } } class StatusChecker { int invokeCount, maxCount; public StatusChecker(int count) { invokeCount = 0; maxCount = count; } public void CheckStatus(Object stateInfo) { AutoResetEvent autoEvent = (AutoResetEvent)stateInfo; Console.WriteLine("{0} Checking status {1,2}.", DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString()); if(invokeCount == maxCount) { invokeCount = 0; autoEvent.Set(); } } } }
经过上面对比,很容易发现,Windows服务计时器功能最好使用System.Timers.Timer,在选择时,一定要注意是不是选对了控件。
3、右击 添加安装程序,出现以下界面:
修改serviceProcessInstaller1的Account属性值为:LocalSystem;修改serviceInstaller1的StartType属性值为:Automatic,注意ServiceName属性值一致性。
到这里,一个简单的Windows服务程序就建立起来了。至于安装只需要使用一句命令:
C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe [服务路径]
卸载命令如下:
C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe /u [服务路径]
显然我们每次都要敲入命令,为了不重复同样的工作,只需要新建两个不同的.bat文件,然后把这两条命令拷贝进去(注意:这条命令不要换行),以后要安装、卸载,只需简单的双击下该文件即可。