任务管理器编码详解

模仿windows任务管理器制作一个任务管理器软件。设计语言不限。

二知识要求

   Windows编程,MFC编程,API调用

三.开发环境

使用Microsoft Visual Studio 2013的开发环境,模拟Windows的任务管理器。首先分析进程管理器软件的相关功能;其次,综合运用以前所学的相关知识,广泛查阅资料。

四.主要功能及实现思路

4.1设计要求实现的主要功能进程管理功能,具体包括以下内容:

(1) 使用系统API。

(2) 制作出相应的图形用户界面。

(3) 至少包括三个功能:

  • 获取、显示、控制(结束任务)当前系统中的应用程序;
  • 获取、显示、控制(结束进程)当前系统中的进程;
  • 获取、显示当前系统CPU及内存的使用情况。

4.2实现思路

   4.2.1界面设计

所设计的程序是基于对话框的程序。首先创建一个MFC的应用程序, 在主对话框类中添加一个TabContrl标签控件用于放置应用程序、进程和CPU信息三个页面,

子对话框的显示与切换,是通过标签控件完成的。当用户点击标签控件上的每一项时,分别显示对应页面的相关信息。

要显示三个子对话框,需要添加三个对话框到工程中,并将Style属性设为Child,Board设为None,取消标题栏。再分别创建三个对话框的类CTask ,CProcess,CChart,并定义这三个类的变量:

CTask m_Task; //任务

CProcess m_Process; //进程

CChart m_Chart; //图表

接下来就创建子窗口:

m_Tab.InsertItem(0, _T("应用程序"), 60);//向tab控件中添加每个参数选项卡的值
m_Tab.InsertItem(1, _T("进程信息"), 60);
m_Tab.InsertItem(2, _T("CPU信息"), 60);
//关联对话框,让tab控件为父窗口
m_Task.Create(IDD_TASK, &m_Tab);
m_Process.Create(IDD_PROCESS, &m_Tab);
m_Chart.Create(IDD_CHART, &m_Tab);
当用户选择标签中的一项是,为了将对应的对话框在标签控件中显示出来,需要在OnShowWindow(BOOL bShow,UINT nStatus)中添加代码相关代码。这样便可将在个对话框分别显示于标签控件的每个页面中,但要实现选择标签的不同项显示不同页面还需在OnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)添加显示代码。核心代码如下:
void CTaskMgrDlg::OnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)
{
   // TODO:  在此添加控件通知处理程序代码
   *pResult = 0;
 CRect tabRect;
   m_Tab.GetClientRect(&tabRect);
   tabRect.top += 20;
   tabRect.left += 1;
   tabRect.right += 1;
   tabRect.bottom += 1;
   switch (m_Tab.GetCurSel())//根据鼠标选择的标签进行显示相应的对话框
   {
   case 0:
      m_Task.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);//SWP_SHOWWINDOW:显示窗口
      m_Process.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);//SWP_HIDEWINDOW:隐藏窗口
      m_Chart.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
      break;
   case 1:
      m_Task.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
      m_Process.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
      m_Chart.SetWindowPos(NULL,tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
      break;
   case 2:
      m_Task.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
      m_Process.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
      m_Chart.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
      break;
   default:
      break;
   }
}

4.2.2有关应用程序的功能实现

查看应用程序:

   EnumWindowsProc函数

参数

hwnd:顶层窗口句柄。

lParam:指定在EnumWindows或EnumDesktopWindows中的应用程序定义值。

返回值

为继续列表,回调函数必须返回TRUE;若停止列表,它必须返回FALSE。

备注

应用程序必须通过传递给EnumWindows或EnumDesktopWindows应用程序地址来注册这个回调函数。

EnumWindows函数

函数功能 该函数枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数。回调函数返回FALSE将停止枚举,否则EnumWindows函数继续到所有顶层窗口枚举完为止。 函数原型 BOOL EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam);

参数: lpEnumFunc:指向一个应用程序定义的回调函数指针,请参看EnumWindowsProc。 lPararm:指定一个传递给回调函数的应用程序定义值。

回调函数原型

 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
   if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && ((GetWindowLong(hWnd, GWL_EXSTYLE)&WS_EX_TOOLWINDOW) != WS_EX_TOOLWINDOW) &&
      (GetWindowLong(hWnd, GWL_HWNDPARENT) == 0))//判断条件
   {
 TCHAR WindowTitle[100] = { 0 };
      ::GetWindowText(hWnd, WindowTitle, 100);
      int m = n++;
      buf[m] = WindowTitle;
 DWORD dwProcessID = 0;
      dwProcessID = GetWindowThreadProcessId(hWnd, &dwProcessID);
      id[m].Format(_T("%d"), dwProcessID);
      HD[m] = hWnd;
   }
   return true;
}

结束应用程序

   根据应用程序的生命周期,以及窗口的消息循环,当关闭窗口或者应用程序(就是点上面的叉号),发出WM_CLOSE消息,但是translatemessage函数,进入while消息循环,被默认的情况进行处理,最后::PostMessage()函数接受消息,发送WM_QUIT消息,窗口关闭,程序结束。;

源码实现:

void CTask::OnBnClickedEndapp()
{
   // TODO:  在此添加控件通知处理程序代码
 CString str;
   int iRow = m_taskList.GetSelectionMark();
   str = m_taskList.GetItemText(iRow, 1);
   for (int i = n; i >= 1; i--)
   {
      if (str == id[i])
      {
        ::PostMessage(HD[i], WM_QUIT, 0, 0);//向结束的应用程序进行发送WM_QUIT消息
        break;
      }
   }
}

4.2.3有关进程的功能实现

查看进程:

这个主要是用到TlHelp32.h头文件里有关进程的定义。

在创建进程快照时,首先,定义一个进程结构体,然后在创建

PROCESSENTRY32 procList;   //这是一个进程结构体

procList.dwSize = sizeof(PROCESSENTRY32); //在使用这个结构体之前先定义这个结构体的大小

HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

应用到的函数:

CreateToolhelp32Snapshot

函数通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照.

说到底,可以获取系统中正在运行的进程信息,线程信息,等

HANDLE WINAPI CreateToolhelp32Snapshot(

DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等

DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0

Process32First(),Process32Next()函数用来遍历进程

结束进程:

TerminateProcess

BOOL TerminateProcess(

HANDLE hProcess,//进程句柄

UINT uExitCode //进程终止码

);

4.2.4有关CPU的功能实现

查看CPU的利用率

   利用率的介绍:CPU在t1到t2时间段即时利用率 =  1 - CPU空闲使用时间 / CPU总的使用时间

核心代码:

   res = GetSystemTimes(&idleTime, &kernelTime, &userTime);
   preidleTime = idleTime;;//系统是空闲的时间
   prekernelTime = kernelTime;//;//FILETIME结构指针接收系统的时间花费在内核模式执行
   preuserTime = userTime;//FILETIME结构指针接收系统的时间花了在用户模式下执行
   hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // 初始值为 nonsignaled ,并且每次触发后自动设置为nonsignaled
 WaitForSingleObject(hEvent, 1000); //
   res = GetSystemTimes(&idleTime, &kernelTime, &userTime);
   int idle = CompareFileTime(preidleTime, idleTime);
   int kernel = CompareFileTime(prekernelTime, kernelTime);
   int user = CompareFileTime(preuserTime, userTime);
   int cpu = (kernel + user - idle) * 100 / (kernel + user);//CPU利用率
   int cpuidle = (idle)* 100 / (kernel + user);//CPU空闲率

画图:主要用到的是CPen类

画图函数:

   void CChart::DrawWaveCPU(CDC* pCD, CRect& rectPicture)
{
   float fDeltaX;     // x轴相邻两个绘图点的坐标距离  
   float fDeltaY;     // y轴每个逻辑单位对应的坐标值  
   int nX;      // 在连线时用于存储绘图点的横坐标  
   int nY;      // 在连线时用于存储绘图点的纵坐标  
 CPen newPen;       // 用于创建新画笔  
 CPen *pOldPen;     // 用于存放旧画笔  
 CBrush newBrush;   // 用于创建新画刷  
 CBrush *pOldBrush; // 用于存放旧画刷  
   // 计算fDeltaX和fDeltaY  
   fDeltaX = (float)rectPicture.Width() / (POINT_COUNT - 1);
   fDeltaY = (float)rectPicture.Height() / 80;
   // 创建黑色新画刷  
   newBrush.CreateSolidBrush(RGB(0, 0, 0));
   // 选择新画刷,并将旧画刷的指针保存到pOldBrush  
   pOldBrush = pCD->SelectObject(&newBrush);
   // 以黑色画刷为绘图控件填充黑色,形成黑色背景  
   pCD->Rectangle(rectPicture);
   // 恢复旧画刷  
   pCD->SelectObject(pOldBrush);
   // 删除新画刷  
   newBrush.DeleteObject();
   // 创建实心画笔,粗度为1,颜色为绿色  
   newPen.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
   // 选择新画笔,并将旧画笔的指针保存到pOldPen  
   pOldPen = pCD->SelectObject(&newPen);
   // 将当前点移动到绘图控件窗口的左下角,以此为波形的起始点  
   pCD->MoveTo(rectPicture.left, rectPicture.bottom);
   // 计算m_nzValues数组中每个点对应的坐标位置,并依次连接,最终形成曲线  
   for (int i = 0; i < POINT_COUNT; i++)
   {
      nX = rectPicture.left + (int)(i * fDeltaX);
      nY = rectPicture.bottom - (int)(m_nzValues[i] * fDeltaY);
      pCD->LineTo(nX, nY);
   }
   // 恢复旧画笔  
   pCD->SelectObject(pOldPen);
   // 删除新画笔  
   newPen.DeleteObject();
}

实现功能的核心代码主要是这些。

五 收获

   通过这个小任务(其实这个任务一点也不小),花费了好长好长时间,做的过程中,深受折磨。首先,没有学过MFC,无从下手,就从图书馆里借了本书《深入简出MFC》这本书说实话真不错,它从整体上讲解了MFC,讲解了Windows编程,它们之间的联系,区别。但是对于像我这种想很快入手的人来说,实不可取的,尤其是在这么多的时间。然后就在网上搜源代码,类似:windows任务管理器源代码神马的。

主要的网站:CSDN,PUDN,codefree。

搜索引擎:百度,图灵搜索,谷歌婊,好搜

搜索时,最好搜博客,讲解详细。

   还发现了自己的一些不足之处:最重要的就是犹豫不前,搜索到以后就一个就可以开始写,我们要在写的过程中发现自己的问题,而不是先整体上有框架,知道具体的实现过程,这是不可取的。正确的做法是要边做边发现问题。不要犹豫,先下手。然后就是,在实现过程中,我们可以做个整体分析,将要实现的功能列出来,然后一个一个的实现。只有做了才能发现自己的不足之处。我们总是自我感觉良好,但是,现实却是残酷的。还有,要加强英语学习,一些好的资料英文写的比较多,再说了,如果我们能多掌握一种语言,就不止掌握了多一种资源了。最后,深刻体会到,开源的重要性,只有交流,才能让自己不断提高。最最后,要写上注释!要写上注释!要写上注释!

重要的话说三遍!

2015.12.15

参考资料:

http://www.jizhuomi.com/software/257.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏移动开发之家

Flutter完整开发实战详解(二、 快速开发实战篇)

 作为系列文章的第二篇,继《Flutter完整开发实战详解(一、Dart语言和Flutter基础)》之后,本篇将为你着重展示:如何搭建一个通用的Flutter ...

9423
来自专栏木子墨的前端日常

react-navigation 使用笔记 持续更新中

React-Navigation是目前React-Native官方推荐的导航组件,代替了原用的Navigator。最近开始接触,做个笔记

1174
来自专栏Young Dreamer

html5之histroy浅析

history是HTML5的新特性,我们可以使用它操作这个历史记录堆栈。 (1)history提供了对浏览器历史纪录堆栈的读取,同时实现在访问记录中的前进和后退...

2077
来自专栏狮乐园

高级 Angular 组件模式 (6)

Render Props最近在React社区中引起了轰动,但是与之类似的模式在Angular中似乎并没有得到太多关注。我在之前写的文章提及过,TemplateR...

981
来自专栏Windows Community

Extensions in UWP Community Toolkit - Overview

概述 UWP Community Toolkit  中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先...

38712
来自专栏老九学堂

超详细的Web 前端知识体系,等你来挑战!

作为苦逼的IT行业,没日没夜的加班,妹纸也少的可怜,就算在一个班办公室或者一个部门,可能也只有一个妹纸,但估计也轮不到你来上,只能眼巴巴的放着光。可是程序猿一直...

4007
来自专栏debugeeker的专栏

xss渗透试验(3)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

851
来自专栏Debian社区

Web前端知识体系精简

Web前端技术由html、css和javascript三大部分构成,是一个庞大而复杂的技术体系,其复杂程度不低于任何一门后端语言。而我们在学习它的时候往往是先从...

1623
来自专栏GIS讲堂

基于Arcgis for Js的web GIS数据在线采集简介

在前一篇博文“Arcgis for js之WKT和geometry转换”中实现了wkt和geometry之间的相互转化,博文原文地址为:http://blog....

1112
来自专栏黑泽君的专栏

java基础学习_GUI_如何让Netbeans的东西Eclipse能访问、GUI(图形用户接口)_day25总结

java基础学习_GUI_如何让Netbeans的东西Eclipse能访问、GUI(图形用户接口)_day25总结

912

扫码关注云+社区

领取腾讯云代金券