用.Net开发Windows服务的方法和步骤在很多文章里都有详细的介绍,相信大家也都会制作Windows服务了。如果还不会,那么请先去网上搜一下,因为本文的假设是您已经会顺利地制作Windows服务了。
历史
前段时间由于项目的需求,要在Windows里把同样的组件(不同的拷贝)制作成多个不同名称的服务,这些服务完成相同的功能。这下可把我难住了。难道要在开发的代码中一个一个地设置想要的名称,然后编译,然后注册成服务?这样虽然可以完成,但也太fool了,不可取,如果将来要换个名称呢?在重新设置、编译、注册一遍?
困惑
分析制作Windows服务的过程,你会发现对于任何一个还没有注册的Windows服务,它就是一个可执行的程序(.exe),而运行注册工具注册Windows服务的时候,它的服务名称已经确定了。似乎是这样:在编译生成服务安装程序的时侯,服务的名称已经确定了。
再看看Windows服务的项目:有一个xxxService.cs的类,一个xxxServiceInstaller.cs的类
在前一个类中可以设置你的服务的ServiceName,后一个类中指定安装时要安装哪个ServiceName的服务。这两个ServiceName必须相同。
斗争
是的,正是ServiceName,而不是Service。
ServiceName只是指定了要安装服务的名称,而不是那个服务。一个服务应该是个对象,在编译时其实那个对象压根就不存在吧!也就是说至少在编译完成后,没有注册成服务前,指定任何的服务名称(ServiceName)都是骗人的障眼法。
可以这样设想:在安装时,安装工具产生了一系列的对象以执行安装注册服务的过程,其中就包括了ServiceInstaller的对象,以及Service对象。(这个安装过程是注册Windows服务范畴,与这个服务完成的功能无关。)你不是要构造对象吗?于是,我们可以在ServiceInstaller的构造函数里指定要安装的Service的ServiceName,同时在Service的构造函数里指定自己的ServiceName,只要两者一致就可以让安装过程顺利完成。再仔细看看项目的代码,这两个类设置ServiceName的地方确实在构造函数中。OK,终于有一线生机了。
曙光
来个最简单的,用.txt文件来指定服务名称。
建立一个文本文件ServiceName.txt存放Windows服务的名称。
在代码中添加一个函数GetServiceName从文件中获取名称:
Code
private string GetServiceName()
{
string serviceName = string.Empty;
string fileName = "ServiceName.txt";
if (File.Exists(fileName))
{
serviceName = File.ReadAllText(fileName, Encoding.Default);
if (string.IsNullOrEmpty(serviceName) || (serviceName.Trim().Length == 0))
serviceName = "我的服务";
}
else
{
serviceName = "我的服务";
}
return serviceName;
}
在两个类的构造函数中分别设置ServiceName为GetServiceName()。
编译,设置ServiceName.txt的文本值为“服务一”,注册时,运行InstallUtil.exe WindowsService1.exe,“服务一”注册成功。
把程序组件拷贝一份到新的目录下,改变ServiceName.txt的文本值为“服务二”,运行InstallUtil.exe WindowsService1.exe,“服务二”注册成功。
这样我的程序就可以拷贝到天涯海角,然后改变ServiceName.txt的值就可以注册成无数的服务了。
后遗症
不过到目前我尚不确定前面那样的“设想”是否正确,姑且如此吧。