如果对以个问题,您有更好的实现方法,请不吝赐教,谢谢!第一次写Windows服务,虽说只是一个小程序,但也够我忙活了几天。本来前段时间就要写的,后来有些其他的事情,给耽搁了。在写这个程序的过程中,碰到了一些问题,现记录下来,希望对一些朋友有些帮助。 我做的这个服务是带界面的,其实服务跟界面是两个不同的项目,只是放在同一个解决方案下而已。
1、启动/停止服务
别看着好像挺简单,一两句代码就能搞定。
添加引用System.ServiceProcess.dllServiceController sc = new ServiceController(); 
sc.ServiceName = "服务名";以下是启动服务和停止服务的按钮事件        private void btnStart_Click(object sender, EventArgs e) 
        { 
            sc.Start();//启动 
        }         private void btnStop_Click(object sender, EventArgs e) 
        { 
            sc.Stop();//停止 
        } 如果以为这样就可以,那可就错了。服务的启动或停止可能需要一定的时间,如果在这过程中再去点击启动或停止服务的按钮,程序将会报错。因此,我又加了一些代码,以启动服务事件为例:        private void btnStart_Click(object sender, EventArgs e) 
        { 
            sc.Start();//启动 
            sc.WaitForStatus(ServiceControllerStatus.Running);//等待服务达到指定状态 
        }
然而,如果服务已经通过其他方式启动了,点击启动按钮,还是会错,于是还得判断一下:        private void btnStart_Click(object sender, EventArgs e) 
        { 
            if(sc.Status==ServiceControllerStatus.Stopped) 
                sc.Start();//启动 
            sc.WaitForStatus(ServiceControllerStatus.Running);//等待服务达到指定状态 
        } 可是问题还没有解决,经过调试,发现sc.Status并没有取到最新的状态,还得加句代码,最后版本如下:        private void btnStart_Click(object sender, EventArgs e) 
        { 
            sc.Refresh();//刷新属性值 
            if(sc.Status==ServiceControllerStatus.Stopped) 
                sc.Start();//启动 
            sc.WaitForStatus(ServiceControllerStatus.Running);//等待服务达到指定状态 
        }
2、读取config文件如果是自身项目中的config文件,那么只需要:            using System.Configuration; 
            string _value = ConfigurationSettings.AppSettings["Key值"];
注意:   ConfigurationSettings.AppSettings[""]获取的是程序初始化时的数据,如果此后config文件作了修改,需要在下次初始化时才能获取到新的值(换句话说:程序需要重新启动)。因此如果要使用新值,需要声明全局变量将新值存储起来。 但我是在界面项目读取服务项目的config文件,那就得采用其他的方法了:            using System.Xml;             XmlDocument xmlDoc = new XmlDocument(); 
            xmlDoc.Load(configPath);//configPath是config文件的路径,对于这个路径的获取,将会在后面说明 
            XmlNodeList nodes = xmlDoc.GetElementsByTagName("add"); 
            Hashtable hash = new Hashtable(); 
            foreach (XmlNode node in nodes) 
            { 
                hash.Add(node.Attributes["key"].Value.ToString(), node.Attributes["value"].Value.ToString()); 
            } 
            //通过hash["Key值"].ToString()就能获取到某一个key所对应的value了 3、修改config配置文件指定key的value与第2点类似,若是自身项目的config文件,只需要   ConfigurationSettings.AppSettings.Set(key,value)方法就可以搞定的。但我不得不用读写XML文件来做,具体代码如下:   XmlDocument xmlDoc=new XmlDocument(); 
   xmlDoc.Load(configPath);//configPath为config文件的路径 
   XmlNode xmlNode=xmlDoc.SelectSingleNode("configuration/appSettings/add[@key='"+_key+"']");//_key为需要修改其value的key值 
   xmlNode.Attributes["value"].InnerText=_value;//_value为新值 
   xmlDoc.Save(configPath);
4、获取服务的文件路径个人觉得通过读取注册表的相应项的方法不错,具体实现代码如下:            using Microsoft.Win32;             RegistryKey rk = Registry.LocalMachine; 
            RegistryKey rkSub = rk.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\服务名"); 
            string servicePath = rkSub.GetValue("ImagePath").ToString(); 
            //那么我们就可以轻易地得到第2点所需要的config文件路径 
            string configPath = servicePath + ".config"; 4、添加服务的描述本来以为要给某个服务设置“描述”信息应该就像是给服务设置名称一样简单,结果找来找去,竟没有发现可以设置的地方。搜索了一下,发现以下这个方法不错(保留代码的注释): 把以下的代码插入到ProjectInstaller 类的代码中就可以了。代码出处:http://www.codeproject.com/dotnet/dotnetscmdescription.asp        //This code should be inserted into your ProjectInstaller class' code         public override void Install(IDictionary stateServer) 
        { 
            Microsoft.Win32.RegistryKey system, 
                //HKEY_LOCAL_MACHINE\Services\CurrentControlSet 
                currentControlSet, 
                //...\Services 
                services, 
                //...\<Service Name> 
                service, 
                //...\Parameters - this is where you can put service-specific configuration 
                config;              try 
            { 
                //Let the project installer do its job 
                base.Install(stateServer);                 //Open the HKEY_LOCAL_MACHINE\SYSTEM key 
                system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); 
                //Open CurrentControlSet 
                currentControlSet = system.OpenSubKey("CurrentControlSet"); 
                //Go to the services key 
                services = currentControlSet.OpenSubKey("Services"); 
                //Open the key for your service, and allow writing 
                service = services.OpenSubKey(this.BakServiceInstaller.ServiceName, true); 
                //Add your service's description as a REG_SZ value named "Description" 
                service.SetValue("Description", "你的描述写在这里!"); 
                //(Optional) Add some custom information your service will use... 
                config = service.CreateSubKey("Parameters"); 
            } 
            catch(Exception e) 
            { 
                Console.WriteLine("An exception was thrown during service installation:\n" + e.ToString()); 
            } 
        }         public override void Uninstall(IDictionary stateServer) 
        { 
            Microsoft.Win32.RegistryKey system, 
                currentControlSet, 
                services, 
                service;             try 
            { 
                //Drill down to the service key and open it with write permission 
                system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); 
                currentControlSet = system.OpenSubKey("CurrentControlSet"); 
                services = currentControlSet.OpenSubKey("Services"); 
                service = services.OpenSubKey(this.BakServiceInstaller.ServiceName, true); 
                //Delete any keys you created during installation (or that your service created) 
                service.DeleteSubKeyTree("Parameters"); 
                //... 
            } 
            catch(Exception e) 
            { 
                Console.WriteLine("Exception encountered while uninstalling service:\n" + e.ToString()); 
            } 
            finally 
            { 
                //Let the project installer do its job 
                base.Uninstall(stateServer); 
            } 
        } 

解决方案 »

  1.   

    用c#写windows服务还需要安装dotnet framework,我更倾向于使用vc++或delphi来写这样的程序,个人感觉c#写这样的程序没有什么优势
      

  2.   

    服务的相关信息就是保存在注册表里面,你到这个注册表项内找一些信息全的参考一下然后自己往注册表里面写就可以了
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
      

  3.   


    参照SQL Server服务管理器的做法,我用的是两个按钮,只能有一个按钮处于可操作状态。
    private void btnStart_Click(object sender, System.EventArgs e)
    {
    try
    {
    sc.Refresh();
    if(sc.Status==ServiceControllerStatus.Stopped)
    sc.Start();
    sc.WaitForStatus(ServiceControllerStatus.Running);
    btnStart.Enabled=false;
    btnStop.Enabled=true;
    }
    catch(Exception ex)
    {
    MessageBox.Show("服务启动失败:"+ex.Message);//可能会由于登录密码错误或其他原因,而导致服务无法正常启动。
    }
    }
      

  4.   

    4、获取服务的文件路径 我 这有个别的方法。。System.AppDomain.CurrentDomain.BaseDirectory.ToString()这个可以获得服务器程序的执行exe文件所在的文件夹路径。
    (Process.GetCurrentProcess().MainModule.FileName文件名)
      

  5.   

     学习 
    服务有设置Description的地方啊partial class ProjectInstaller
        {
            /// <summary>
            /// 必需的设计器变量。
            /// </summary>
            private System.ComponentModel.IContainer components = null;        /// <summary> 
            /// 清理所有正在使用的资源。
            /// </summary>
            /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }        #region 组件设计器生成的代码        /// <summary>
            /// 设计器支持所需的方法 - 不要
            /// 使用代码编辑器修改此方法的内容。
            /// </summary>
            private void InitializeComponent()
            {
                this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
                this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
                // 
                // serviceProcessInstaller1
                // 
                this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
                this.serviceProcessInstaller1.Password = null;
                this.serviceProcessInstaller1.Username = null;
                // 
                // serviceInstaller1
                // 
                this.serviceInstaller1.Description = "OOOOOOOOOOOOOOOOOOOOOOOOOOO";}
      

  6.   


    我回去看了下,没有Description。你确定没有搞错?
      

  7.   

    之前刚做了一个监视系统,也是Service
      

  8.   

     ServiceInstaller a = new ServiceInstaller();
     a.Description = "这是一个***服务";
    这样可以添加服务控制类对象的描述。
    也可以直接用ServiceInstaller 控件,在属性里面有设置
    http://blog.csdn.net/xuhaiyan8825/archive/2009/01/10/3746953.aspx
    这是我写的一篇服务的
    包括服务本身,和服务控制,以及服务安装和卸载,还有调试
    楼主可以看看,多提意见,我也是第一次写服务
      

  9.   


    我找了台装了VS2008的机器试了一下,确实有了。
    真郁闷,现在还得用VS2003来写。
      

  10.   


    VS2003还没有Description。Blog我看了,服务也是可以打包的,不用另外写程序去控制安装和卸载。
    改天我把这一个也写出来。