C# 关于进程回收管理的一款工具设计与分享

简介:

设计初衷

在使用 COM 模式操作 OFFICE 组件的开发过程中,当操作完相关文档后,在某些情况下仍然无法释放掉 Word 或 EXCEL 等应用进程,因此根据进程活动情况或时间点范围开发了一个强制杀掉指定进程名称的 WinForm 程序,做为一种辅助工具运行在云服务器上,命名为 Craneoffice ProcessGC。


开发运行环境

操作系统: Windows Server 2019 DataCenter


.net版本: .netFramework4.0 或以上


开发工具:VS2019  C#


Craneoffice ProcessGC

该工具软件属绿色版,无须安装,直接运行 bin 目录下的 ProcessGC.exe 即可,同目录下的 ProcessList.txt 为配置文件,用于配置要释放的进程,后续也可用工具程序进行操作。


运行主界面

运行后的主界面如下图:

主界面显示了要回收的进程列表,源引于 ProcessList.txt 文件配置,如图示例我们可以看到欲回收的进程为EXCEL和WORD,下面则显示已被回收的进程(如果有的话)。


下方显示 CPU 的利用率和可用内存情况。


系统会随时监测指定的进程名,如果有则按指定的策略进行管理。


管理任务与策略

点击管理任务选项卡,显示如下图:

策略设置如下表:

序号

说明

1

要添加回收的进程名

请正确添加,无须输入扩展名,如果不确定名称则可以通过任务管理器进行查看

2


管理策略

共分三种方式:

1、Force(默认值,表示符合条件则强制关闭)

2、CPU

3、Memor

3


回收时间差(秒)

以秒为单位,记录进程停止活动的时间,超过停止活动时间的进程将被回收

4

上限指标

1、上限指标不能小于零。

2、当选用的策略为CPU时,上限指标不能大于100(即最高100%占用率)

3、当选用的策略为Memory时,指定为Mb值,表示内存占用的最高上限

5

检测时间标准


共有两种方式:

1、ByProcess,以进程时间计算(默认)

2、ByNowTime,以启动当前时间计算

6

回收动作

共有两种方式:

1、Kill,直接关闭释放进程(默认)

2、Command,执行命令行操作

7

相关动作命令

当第6项回收动作为Command时,此项为必输入项,表示要执行的 WINDOWS 命令行操作

8

重新启用命令 设置此项,则当关闭或执行动作命令后,尝试执行此命令

9


计划强制关闭时间(小时)
可以设定小时:分:秒(这个值前缀需要设置一个有效日期),代表每到此时此分此秒,则强制关闭进程

通过以上设置,我们可以灵活的对进程的关闭方式进行控制,以达到实际应用的目的。

其它设置

选择设置选项卡,如下图: 我们可设置窗口的透明度,另外可以设置两个选项:

1、只回收本程序启动时间以后的进程

2、只回收非激活窗口的进程, 指非操作系统显式的应用进程。

3、管理密码:默认值为111111,用于关闭应用程序等操作。

移动存储设备管理

这个选项如下图: 这是为移动设备存储数据库准备的一个选项,点击停止服务可以有效的、安全的移除存储设备,也可以继续启动服务。这个选项较少使用,也需要谨慎使用(因为它会尝试停止IIS、MS SQL SERVER 数据库服务等)。

核心代码-计时器监控

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
      DateTime cur_now=System.DateTime.Now;
      int cur_hour=cur_now.Hour;
      int cur_min=cur_now.Minute;
      int cur_sec=cur_now.Second;
    
      pc.CategoryName="Processor";
      pc.CounterName="% Processor Time";
      pc.InstanceName="_Total";
      
//      pc.MachineName="michaeljane";
      float pcv=pc.NextValue();
      label7.Text="CPU利用率:"+(pcv).ToString()+" %";
      cpubar.Value=(int)(pcv);
 
      pcmem.CategoryName="Memory";
      pcmem.CounterName="Available MBytes";
      pcmem.InstanceName=null;
 
//      richTextBox1.Text=pcpu.NextValue().ToString()+"\r\n";
      
 
      /*      System.Diagnostics.PerformanceCounter[] mypc; 
      System.Diagnostics.PerformanceCounterCategory mycat = 
        new System.Diagnostics.PerformanceCounterCategory("process");
      // Remove the current contents of the list.
      // Retrieve the counters.
      mypc = mycat.GetCounters();
      // Add the retrieved counters to the list.
      richTextBox1.Text="";
      for (int i = 0; i < mypc.Length; i++) 
      { 
        richTextBox1.Text+=(mypc[i].CounterName)+"\r\n";
      }
*/
 
//      float cpuLoad = pc.NextValue();
            try
            {
                label7.Text += "\r\n可用内存:" + pcmem.NextValue().ToString() + "M";
            }
            catch (Exception s)
            {
            }
      statusBar1.Text=cur_now.ToString();  //显示当前时间
      Process[] processes; //定义进程组
      processes = System.Diagnostics.Process.GetProcesses(); //获得当前进程组
      Process process;  //定义初始进程中间变量
      string _pname,_killstate="";   //定义进程名变量,及进程回收状态字符串
      bool _kill=false;  //是否要回收标志变量
      bool _phandle=checkBox2.Checked;
      int _gcSpan;  //时间差变量
      DateTime _pdatetime,_checktime,_stdtime; //进程启动的时间变量和检测时间变量
      string[] _rv;    //接受检测结果的数组
      System.TimeSpan _dd; //时间差的秒数变量
//      string[] _processid=new string[1000];
//      DateTime[] _processLastTime=new DateTime[1000];
//      int[] _processLastMem=new int[1000];
        for(int i = 0;i<processes.Length-1;i++)
        {
          process= processes[i];  //获得当前进程
          _pname=process.ProcessName.ToLower();  //获得进程名并转为小写
                try
                {
                    _pdatetime = process.StartTime;  //获得进程的启动时间
                }catch(Exception e1)
                {
                    continue;
                }
          //        _rv=GetSubValueIndex(listBox1,_pname,"|");  //得到要回收的用户指定进程
          for(int li=0;li<listBox1.Items.Count;li++)
          {
            _rv=listBox1.Items[li].ToString().Split('|');
            string ref_process=_rv[0].ToLower().Trim();
            int ref_span=int.Parse(_rv[1].ToString());
            string ref_cl=_rv[2].ToLower().Trim();
            float ref_rank=float.Parse(_rv[3].ToString());
            string ref_stdtime=_rv[4].ToLower().Trim();
            string ref_act=_rv[5].ToLower().Trim();
            string[] ref_cmd1=_rv[6].Split('↙');
            string[] ref_cmd2=_rv[7].Split('↙');
            string ref_closetime=_rv[8].Trim();
            //        richTextBox1.Text+=_rv[0]+_rv[1]+"\r\n";
          
            if(ref_process==_pname)  //如果是要回收的进程则进行处理
            {
              //如果在检测数组没有找到,则添加到检测数中
              int _curpoint=System.Array.IndexOf(_processid,process.Id);
              if(_curpoint<0)
              {
                _stdtime=process.StartTime;
                if(ref_stdtime=="bynowtime")
                {
                  _stdtime=System.DateTime.Now;
                }
                System.Diagnostics.PerformanceCounter pcm=new System.Diagnostics.PerformanceCounter("Process","% Processor Time",_pname);
                            try
                            {
                                AddArray(process.Id, _stdtime, process.WorkingSet, pcm);
                            }catch(Exception e3)
                            {
 
                            }
                continue;
              }
                        //            richTextBox1.Text+=((System.Diagnostics.PerformanceCounter)_processLastCPU[_curpoint]).NextValue().ToString()+"\r\n";
                        try
                        {
                            float cur_rank = ((System.Diagnostics.PerformanceCounter)_processLastCPU[_curpoint]).NextValue();
                            _checktime = System.DateTime.Now;  //检测时间为当前时间
                                                               //开始分析CPU策略
                            if (ref_cl == "cpu")
                            {
                                //如果当前进程的CPU占用率没有超过指定的上限,则重置最后的检测时间为当前时间,继续监测。
                                if (cur_rank < ref_rank)
                                {
                                    _processLastTime[_curpoint] = _checktime;
                                }
                            }
                        }catch(Exception e2)
                        {
                            continue;
                        }
              //开始分析memory策略
              if(ref_cl=="memory")
              {
                float _curmem=process.WorkingSet/(1024*1024);
                //              richTextBox1.Text+=_pname+" "+_curmem.ToString()+"\r\n";
                //如果当前进程的内存占用没有超过指定的上限,则重置最后的检测时间为当前时间,继续监测。
                if(_curmem<ref_rank)
                {
                  _processLastTime[_curpoint]=_checktime;
                }
              }
              _gcSpan=ref_span;  //得到用户指定的回收时间差
              _kill=false;
              _pdatetime=_processLastTime[_curpoint]; //得到进程的数组最后指定时间
              _dd=_checktime-_pdatetime;     //时间差以检测时间 减去 进行启动时间
              //如果时间差大于回收指定时间则可以回收进程,KILL变量为真
              if(checkBox1.Checked)
              {
                //只回收本程序启动以后的进程时间
                if((_dd.TotalSeconds>_gcSpan)&&(_starttime<_pdatetime))
                {
                  _kill=true;
                }
              }
              else
              {
                if(_dd.TotalSeconds>_gcSpan)
                {
                  _kill=true;
                }
              }
              //如果初期标识为可以关闭该进程,并且策略为强制性关闭,则进行内存判断
              if((_kill)&&(ref_cl=="force"))
              {
                //如果内存有变化,则表示进程仍在活动,则不进行关闭,并更新检测内容
                int _curmem=process.WorkingSet;
                label6.Text=_curmem.ToString()+"  "+_processLastMem[_curpoint];
                if(_curmem!=_processLastMem[_curpoint])
                {
                  _processLastTime[_curpoint]=_checktime;
                  _processLastMem[_curpoint]=_curmem;
                  _kill=false;
                }
              }
              //如果指定了强制关闭时间,则进行判断
              string close_tip="";
              if(ref_closetime!="")
              {
                DateTime ref_cls=DateTime.Parse(ref_closetime);
                if((ref_cls.Hour==cur_hour)&&(ref_cls.Minute==cur_min)&&(ref_cls.Second==cur_sec))
                {
                  _kill=true;
                    close_tip="强制关闭计划启动,计划时间为:"+ref_closetime;
                }
              }
              //如果只回收死进程,而当前进程为激活的窗口的话,则不关闭
              if((_phandle)&&((int)process.MainWindowHandle!=0))
              {
                _kill=false;
              }
 
              //如果可以回收则在文本框中添加回收状态,并将进程关闭
              if(_kill)
              {
                if(!process.HasExited)
                {
                  if(ref_act=="kill")
                  {
                    //                MessageBox.Show("has exited");
                    _killstate=close_tip+".进程"+_pname+"已被回收,关闭策略为"+ref_cl+",动作为:"+ref_act+"。进程的启动时间为"+
                      _pdatetime.ToString()+",检测时间为:"+_checktime.ToString()+
                      ",现已经超时"+(_dd.TotalSeconds-_gcSpan).ToString()+
                      "秒,回收时间单位是"+_gcSpan.ToString()+"秒。"+
                      "进程ID:"+process.Id.ToString()+
                      "进程主窗口句柄:"+process.MainWindowHandle.ToString();
                    process.Kill();
                    richTextBox1.AppendText(_killstate+"\r\n");
                  }
                  if(ref_act=="command")
                  {
                    //                MessageBox.Show("has exited");
                    string _return="";
                    for(int st=0;st<ref_cmd1.GetLength(0);st++)
                    {
                      _return+=ref_cmd1[st]+" Result:"+WinExec(ref_cmd1[st],0).ToString()+"↙";
                    }
                    _killstate=close_tip+".进程"+_pname+"已被回收,关闭策略为"+ref_cl+",动作为:"+ref_act+",执行了命令:"+
                      ref_cmd1+"。返回值为:"+_return+"。进程的启动时间为"+
                      _pdatetime.ToString()+",检测时间为:"+_checktime.ToString()+
                      ",现已经超时"+(_dd.TotalSeconds-_gcSpan).ToString()+
                      "秒,回收时间单位是"+_gcSpan.ToString()+"秒。"+
                      "进程ID:"+process.Id.ToString()+
                      "进程主窗口句柄:"+process.MainWindowHandle.ToString();
                    richTextBox1.AppendText(_killstate+"\r\n");
                    //                    process.Kill();
                  }
                  //清空当前进程检测数组元素
                  _processid[_curpoint]=0;
                  _processLastTime[_curpoint]=_checktime;
                  _processLastMem[_curpoint]=0;
                  _processLastCPU[_curpoint]=null;
                }//判断进程是否已经退出
              }
            }//if proecess
            else //如果没有找到进程名称,则二次判断任务是否提供了启动命令,如果提供,则运行它
            {
            }//end find process name
          }//li
        }//for
      processes = System.Diagnostics.Process.GetProcesses(); //获得当前进程组
      for(int ali=0;ali<listBox1.Items.Count;ali++)
      {
        _rv=listBox1.Items[ali].ToString().Split('|');
        string ref_process=_rv[0].ToLower().Trim();
        int ref_span=int.Parse(_rv[1].ToString());
        string ref_cl=_rv[2].ToLower().Trim();
        float ref_rank=float.Parse(_rv[3].ToString());
        string ref_stdtime=_rv[4].ToLower().Trim();
        string ref_act=_rv[5].ToLower().Trim();
        string[] ref_cmd1=_rv[6].Split('↙');
        string ref_start_cmd=_rv[7];
        string[] ref_cmd2=_rv[7].Split('↙');
        bool _find=false;
        if(ref_start_cmd!="")
        {
          for(int i = 0;i<processes.Length-1;i++)
            {
            process= processes[i];  //获得当前进程
            string cur_pname=process.ProcessName.ToLower();  //获得进程名并转为小写
            if(cur_pname==ref_process)
            {
              _find=true;
            }
            }
          if(!_find)
          {
            string _return="";
            for(int st=0;st<ref_cmd2.GetLength(0);st++)
            {
              _return+=ref_cmd2[st]+" Result:"+WinExec(ref_cmd2[st],0).ToString()+"↙";
            }
            _killstate="进程"+ref_process+"尝试启动,关闭策略为"+ref_cl+",动作为:"+ref_act+",启动命令为:"+
              ref_cmd2+"。返回值为:"+_return+"。";
            richTextBox1.AppendText(_killstate+"\r\n");
          }
        }
      }//end for listbox
 
    }

小结

开发这款小工具,也是初识 System.Diagnostics(与系统进程、事件日志和性能计数器进行交互的类)的一个过程。


这里可以下载完整源码:https://download.csdn.net/download/michaelline/89140846


工具仅作学习使用,大家感兴趣的话可以按照自己的需求进行修改,感谢您的阅读,希望本文能对您有所帮助。



相关文章
|
7月前
|
IDE C# 开发工具
一个开源轻量级的C#代码格式化工具(支持VS和VS Code)
一个开源轻量级的C#代码格式化工具(支持VS和VS Code)
227 6
|
2月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
113 0
|
2月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
76 0
|
2月前
|
SQL JSON BI
最好的 C# .NET 报告工具
最好的 C# .NET 报告工具
51 0
|
3月前
|
消息中间件 网络协议 Python
工具人逆袭!掌握Python IPC,让你的进程从此告别单打独斗
【9月更文挑战第9天】你是否曾遇到多个Python程序像孤岛般无法通信,导致数据孤立、任务难协同的问题?掌握进程间通信(IPC)技术,可助你打破这一僵局。IPC是不同进程间传递数据或信号的机制,在Python中常用的方法有管道、消息队列、共享内存及套接字等。其中,管道适用于父子或兄弟进程间简单数据传递;套接字则不仅限于本地,还能在网络间实现复杂的数据交换。通过学习IPC,你将能设计更健壮灵活的系统架构,成为真正的编程高手。
31 3
|
3月前
|
SQL 网络协议 数据库连接
已解决:连接SqlServer出现 provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程【C#连接SqlServer踩坑记录】
本文介绍了解决连接SqlServer时出现“provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程”错误的步骤,包括更改服务器验证模式、修改sa用户设置、启用TCP/IP协议,以及检查数据库连接语句中的实例名是否正确。此外,还解释了实例名mssqlserver和sqlserver之间的区别,包括它们在默认设置、功能和用途上的差异。
|
4月前
|
C语言
【C语言】多进程创建和回收
【C语言】多进程创建和回收
80 0
|
4月前
|
消息中间件 网络协议 Python
工具人逆袭!掌握Python IPC,让你的进程从此告别单打独斗
【8月更文挑战第3天】你是否苦恼于Python程序间的“信息孤岛”现象?进程间通信(IPC)技术能助你打破壁垒。IPC是使不同进程共享数据或信号的方法。因全局解释器锁(GIL),多进程配合IPC成为高效处理数据的选择。Python提供管道、消息队列、共享内存等多种IPC手段。例如,管道适合简单父子或兄弟进程通信;套接字不仅限于网络通信,还能实现本地进程间复杂数据交换。掌握IPC,让你的进程协同作战,构建更强大灵活的系统。
29 0
|
5月前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
201 1
|
5月前
|
C#
C#进程调用FFmpeg操作音视频
因为公司需要对音视频做一些操作,比如说对系统用户的发音和背景视频进行合成,以及对多个音视频之间进行合成,还有就是在指定的源背景音频中按照对应的规则在视频的多少秒钟内插入一段客户发音等一些复杂的音视频操作。本篇文章主要讲解的是使用C#进程(Process)调用FFmpeg.exe进行视频合并、音频合并、音频与视频合并成视频这几个简单的音视频操作。