Windows 进程管理工具的设计与实现

引子

前阵子曾提到过为了应某些人的需要,得做几个毕业设计,其中一个就是 Windows 的进程管理工具 。

在前期的规划中是做成比较高难度的那种 Windows 进程管理工具,

也就是在底层使用驱动程序来获取进程的信息,而在上层则使用 VC 做用户界面层的。

至于为什么在底层要使用驱动程序来获取进程信息而不是直接在上层使用高级语言来直接获取进程信息,

那是因为在上层中通过高级语言来获取进程信息时无法获取到某些隐藏的进程,

并且对这些获取到的进程的操作也是有限的,而在内核层里面则可以对这些进程做几乎是任何的操作。

而在用户界面层的话,说实在的,我一直对 C#Windows 窗体应用程序有些排斥感,

虽然做个漂亮界面相对于 VC 来说 C#Windows 窗体应用程序那是容易一万倍,

但要不是现在的 CPU 如此强劲的话,我总感觉其会爆了去。

但是后来由于受到时间以及个人能力等方面的影响,上述方案被否决了。

首先,要想在内核层中遍历出所有的进程并不是个容易事情的,

曾在看雪里面看了几个牛逼嘻嘻的文章,看完后,我是被搞的稀里糊涂了,

主要是那种通过遍历指定内存块来获取所有进程的方式确实够变态,

而且这种方式在不同的 Windows 操作系统版本当中还完全不一样,

其次,由于在那段时间里面做的毕业设计确实比较多,

时间太紧了,根本没有太多时间去琢磨这种变态的方式了,

所以在后来的 Windows 进程管理工具的开发中我便没有采用上面那种在内核层里面获取进程信息的方式了,

而是直接在上层中调用简单的 Win32 API 来完成了所有进程的获取。

而在用户界面层上,本来确实是想使用 VC 来做的,但是众所周知的是,用 VC 想做个漂亮界面那着实不容易,

而且在 VC 上,说实话,我并不那么精通,相对于 C# 来说,我熟悉很多,开发起来速度也会快很多,

所以在最终方案的确定上,我采用 C# 来做用户界面层,而在 C# 中调用 Win32 API 也是很容易的,

直接通过平台调用即可以实现,上面谈到的即是这个小项目的开发背景了。

             

            

设计

关于设计这一块的话,由于是给某某人做的毕业设计,

所以就直接从他的毕业论文里面摘抄一些出来算了,我也省下很多功夫的。

(所以下面的很多文字和截图就来自于别人的毕业论文,有蛮多还是废话的)

项目采用三层架构设计,其实在这个项目中比没有涉及到数据库的操作,

所以肯定有人会问数据库都没有,要什么数据访问层,

但是别忘了平台调用这个东西,其实我们可以把 Win32 平台看作是数据库,

而我们的 Win32 API 则是 SQL 语句,这样不就有了数据访问层了。

其实在这里将 Win32 API 的声明放在数据访问层中也是为了代码之间的逻辑更加明确而已,并无太多实际意义。

三层架构图:

image

功能模块图:

image

1. 新任务模块

新任务模块就是能够让用户选择一个 Windows 操作系统下标准的可执行文件来创建一个新的进程。

在该模块中,用户应该要能够选择一个可执行文件,

同时在程序中还必须根据用户所选择的可执行文件来创建新的进程,从而运行可执行文件。

2. 应用程序窗口管理模块

应用程序窗口管理模块中将列举出 Windows 操作系统中当前登录的用户下的所有的应用程序窗口,

并且能够获取到这些应用程序窗口的图标以及窗口标题等等常用信息。

窗口的管理包括可以控制指定窗口的最大化或者最小化,或者是控制窗口前置和还原等等操作。

一个应用程序窗口只是一个进程的主界面窗口,所以一个应用程序窗口其实对应的是一个进程,

所以在应用程序窗口中还必须能够跳转到与该应用程序窗口相对应的进程当中。

3. 内存信息查看模块

在 Windows 操作系统自带的任务管理器中,在内存信息的查看上,其只有页面文件使用率这一项,

而在很多时候我们所要查看的却不仅仅只是页面文件使用率,我们要查看的包括虚拟内存的使用率,

物理内存的使用率等,所以在 Windows 进程管理软件当中便实现了可以查看机器虚拟内存的使用率,

物理内存的使用率,页面文件的使用率,为了方便用户查看近段时间内物理内存的使用率,

在内存信息查看模块中应当还存在一条物理内存使用率的记录曲线。

4. 处理器信息查看模块

Windows 操作系统自带的任务管理器一样,

Windows 进程管理软件中将也提供了查看当前 CPU 使用率的功能,

并且相对于 Windows 操作系统自带的任务管理器来说,

Windows 进程管理软件中的 CPU 使用率精确度更高。

5. 关机管理模块

Windows Server 系列操作系统自带的任务管理器提供了关机功能,

但是在 Windows 7 以及 Windows Vista 自带的任务管理器中则均不再提供关机功能,

虽然关机操作在 Windows 操作系统上很方便,但是有时候也并不非常方便,

所以在 Windows 进程管理软件中将提供关机管理的功能,

在该功能块中,将提供锁定、注销、待机、睡眠、休眠、重启、关机等功能。

6. 进程管理模块

进程管理模块首先需要获取当前 Windows 操作系统中所有的进程,

并且将这些进程列举在表格控件中,其中需要获取到进程的图标,进程的标志,

并且还需要计算出进程所占有的 CPU 使用率。然后进程管理需要提供的功能是结束指定进程,

挂起进程或者恢复一个已被挂起的进程,

同时对于一些非特定的进程还可以通过设置优先级来提高或者降低该进程获得 CPU 使用的几率,

从而更好的控制进程。

7. 进程模块信息模块

进程模块信息指的是一个进程在其运行过程当中所引用的模块,这些模块包括进程自身所处的可执行文件,

也包括由 Windows 操作系统所提供的动态链接库,

在很多时候,我们都需要查看一个进程引用了哪一些模块,

并且有的时候我们还需要控制一个进程对模块的引用,使得进程不能够引用某些模块。

在进程模块信息模块中所要完成的即是列举出指定进程所引用的所有的模块,

并且能够获取到这些模块的图标以及模块的名字,大小等等常用信息。

8. 进程树模块

一个进程肯定是由另外一个进程所创建的

(当然这不包括 Windows 在引导过程中由某些操作蜕化成进程的空闲进程和 System 进程),

既然一个进程肯定是由另外一个进程所创建的,那么在这些进程之间肯定是存在一棵进程树的,

而作为进程树模块就是要列举出指定进程的所有父进程,

这对于系统开发人员以及 Windows 研究人员是很有用的。

9. 进程私有内存信息模块

在有些时候,比如在调试 Windows 应用程序时,我们可能通过调试器得出了该进程中的某段内存地址信息,

但是我们无法更多的知道这段内存地址的详细信息,而这些信息在调试时是很重要的数据,

Windows 进程管理软件中便提供了这一功能,即列出指定进程下的私有内存地址信息。

10. 线程管理模块

Windows 操作系统自带的任务管理器中并不能操作指定进程的线程,

这在一定程度上造成了开发人员的不便,而在 Windows 进程管理软件中便特别针对线程进行操作。

在线程管理模块中,首先列举出了指定进程下的所有的线程信息,并且用户可以结束一个线程,

挂起一个线程或者恢复一个已被挂起的进程。

             

           

附点代码

数据访问层中的 ProcessDAL

using System;
using System.Runtime.InteropServices;
using ComType = System.Runtime.InteropServices.ComTypes;
using TaskManager.Entity;
 
namespace TaskManager.DAL
{
    public class ProcessDAL
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr hObject);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool DestroyIcon(IntPtr hIcon);
 
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool Process32First(IntPtr hSnapshot, 
            ref ProcessEntity.PROCESSENTRY32 lppe);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool Process32Next(IntPtr hSnapshot, 
            ref ProcessEntity.PROCESSENTRY32 lppe);
 
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenProcess(UInt32 fdwAccess, 
            bool fInherit, UInt32 IDProcess);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool TerminateProcess(IntPtr hProcess, UInt32 uExitCode);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern UInt32 GetCurrentProcessId();
 
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool QueryFullProcessImageName(IntPtr hProcess, 
            Int32 dwFlags, String lpExeName, ref UInt32 lpdwSize);
 
        [DllImport("Psapi.dll", CharSet = CharSet.Auto)]
        public static extern UInt32 GetProcessImageFileName(IntPtr hProcess, 
            Char[] lpImageFileName, UInt32 nSize);
 
 
        /// <summary>
        /// 通过传入进程句柄来获得该进程的时间信息
        /// </summary>
        /// <param name="ProcessHandle"></param>
        /// <param name="CreationTime"></param>
        /// <param name="ExitTime"></param>
        /// <param name="KernelTime"></param>
        /// <param name="UserTime"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        public static extern bool GetProcessTimes(IntPtr ProcessHandle, 
            out ComType.FILETIME CreationTime, out ComType.FILETIME ExitTime, 
            out ComType.FILETIME KernelTime, out ComType.FILETIME UserTime); 
 
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern UInt32 GetPriorityClass(IntPtr hProcess);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool SetPriorityClass(IntPtr hProcess, UInt32 dwPriorityClass);
 
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, 
            out ProcessEntity.MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);
 
        [DllImport("psapi.dll", CharSet = CharSet.Auto)]
        public static extern bool GetProcessMemoryInfo(IntPtr Process, 
            ref ProcessEntity.PROCESS_MEMORY_COUNTERS ppsmemCounters, Int32 cb);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetProcessIoCounters(IntPtr hProcess, 
            ref ProcessEntity.IO_COUNTERS lpIoCounters);
 
 
        //[DllImport("ntdll.dll", CharSet = CharSet.Auto)]
        //public static extern Int32 NtQueryInformationProcess(IntPtr hProcessHandle, 
        //    PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, 
        //    UInt32 processInformationLength, ref UInt32 returnLength);        
    }
}

                                 

                   

截图展示

其实废话说那么多根本没什么用的,还不如直接截几张图,然后对这个东西有兴趣的给我留个邮箱,

我直接发他源代码,他自个去看估计效果要好的多的。所以这里就直接上图了。

              

应用程序窗体(同 Windows 任务管理器一样,列出当前所有打开的的窗口):

image

                

应用程序窗体管理:

image

                       

进程界面(列举出所有的进程):

image

              

进程管理:

image

                       

处理器界面(描绘出 CPU 使用率图):

image

                                     

内存界面(描绘出内存使用率图):

image

                       

查看进程树(描绘出进程树图):

image

                

查看进程模块信息:

image

             

查看进程内存信息:

image

                 

查看进程线程信息:

image

               

通过线程管理来实现进程管理:

image

                

进程详细信息的查看:

image

                         

关机功能的实现:

image

                 

             

结束语

上面的这个 Windows 进程管理工具呢,其实里面也还是稍微有一点点内涵的,

至少在平台调用这一块上,如果你把这个 Windows 进程管理工具搞定了的话,平台调用是肯定难不住你了的。

最后呢,一直本着以前的作风,只要不是公司的项目,而且个人觉得还拿得出手的话,我一定会拿出来分享的。

但是我一直是在这个 Windows Live Writer 里面写博客,所以也不晓得怎么把这个项目给打包传上去,

所以如果觉得还可以拿去学习一下的,给我留个邮箱就是了,到时候我会把源码给你发过去的。

然后需要注意的是,这个东西大家不要肆意的传播,自己学习学习就是了,

虽然我也是给别人做的毕业设计,但我可不希望这东西又落到某位毕业生手上并又成了他的毕业设计了,

这样与我与他都不好。

              

         

版权所有,迎转载,但转载请注明: 转载自 Zachary.XiaoZhen - 梦想的天空

          

           

 

posted @ 2011-06-04 15:01  小宝马的爸爸  阅读(7476)  评论(114编辑  收藏  举报