编写 Window 服务程序

一、直观认识Windows服务。

打开Windows“控制面板/管理工具/服务”,系统显示Windows服务列表。
双击服务,可以显示和更改服务属性。在这个对话框中,可以控制服务的启动、暂停和停止。在这里还可以配置服务的启动类型,令服务在系统启动时自行启动。因此,Windows服务经常作为服务器程序运行。
在故障恢复这个属性页,可以配置该服务失败后系统的相应。一些病毒程序就是在这里做文章,将病毒程序激活的。

二、Windows服务的开发要点

Visual Studio的随机文档里,详细介绍了Windows服务程序的开发步骤,并且带有实例,笔者不再赘述。读者只需注意几个要点:
1、创建一个派生自ServiceBase的入口类。这个入口类管理这个Windows服务的生存期。
public class MyService : System.ServiceProcess.ServiceBase
{
……
}
2、在入口类的main方法里将服务向Windows的服务控制器(Service Control Manager, SCM)注册,代码:
……
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
……
3、重写 OnStart 、OnStop ,或OnPause 和 OnContinue 方法来响应服务状态的更改。通常需要重写OnStart 方法,结束服务时在 OnStop 方法中释放资源,酌情重写OnPause 和 OnContinue方法。
4、Windows服务通常启动一个定时器来定时或轮询进行业务处理。
5、Windows服务需要安装后才能使用。通常通过两个办法安装Windows服务:
  • 在命令行运行InstallUtil.exe;
  • 在Windows服务程序的代码中添加ProjectInstraller类的实例,里面包含ServiceProcessInstaller类和ServiceInstaller类的实例。
上述两个办法在Framework的随机文档中均有描述,在此不再赘述。
6、Windows服务在Windows的服务控制器(Service Control Manager, SCM)中运行,因此调试起来不像其他Visual Studio应用程序那样简单。关于Windows服务的调试,在Visual Studio的随机文档里面有介绍,在此不再赘述。

三、Windows服务的异常处理

Windows服务没有用户界面,在运行过程中难以将异常通知给用户。通常情况下,Windows服务在运行过程中发生了异常,可能导致服务运行挂起,但没有任何提醒。
推荐的一个做法是在Windows服务中捕获异常,并把异常信息写在Windows的事件日志中。打开Windows的“控制面板/管理工具/事件查看器”,系统显示Windows事件日志。
在一个实际的应用中,笔者除了把异常和提示记录在事件日志中,还把严重错误自动通过邮件发送给相关人员。同时,所有记录在事件日志中的信息,还重定向到一个自行开发的控制台程序中,用以随时监控服务。

三、Windows事件日志的开发要点和技巧

Visual Studio的随机文档里,在介绍Windows服务程序的开发步骤的同时,也介绍了如何向Windows服务中加入事件日志,笔者不再赘述。开发要点如下:
1、在需要写入日志的类中创建EventLog的实例eventLog,在构造函数里加入代码:
if (!System.Diagnostics.EventLog.SourceExists("mySource"))
{        
System.Diagnostics.EventLog.CreateEventSource("mySource","myEventLog");
}
eventLog.Source = " mySource ";
eventLog.Log = " myEventLog ";
2、在需要写事件日志的地方写日志,例如:
protected override void OnStop()
{
eventLog.WriteEntry("In onStop.");
}
读者可以在实际应用中尝试使用下面的技巧。
1、把写Windows事件日志的代码封装成独立的class,这样不仅在Windows服务中,而且在其他的业务代码中都可以使用Windows事件日志。代码见附件。
2、为方便调试和跟踪,Visual Sdudio提供了Trace类。在应用程序的debug编译版本中,用Trace类可以把调试和跟踪信息写到控制台。有一个技巧,可以同时把写入Trace的内容写入Windows事件日志。要点如下:
首先声明一个事件监听类EventLogTraceListener的实例,
static private  EventLogTraceListener cTraceListener = new EventLogTraceListener( m_eventLog );
将EventLogTraceListener的实例加入Trace的监听列表:
Trace.Listeners.Add( cTraceListener );
此后,凡是写入Trace的调试信息,均写入Windows事件日志中。如果不希望将Trace继续写入事件日志,运行下面代码即可:
Trace.Listeners.Remove( cTraceListener );
3、写入事件日志的信息,还可以同时写入其他应用程序窗体中的显示控件。
首先打开窗体的设计视图,从工具箱/组件中选择EventLog并加入窗体,配置EventLog的EnableRaisingEvents属性为True。
加入EventLog的EntryWritten事件处理方法,该事件的第二个参数类行为System.Diagnostics.EntryWrittenEventArgs,其中包含了Windows事件日志条目中的必要内容,将该内容显示在窗体中的某个显示控件中即可。示例代码如下:
/// <summary>
/// 监听事件日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void eventLog_EntryWritten(object sender,
System.Diagnostics.EntryWrittenEventArgs e)
{
try
{
// 把日志内容写到名为listEventLog的List控件中
listEventLog.Items.Insert( 0,
e.Entry.TimeWritten + " " +
e.Entry.Message );
// List控件保存不超过500行的日志
while( listEventLog.Items.Count > 500 )
{
listEventLog.Items.RemoveAt( listEventLog.Items.Count-1 );
}
}
catch( Exception ex )
{
MessageBox.Show( ex.Message );
}
}

四、与Windows服务的通讯

在应用程序或其他服务中,可以与Windows服务通讯,包括:
  • 管理Windows服务的生命期,即开启、停止、暂停和重启服务;
  • 获得Windows服务的属性和状态;
  • 获得特定计算机上的服务列表;
  • 向特定的服务发送命令。
这些操作是通过ServiceController 类完成的。ServiceController是一个可视化控件,可以在工具箱中找到。
比较有意思的是ServiceController 中ExecuteCommand这个方法,调用这个方法,可以向Windows服务发送命令,指挥Windows服务的一些操作。例如,在Windows服务的入口类中有一个复写OnCustomCommand()的方法:
/// <summary>
/// 执行用户自定义消息
/// </summary>
/// <param name="command">消息编号</param>
protected override void OnCustomCommand( int command )
{
try
{
switch( command )
{
case 1: // 业务操作
doBusiness1();
break;
case 2: //业务操作
doBusiness2();
break;
default:
……
break;
}
}
catch( Exception ex )
{
// 错误信息
string strErrorMsg = string.Format("异常:{0}/n", ex.Message );
// 写日志
TLineEventLog.DoWriteEventLog( strErrorMsg, EventType.Error );
// 给管理员发邮件
CMail.SendMail(
PropertyManager.strMailFromAddress, PropertyManager.strMailAdminAddress, "",
"异常信息提示",
strErrorMsg );
// 写Trace
Trace.WriteLine( strErrorMsg );
}
}
在另外一个应用程序中通过ServiceController的ExecuteCommand()方法向这个Windows服务发送命令:
myController.ExecuteCommand(2);
Windows服务将执行业务方法:doBusiness2();
应该承认,利用ServiceController与Windows服务通讯的功能目前还十分薄弱。通过ExecuteCommand只能与Windows服务进行简单而有限的通讯。
笔者在实际的应用中,分别用一个命令行程序、一个控制台程序和一个Webservice和Windows服务进行通讯,启动、停止服务,或通过ExecuteCommand控制服务的行为。

附件:操纵Windows事件日志的通用类

using System;
using System.Diagnostics;
using System.Configuration;
namespace MYCOMMON.EVENTLOG
{
public enum EventType { Error,Information,Warning }
/// <summary>
///
/// </summary>
public class TLineEventLog
{
// 任务日志
static private EventLog m_eventLog = new EventLog();
// 源名称,从配置文件中读取
static private string m_strEventSource =
ConfigurationSettings.AppSettings["f_eventLog.Source"].ToString().Trim();
// 日志名称,从配置文件中读取
static private string m_strEventLog =
ConfigurationSettings.AppSettings["f_eventLog.Log"].ToString().Trim();
// 调试信息写入日志
static private EventLogTraceListener cTraceListener =
new EventLogTraceListener( m_eventLog );
// 缺省构造函数。配置文件读取失败时,提供默认的源名称和日志名称
public TLineEventLog()
{
if( m_strEventSource.Length == 0 )
m_strEventSource = "mySource";
if( m_strEventLog.Length == 0 )
m_strEventLog    = "myLog";
m_eventLog.Source = m_strEventSource;
m_eventLog.Log    = m_strEventLog;
}
// 构造函数。提供源名称和日志名称。
public TLineEventLog( string strEventSource, string strEventLog )
{
m_strEventSource = strEventSource;
m_strEventLog    = strEventLog;
m_eventLog.Source = m_strEventSource;
m_eventLog.Log    = m_strEventLog;
}
/// <summary>
/// 写事件日志
/// </summary>
/// <param name="strMessage">事件内容</param>
/// <param name="eventType">事件类别,错误、警告或者消息</param>
static public void DoWriteEventLog( string strMessage, EventType eventType )
{
if (!System.Diagnostics.EventLog.SourceExists( m_strEventSource ))
{         
System.Diagnostics.EventLog.CreateEventSource(
m_strEventSource,m_strEventLog );
}
EventLogEntryType entryType = new EventLogEntryType();
switch(eventType)
{
case EventType.Error:      
entryType = EventLogEntryType.Error;
break;
case EventType.Information:
entryType = EventLogEntryType.Information;
break;
case EventType.Warning:    
entryType = EventLogEntryType.Warning;
break;
default:                   
entryType = EventLogEntryType.Information;
break;
}
m_eventLog.WriteEntry( strMessage, entryType );
}
/// <summary>
/// 写事件日志,默认为消息
/// </summary>
/// <param name="strMessage">事件内容</param>
static public void DoWriteEventLog( string strMessage )
{
if (!System.Diagnostics.EventLog.SourceExists( m_strEventSource ))
{        
System.Diagnostics.EventLog.CreateEventSource(
m_strEventSource,m_strEventLog );
}
m_eventLog.WriteEntry( strMessage );
}
/// <summary>
/// 调试信息写入日志
/// </summary>
public static void OpenTrace()
{
if( cTraceListener != null )
{
if( !Trace.Listeners.Contains( cTraceListener ) )
{
Trace.Listeners.Add( cTraceListener );
}
}
}
/// <summary>
/// 调试信息不写入日志
/// </summary>
public static void CloseTrace()
{
if( Trace.Listeners.IndexOf(cTraceListener) >= 0 )
{
Trace.Listeners.Remove( cTraceListener );
}
}
}
}
作者简介:张昱,联想利泰软件公司(原联想软件设计中心) e-zhangyu@vip.sina.com
出处:http://blog.csdn.net/zhangyuk/article/details/338243

编写 Window 服务程序相关推荐

  1. 用C/C++编写window服务

    2019独角兽企业重金招聘Python工程师标准>>> Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务.为了学习这种控制台应用程序的基础知识,C(不 ...

  2. c#window服务程序

    c#window服务程序 转载于:https://www.cnblogs.com/mc67/p/5086525.html

  3. C语言编写Windows服务程序

    C语言编写Windows服务程序 原文:C语言编写Windows服务程序 #include <Windows.h> #include <stdio.h>#define SLEE ...

  4. 用汇编写系统服务程序

    用汇编写系统服务程序 本想写一篇关于服务的文章,结果搜了一遍以后,发现发表于天极网上的一篇文章<Win32程序设计之服务>把要说的大部分东西都说了,为了不做重复劳动,所以在这里首先引用这篇 ...

  5. C#2.0 编写window服务

    C#2.0 编写window服务(msdn) 注意 Visual Studio 标准版中不提供"Windows 服务"模板及相关功能.有关更多信息,请参见 Visual Studi ...

  6. 用 C 语言编写 Windows 服务程序的五个步骤

    前一段时间我写了一篇通过写服务的形式来达到一些监视程序运行的目的的文章,至于如何在windows下写服务我没有详细介绍,今天就让我们一起看看如何来写服务程序. Windows 服务被设计用于需要在后台 ...

  7. window服务程序编写及发布

    log4net打印log日志必须在AssemblyInfo.cs里面增加[assembly: log4net.Config.DOMConfigurator(Watch = true)] windows ...

  8. c语言编写系统服务程序,C语言Windows服务程序编写-ServiceMain

    C语言编写的Windows服务程序,可以类比Linux/Unix环境下的daemon进程. 一下是VS2010环境下的demo: // windows_service.cpp : 定义控制台应用程序的 ...

  9. 编写Windows服务程序,将Python作为Windows服务启动

    首先需要安装两个模块. pip install pywin32 -i https://pypi.tuna.tsinghua.edu.cn/simplepip install pyinstaller - ...

  10. C#编写Windows服务程序 (服务端),客户端使用 消息队列 实现淘宝 订单全链路效果

    需求: 针对 淘宝提出的 订单全链路 产品接入 .http://open.taobao.com/doc/detail.htm?id=102423&qq-pf-to=pcqq.group oms ...

最新文章

  1. 信号量与条件变量的区别
  2. 创建一个storageevent事件_事件循环:微任务和宏任务
  3. php 二维数组值相加,php二维数组指定某元素后面的值是和前面的值相加起来的...
  4. 《记得我们有约》17集
  5. Python 装饰器详解(中)
  6. centos哪个版本好用_Ubuntu VS CentOS,谁才是更好的 Linux 版本?
  7. 引入外部less_CSS扩展语言sass和less应该选哪个?
  8. 软件开发生命周期及文档
  9. php 爬虫检查,php判断是否是爬虫访问
  10. mysql的explain执行计划_MySQL之Explain(执行计划)
  11. 学习ROS初始遇到的各种问题及解决方法
  12. 关于微信群的一个新玩法 (月末总结)
  13. 【VC++游戏开发#六】2D篇 —— 粒子系统(一):浪漫唯美的场景之雪花飞舞
  14. Python热门单元测试框架对比:pytest和unittest还傻傻分不清楚?
  15. 前端页面阻尼效果实现
  16. 触目2006信息化之灾
  17. 计算机网络 英文笔记本,笔记本的英文是什么
  18. freetype字体描边
  19. 股指期权的保证金模式简介
  20. jira与Jenkins集成

热门文章

  1. [工具向]__申请,下载,使用百度地图api
  2. Java小题,通过JNI调用本地C++共享库中的对应方法实现杨辉三角的绘制
  3. Mercurial使用简单介绍zz
  4. ant 打包war 遇到的一些问题
  5. 思科/华为/Juniper探测技术
  6. spring security免登录动态配置方案2
  7. windows下双击可运行的Java软件打包方案
  8. 《Pig编程指南》一导读
  9. celery+rabbitmq+redis 分布任务队列探索(一)
  10. 在Windows上安装虚拟机详细图文教程