使用C#创建一个进程杀手Windows服务

标签: 建一 进程 杀手 | 发表时间:2011-09-06 14:12 | 作者:_Mgen Bloger
出处:http://www.cnblogs.com/

 

 

 

 

 

 

 

返回目录

1. 使用概述

此程序可以注册一个Windows服务(Windows Service),并通过启动参数可以制定需要杀掉的进程名称和执行间隔。

 

注意:

此程序主要用来演示使用.NET创建Windows服务,自定义EventLog,以及托管应用程序集的安装部署。涉及到System.ServiceBase, System.Diagnostics, System.Configuration.Install命名空间内的类型使用。至于程序所带来的功能,仅供娱乐呵呵。

 

此程序在Windows 7下测试可以正常运行,但未在其他Windows系统上测试

 

 

image

 

服务的运行需要用户制定参数:(否则服务无法启动,并将错误报到自定义事件目录下)

第一个参数是需要干掉的进程名称,不需要加exe,多个名称用分号隔开。

第二个参数是每次执行的间隔,参数为整数,单位秒,如果是2秒,就直接用2。默认是5秒。

 

比如每隔一秒终止系统内所有的记事本进程和Chrome浏览器进程,那么参数这样写:

notepad;chrome 1

 

 

下面是对服务设置参数的截图:

image

 

 

当然,如果有错误发生的话,比如参数错误,服务会立即停止:

image

 

然后用户可以在自定义事件目录中查看错误信息,当然时间目录中还包含着其他服务运行状态的信息。

image

 

 

 

 

返回目录

2. 创建Windows服务

在.NET的里,Windows服务被包装在System.ServiceProcess命名空间内,因此首先需要给工程添加引用System.ServiceProcess程序集。System.ServiceProcess.ServiceBase类代表着一个Windows服务,这个类继承于Component类,Component类常用在类型对IDE设计模式中的支持。

  注意Windows服务是控制台程序,但它随Windows启动而启动,可以跟随用户账户控制,也可以不(一般是以本地系统权限运行),也不存在用户交互界面的概念。

  ServiceBase的ServiceName属性代表着服务名称,ServiceHandle是Windows内部句柄。ExitCode是退出时的返回代码。EventLog可以设置Windows事件目录,默认EventLog.Log是应用程序事件目录,EventLog.Source默认是服务名称(ServiceBase.ServiceName)。同时使用AutoLog可以自动记录服务状态的改变,如继续,暂停,停止,开始等……

  ServiceBase的Canxxx属性可以设置服务是否可以或者接受某些功能,如可以暂停重新开始(CanPauseAndContinue),是否接收Windows登陆状态改变事件(CanHandleSessionChangedEvent),是否接收电源状态事件(CanHandlePowerEvent)等等……。接着就是一系列protected virtual方法对应上述功能。

 

下面是一个最基本的Windows服务的派生类:

    class Program : ServiceBase

    {

        public const string SERVICE_NAME = "服务名称";

 

        public Program()

        {

            base.ServiceName = SERVICE_NAME;

        }

 

        protected override void OnStart(string[] args)

        {

            base.OnStart(args);

        }

 

        protected override void OnStop()

        {

            base.OnStop();

        }

 

        protected override void OnContinue()

        {

            base.OnContinue();

        }

 

        protected override void OnPause()

        {

            base.OnPause();

        }

 

        protected override void Dispose(bool disposing)

        {

            base.Dispose(disposing);

        }

 

        static void Main(string[] args)

        {

            ServiceBase.Run(new Program());

        }

 

    }

 

 

 

 

注意在Main函数中要通过ServiceBase.Run来运行定义好的Windows服务示例,ServiceBase.Run还可以运行一个ServiceBase数组。如果没有运行的话,当使用Windows服务管理器运行服务时会有如下错误信息:Windows无法运行服务,错误1053:服务没有及时响应启动或控制请求。

image

 

 

 

 

 

返回目录

3. 自定义事件目录并使用EventLogInstaller

前面提到过,ServiceBase的EventLog属性的事件源默认是ServiceBase的服务名称,事件目录是应用程序。当然完全可以自定义Windows服务所需的事件记录目录。

注册事件源可以使用EventLog.CreateEventSource方法,当然更推荐使用EventLogInstaller去部署,这样连同服务本身的部署安装程序,整个过程可以一体化安装,卸载,出了错误也可以撤销。这得益于.NET中System.Configuration.Install命名空间内对安装部署的支持。

虽然EventLogInstaller在System.Diagnostics命名空间内,但必须先引用System.Configuration.Install.dll才可以使用。

 

使用EventLogInstaller的Source和Log属性来配置数据源名称和事件目录,当然还有更高级的属性如CategoryCount等,这里就不讨论了。

            EventLogInstaller ei = new EventLogInstaller();

 

            ei.Source = Program.CUSTOMSRC_NAME;

            ei.Log = Program.LOG_NAME;

接着在服务中使用事件源名称进行时间写入就可以了:

            EventLog.WriteEntry(Program.CUSTOMSRC_NAME, "测试消息");

 

 

 

 

返回目录

4. 使用ServiceProcessInstaller和ServiceInstaller

Windows服务是一个进程,托管下的Windows进程是可以搭载多个Windows服务的,进程和服务是一对多的关系,但一般情况下一对一就可以了。而ServiceProcessInstaller和ServiceInstaller就是对应处理上述两个概念的System.Configuration.Install.Installer类,它们都继承于ComponentInstaller,用于组建的安装部署。

 

ServiceProcessInstaller用于控制整个进程的角色。Account属性(类型是ServiceAccount枚举)可以设置进程运行的权限。一般情况下用高权限LocalSystem,当然也可以跟随用户权限,这个需要设置用户名称和密码,通过设置ServiceProcessInstaller的Username和Password属性可以完成这个要求。

 

ServiceInstaller用于定义单个服务的部署信息,比如名称(ServiceName属性),这个要和定义的ServiceBase.ServiceName一致。其次还有服务描述(Description属性),显示名称(DisplayName属性),依赖的服务(ServicesDependedOn属性),和启动类型(StartType属性:自动,手动,禁用),延时自动启动(DelayedAutoStart)。

 

最后连同上面讲的ServiceBase用到的自定义事件目录,我们可以创建一个完整的System.Configuration.Install.Installer类,并将所有安装部署类型对象加入到子安装包内。

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Diagnostics;

    using System.Configuration.Install;

    using System.ServiceProcess;

    using System.ComponentModel;

 

    [RunInstaller(true)]

    public class MyInstaller : Installer

    {

        public MyInstaller()

        {

            ServiceProcessInstaller spi = new ServiceProcessInstaller();

            ServiceInstaller si = new ServiceInstaller();

            EventLogInstaller ei = new EventLogInstaller();

 

 

            spi.Account = ServiceAccount.LocalSystem;

 

            si.ServiceName = Program.SERVICE_NAME;

            si.StartType = ServiceStartMode.Manual;

            si.Description = "周期性杀掉制定进程,使用参数:进程名称(用;分开) [时间间隔,默认5秒]。注:仅用于C#与Windows服务的编程示例。";

            si.DisplayName =  Program.SERVICE_NAME;

 

            ei.Source = Program.CUSTOMSRC_NAME;

            ei.Log = Program.LOG_NAME;

 

            Installers.Add(spi);

            Installers.Add(si);

            Installers.Add(ei);

 

            if (EventLog.SourceExists(Program.CUSTOMSRC_NAME))

                EventLog.DeleteEventSource(Program.CUSTOMSRC_NAME);

        }

    }

 

 

 

 

 

返回目录

5. 加入全部功能

好了,万事俱备,这里就差实际功能实现了,具体有如下内容:

  • 使用System.Threading.Timer做计时器
  • 根据制定名称结束系统内所有该名称的进程
  • 用自定义事件目录进行必要的状态和错误的记录
  • 对参数进行解析
  • 暂停,继续和停止后资源的处理

 

由于贴进来会使文章太长,请在下面下载源代码并做参考。

 

 

 

 

返回目录

6. 使用installutil.exe部署程序

整个服务构建好了,可是是无法直接运行的。因为定义好的安装类型没有被真正安装。

使用.NET Framework中提供的installutil.exe可以对制定应用程序集进行安装部署或卸载。

虽然System.Configuration.Install中的Installer类没有提供错误后的撤消操作(Rollback方法的调用)(System.Configuration.Install.TransactedInstaller可以),但installutil可以保证应用程序集在安装和卸载时达到理想的效果。

 

installutil.exe最普通的两种使用方法就是

installutil [程序集路径]       //用于安装

installutil /u [程序集路径]    //用于卸载

更多installutil.exe的使用可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/50614e95.aspx

 

下面是程序进行安装时的运行摘要:

E:\Users\Mgen\Documents\Visual Studio 2010\Projects\TTC\TTC\bin\Release>

installutil mgen.exe

 

Microsoft (R) .NET Framework Installation utility Version 4.0.30319.1

Copyright (c) Microsoft Corporation.  All rights reserved.

 

 

Running a transacted installation.

 

Beginning the Install phase of the installation.

Installing service Mgen 进程杀手服务...

Service Mgen 进程杀手服务 has been successfully installed.

Creating EventLog source Mgen 进程杀手服务 in log Application...

Creating EventLog source 进程杀手服务程序 in log MgenLog...

 

The Install phase completed successfully, and the Commit phase is beginning.

 

The Commit phase completed successfully.

 

The transacted install has completed.

 

 

 

 

返回目录

7. 使用AssemblyInstaller部署程序

除了installutil,另一种安装方法就是在代码中用AssemblyInstaller来安装部署,只不过需要自己写更多代码:

结合网上的代码,我把它写成这样一个类:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Reflection;

using System.Collections;

using System.Configuration.Install;

 

namespace Mgen.TTC

{

    /// <summary>

    /// 代码,稍作修改自:

    /// https://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/4d45e9ea5471cba4/4519371a77ed4a74?hl=en

    /// </summary>

    class InstallHelper

    {

        public static void Install(bool uninstall, Assembly ass, string[] args)

        {

            try

            {

                Console.WriteLine(uninstall ? "uninstalling" : "installing");

                using (AssemblyInstaller inst = new AssemblyInstaller(ass, args))

                {

                    IDictionary state = new Hashtable();

                    inst.UseNewContext = true;

                    try

                    {

                        if (uninstall)

                        {

                            inst.Uninstall(state);

                        }

                        else

                        {

                            inst.Install(state);

                            inst.Commit(state);

                        }

                    }

                    catch

                    {

                        try

                        {

                            inst.Rollback(state);

                        }

                        catch { }

                        throw;

                    }

                }

            }

            catch (Exception ex)

            {

                Console.Error.WriteLine(ex.Message);

            }

        }

 

    }

}

 

使用InstallHelper.Install第一个参数为false会安装制定程序集,为true会卸载制定程序集。

 

 

 

返回目录

8. 使用批处理文件快速安装应用程序集

安装应用程序集的方式多种多样,比如上述两种方法,再结合一些安装制作软件可以很好的部署应用程序集的安装。不过使用installutil.exe + 批处理是其中一种简单而快速的方法。

由于此程序为Windows服务,服务的安装卸载操作都需要与Windows Service Manager打交道,因此需要以管理员身份运行批处理。

但是Windows 7中以管理员运行的批处理(bat文件)的当前目录会被强制调整到系统目录中去。用一个dir /p指令就可以测试,不以管理员运行结果是显示批处理当前目录,而如果以管理员身份运行,显示结果竟然是:C:\Windows\System32。

 

在网上查了半天,发现这个方法比较好:http://www.codeproject.com/Tips/119828/Running-a-bat-file-as-administrator-Correcting-cur

即在批处理前加如下指令:

@setlocal enableextensions
@cd /d "%~dp0"

 

这样的话,把installutil所在的目录地址设置成系统PATH环境变量,或者更简单的直接把installutil拷贝到程序集目录下,然后就可以以管理员身份正确的安装或卸载程序集文件了。

 

比如用于安装的批处理这样定义:

@setlocal enableextensions
@cd /d "%~dp0"
@echo off
echo 开始执行安装
installutil.exe mgen.exe
echo 完成
pause

 

 

 

 

返回目录

9. 启动Windows服务

最后就是启动相关服务了。这个就简单多了,可以在控制面板中的服务中对Windows服务进行指定操作。在运行中键入services.msc也可以启动服务管理器。可以参考:“1. 使用概述”的截图。

 

 

 

 

返回目录

10. 程序和源代码下载

 

程序下载(包含用于安装和卸载的批处理)

点击下载

(此为微软SkyDrive存档,请用浏览器直接下载,用某些下载工具可能无法下载)

环境:.NET Framework 4.0 Client Profile

 

 

源代码下载

点击下载

(此为微软SkyDrive存档,请用浏览器直接下载,用某些下载工具可能无法下载)

环境:Visual C# 2010 Express SP1

作者: _Mgen 发表于 2011-09-06 14:12 原文链接

评论: 2 查看评论 发表评论


最新新闻:
· 福布斯:巴茨黯然离职 未能打动华尔街(2011-09-07 10:19)
· 盛大创新院开源平台 SNDACode 介绍(2011-09-07 10:12)
· 谈谈反 Google 的偏见,或者说我如何学会停止忧虑,爱上了广告(2011-09-07 10:10)
· 惠普正式分拆webOS全球事业部 保留硬件部门(2011-09-07 10:06)
· Google+对于中小型企业意味着什么(2011-09-07 09:59)

编辑推荐:用ASP.NET写自己的服务框架

网站导航:博客园首页  我的园子  新闻  闪存  小组  博问  知识库

相关 [建一 进程 杀手] 推荐:

使用C#创建一个进程杀手Windows服务

- Bloger - 博客园-首页原创精华区
自定义事件目录并使用EventLogInstaller. 使用ServiceProcessInstaller和ServiceInstaller. 使用installutil.exe部署程序. 使用AssemblyInstaller部署程序. 使用批处理文件快速安装应用程序集. 此程序可以注册一个Windows服务(Windows Service),并通过启动参数可以制定需要杀掉的进程名称和执行间隔.

监控进程

- - 火丁笔记
有时候,进程突然终止服务,可能是没有资源了,也可能是意外,比如说:因为 OOM 被杀;或者由于 BUG 导致崩溃;亦或者误操作等等,此时,我们需要重新启动进程. 实际上,Linux 本身的初始化系统能实现简单的功能,无论是老牌的 SysVinit,还是新潮的  Upstart 或者  Systemd 均可,但它们并不适合处理一些复杂的情况,比如说:CPU 占用超过多少就重启;或者同时管理 100 个 PHP 实现的 Worker 进程等等,如果你有类似的需求,那么可以考虑试试 Monit 和 Supervisor,相信会有不一样的感受.

我是一个杀手

- Duran - 网不易 [expanded by feedex.net]
比起崩溃、绝望、屎尿齐流,我更喜欢看到目标发现自己陷入奇怪境地时的错愕,比如说发现指着他脑袋的是一把贴满了卡通贴纸的二战老手枪. 最近我又找到了一个令目标在“错愕”中死去的点子,就是这个玻璃杯. 这种杯子,在 BBC 1967 年的间谍电视剧《The Prisoner》里出现过,最近有人复刻了它,在杯底刻了字,一字一行 ,“you have just been poisoned”(酒里有毒).

Skype杀手:微博Call

- jumpstone - 博客园新闻频道
  从今天起我决定对 Skype 说再见,因为我打算改用微博 Call 了.   微博 Call(可独立于微博像 Skype 一样打电话)是由杭州创业公司青芝网络开发的一款免费的轻量移动语音通信应用,目前有 iOS 版和 Android 版. 我刚刚就通过微博 Call 采访了该公司创始人陈金声(见图).

梦想的头号杀手

- 林子 - 译言-每日精品译文推荐
【注:这是《如何实现梦想》系列的第二篇文章】. 翻译:Shayne Yeats . 我浪费了生命中的许多时日去做那些看上去会有用的事. 我无法确切地说清楚有多少次我因为这个缘故而敷衍地去对待我的梦想. 我去上了大学,因为“那样才行得通”. 我去找了份工作,每天要在办公室待上八个小时,因为“那样才行得通”.

婚姻的四大杀手

- - 南桥的博客
美国国歌里称美国为“自由的国度,勇士的家乡”(land of the free and home of the brave).   有婚姻顾问称,这说的是美国的婚姻状况,因为美国的离婚率高达50% —— 有一半结婚的人最后摆脱捆绑,离婚了,可见这是“自由的国度”. 可是还有一半人,奋不顾身地继续婚姻,说明这也是“勇士的家乡”.

Linux进程关系

- - 博客园_首页
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明. Linux的进程相互之间有一定的关系. 比如说,在 Linux进程基础中,我们看到,每个进程都有父进程,而所有的进程以init进程为根,形成一个树状结构. 我们在这里讲解进程组和会话,以便以更加丰富的方式了管理进程.

现金储备:苹果的杀手锏

- So - 译言-每日精品译文推荐
来源How Apple Uses its Cash Hoard to its Advantage. 译者Robin_Witheme. 苹果公司巨大的现金储备是它推出最先进的产品,从而保持领先竞争对手的一种战略. 在过去几年中,苹果公司储备了大量现金,也因此使得投资者经常质疑它为什么要保留这么多闲钱.

癌症是中国的头号杀手

- 希奇 - Solidot
癌症如今是中国的头号杀手,中国卫生部的数据显示,全国范围内近四分之一的人的死因是癌症. 肺癌是最常见的癌症,自1970年以来死于肺癌的人数增长了5倍. 中国快速发展的大城市如上海和北京,大约30%癌症死亡者是死于肺癌,这些城市空气中的颗粒物质通常比纽约高出4倍. 肮脏的空气不仅仅与一系列癌症有关,还与心脏病、中风和呼吸系统疾病有关联,而超过八成的人是死于上述疾病.