把程序注册为服务的几种方法(转)

方法一: 用inf文件
Note:**结果发现注册成的服务不能启动报错(Error 1053: The service did not respond to the start or control request in a timely fashion.),找不到原因,放弃**:

增加一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=myTest,,My_AddService_Name
[My_AddService_Name]
DisplayName=myTest
Description=myTest服务。
ServiceType=0x10
StartType=2
ErrorControl=0
ServiceBinary=%11%myTest.exe

  保存为inetsvr.inf,然后在运行里注册该文件:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:\path\myTestRegister.inf
  这个例子增加一个名为myTest.的服务.

//////////////////
几点说明:
  1,最后四项分别是
  服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost);
  启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启动,3 手动启动,4 禁用。
(注意,0和1只能用于驱动程序)
  错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3 蓝屏。
  服务程序位置:%11%表示system32目录,%10%表示系统目录(WINNT或Windows),%12%为驱动目录system32drivers。
其他取值参见DDK。你也可以不用变量,直接使用全路径。
  这四项是必须要有的。

  2,除例子中的六个项目,还有LoadOrderGroup、Dependencies等。不常用所以不介绍了。
  3,inetsvr后面有两个逗号,因为中间省略了一个不常用的参数flags。


删除一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
DelService=inetsvr

  很简单,不是吗?
  当然,你也可以通过导入注册表达到目的。但inf自有其优势。

  1,导出一个系统自带服务的注册表项,你会发现其执行路径是这样的:
"ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,
74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,74,
00,6c,00,6e,00,74,00,73,00,76,00,72,00,2e,00,65,00,78,00,65,00,00,00
  可读性太差。其实它就是%SystemRoot%system32 lntsvr.exe,但数据类型是REG_EXPAND_SZ。当手动导入注册表以
增加服务时,这样定义ImagePath显然很不方便。而使用inf文件就完全没有这个问题,ServiceBinary(即ImagePath)
自动成为REG_EXPAND_SZ。

  2,最关键的是,和用SC等工具一样,inf文件的效果是即时起效的,而导入reg后必须重启才有效。
    3,inf文件会自动为服务的注册表项添加一个Security子键,使它看起来更像系统自带的服务。
    另外,AddService和DelService以及AddReg、DelReg可以同时且重复使用。即可以同时增加和删除多个服务和注册表项。

 

--------------------------------------------------------------------------------------------------------------------------------------

方法二:用C#调用myTest.exe, 生成服务
Note: **这个方法试验成功了,可以启动也可以停止服务(可是看不到exe的运行界面:()**

(1).先用C#建立一个"Window服务"专案myTestService,
在WatchFile.cs界面上拖两个控件:fileSystemWatcher1和eventLog1,
设置fileSystemWatcher的属性-filter为"myTest.exe"及path(监控myTest.exe是否被修改),
eventLog1的source设置为fileSystemWatcher1;

然后点属性窗口的"加入安装程式",
会创建一个新页面ProjectInstaller.cs,设置此页面界面上的serviceProcessInstaller1的account属性为LocalSystem,serviceInstaller1的设置是和服务相关的,如StartType设为Automatic自动运行,
DisplayName为myTestService1是生成的服务的名子。。。

(2).编写WatchFile.cs程式(见后面)

(3).建置,在专案的bin\debug下得到一个myTestService.exe
然后在.NET的命令提示字元里,进入这个专案的bin\debug,
安装服务:installutil myTestService.exe
卸除服务:install /u myTestService.exe(先停止服务再卸)

也可以创建安装文件:
加入一个安装专案TestSetup,
点右键:加入->专案输出(选择主要输出),
然后再点右键:检视->自定动作(按此的右键)->应用程序资料夹->加入里面的东东
建置此专案,在TestSetup文件夹的Debug下会有安装文件,安装就可以了

 (4). 安装后,在控制面板的服务里看到服务myTestService1已经有了,
可以启动和停止测看看exe启动没有(在进程里看),也可以查看电脑的应用程序日志文件看程式里的打印信息

 

主要程式如下:
//////////////////
WatchFile.cs的程式: 主要是OnStart和OnStop

========OnStart启动服务========
protected override void OnStart(string[] args)
{
  try
  {
 eventLog1.WriteEntry("[myTest Info]: Start begin!");  //记录在应用程序日志里
 Process[] testService_processNames=Process.GetProcessesByName(System.Diagnostics.Process.GetCurrentProcess().ProcessName);
 System.Diagnostics.Process[] test_processNames = System.Diagnostics.Process.GetProcessesByName("myTest");

 // if there is more than one process
 if (testService_processNames.Length > 1 || test_processNames.Length >0)
 {
   eventLog1.WriteEntry("[myTest Info]: myTest is already running");
   return;
 }
 else
 {
   //在App.config里定义了filepath和filename
   System.Diagnostics.ProcessStartInfo  Info  =  new  System.Diagnostics.ProcessStartInfo();
   Info.WorkingDirectory =System.Configuration.ConfigurationSettings.AppSettings.Get("filepath");//path of exe
   Info.FileName =System.Configuration.ConfigurationSettings.AppSettings.Get("filename");//name of exe
   //Info.Arguments  =  "";
      
//  Info.CreateNoWindow=false;
//  Info.Verb="open";
  Info.WindowStyle=System.Diagnostics.ProcessWindowStyle.Normal;
//  Info.UseShellExecute=true;


   //声明一个程序类
   System.Diagnostics.Process  Proc  ;

   try
   {
   Proc=System.Diagnostics.Process.Start(Info);//启动外部程序myTest.exe
   }
   catch(System.ComponentModel.Win32Exception  e)
   {
  eventLog1.WriteEntry("[myTest Info]: 系统找不到指定的程序文件。\r{0}"+ e.Message);
  return;
   }

//  //打印出外部程序的开始执行时间
   eventLog1.WriteEntry("外部程序的开始执行时间:{0}",  Proc.StartTime);

//
//    //等待3秒钟
//    Proc.WaitForExit(3000);
//     
//    //如果这个外部程序没有结束运行则对其强行终止
//    if(Proc.HasExited  ==  false)
//    {
//     eventLog1.WriteEntry("由主程序强行终止外部程序的运行!");
//     Proc.Kill();
//    }
//    else
//    {
//     eventLog1.WriteEntry("由外部程序正常退出!");
//    }
//    eventLog1.WriteEntry("外部程序的结束运行时间:{0}",  Proc.ExitTime);
//    eventLog1.WriteEntry("外部程序在结束运行时的返回值:{0}",  Proc.ExitCode);

   }

  }
  catch(System.Exception ex)
  {
   eventLog1.WriteEntry("[myTest Info]: Start error- " +ex.Message);
   return;
  }

}

 

========OnStop停止服务========
 protected override void OnStop()
 {
   try
   {
    eventLog1.WriteEntry("[myTest Info]: Stop Begin!");
    System.Diagnostics.Process[] Test_processNames = System.Diagnostics.Process.GetProcessesByName("myTest");
    foreach(System.Diagnostics.Process processChild in Test_processNames)
    {
     eventLog1.WriteEntry("[PBX Info]: ProcessName= " +processChild.ProcessName);
     processChild.Kill();
    }
   }
   catch(System.Exception ex)
   {
    eventLog1.WriteEntry("[myTest Info]: Stop error- "+ex.Message);
    return;
   }
  }

 

========写入txt日志文件========

  public static void WriteLog(string strLog)
  {
   string strPath;
   strPath="D:\\Test";
   strPath+=@"\mylog.tx;
   FileStream fs = new FileStream(strPath,FileMode.OpenOrCreate,FileAccess.Write);
   StreamWriter m_streamWriter = new StreamWriter(fs);
   m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
   m_streamWriter.WriteLine(strLog);                       
   m_streamWriter.Flush();
   m_streamWriter.Close();
   fs.Close();
  }

========App.config========

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <appSettings>
  <add key="filepath" value="D:\\myfile\\done" />
  <add key="filename" value="myTest.exe" />
 </appSettings>
</configuration>

posted @ 2009-04-30 10:53  灰鸽子  阅读(1182)  评论(0编辑  收藏  举报