任务管理器开发(三)

    前言:上一回分析了任务管理器中任务栏窗口的遍历及其一些操作,在接下来的一系列文章中将分析进程管理的一些详细信息及操作。先来熟悉下系统自带的任务管理器中进程管理页面的详细内容吧。

 

    在进程管理页面,可以通过菜单中的选择列来筛选需要查看进程相关信息的列数。在这些列栏中,有几个重要的名词需要解释下,因为有些名词偏离了实际的意义。

CPU Time                        --从进程开始运行所占用的总时间,其中包括KernelTime和UserTime,可以通过GetProcessTime获取。

Memory Usage Delta      --两次统计更新之间,内存使用量的变化。

Page Faults                       --应用程序请求的数据不在内存而需要从硬盘中读取的次数,从进程启动开始计算

Page Faults Delta             --和Memory Usage Delta类似,都是两次更新数据的增量

Page Pool                         --进程占用的操作系统内存数,页面池是可以分配到硬盘的虚拟内存,页面池包括所有用户的内存和操作系统内存的一部分。

其他的一些名词就不需要解释了,都可以“顾名思义”。

    

    现在看看遍历进程得到进程相关信息吧,遍历进程的方法实在是很多,我采用的是Jeffery的CToolHelp类,对Tlhelp32.h里的API进行的一些封装。

  1. #ifndef __ENUM_PROCESS_H__
  2. #define __ENUM_PROCESS_H__
  3. #include <string>
  4. #include <vector>
  5. //#include <Winternl.h>
  6. using namespace std;
  7. #ifdef _UNICODE
  8. #define string wstring
  9. #endif
  10. //typedef struct _THREAD_INFO
  11. //{
  12. //  LARGE_INTEGER CreateTime;
  13. //  DWORD dwUnknown1;
  14. //  DWORD dwStartAddress;
  15. //  DWORD StartEIP;
  16. //  DWORD dwOwnerPID;
  17. //  DWORD dwThreadId;
  18. //  DWORD dwCurrentPriority;
  19. //  DWORD dwBasePriority;
  20. //  DWORD dwContextSwitches;
  21. //  DWORD Unknown;
  22. //  DWORD WaitReason;
  23. //
  24. //}THREADINFO, *PTHREADINFO;
  25. //
  26. //
  27. //typedef struct _PROCESS_INFO
  28. //{
  29. //  DWORD dwOffset;
  30. //  DWORD dwThreadsCount;
  31. //  DWORD dwUnused1[6];
  32. //  LARGE_INTEGER CreateTime;
  33. //  LARGE_INTEGER UserTime;
  34. //  LARGE_INTEGER KernelTime;
  35. //  UNICODE_STRING ProcessName;
  36. //
  37. //  DWORD dwBasePriority;
  38. //  DWORD dwProcessID;
  39. //  DWORD dwParentProcessId;
  40. //  DWORD dwHandleCount;
  41. //  DWORD dwUnused3[2];
  42. //
  43. //  DWORD dwVirtualBytesPeak;
  44. //  DWORD dwVirtualBytes;
  45. //  ULONG dwPageFaults;
  46. //  DWORD dwWorkingSetPeak;
  47. //  DWORD dwWorkingSet;
  48. //  DWORD dwQuotaPeakPagedPoolUsage;
  49. //  DWORD dwQuotaPagedPoolUsage;
  50. //  DWORD dwQuotaPeakNonPagedPoolUsage;
  51. //  DWORD dwQuotaNonPagedPoolUsage;
  52. //  DWORD dwPageFileUsage;
  53. //  DWORD dwPageFileUsagePeak;
  54. //
  55. //  DWORD dCommitCharge;
  56. //  THREADINFO ThreadSysInfo[1];
  57. //
  58. //} PROCESSINFO, *PPROCESSINFO;
  59. namespace enumProcess
  60. {
  61. class ProcessInfo
  62. {
  63.     public:
  64.         HICON   m_hIcon;                    // 进程图标
  65.         DWORD   m_dwID;                     // 进程ID
  66.         string  m_strProcessName;           // 进程名字
  67.         string  m_strProcessID;             // 进程ID
  68.         
  69.         string  m_strCPUUsage;              // 进程CPU使用率
  70.         string  m_strCPUTime;               // 进程CPU使用时间
  71.         string  m_strMemUsage;              // 内存使用率
  72.         string  m_strMemDelta;              // 内存增量
  73.         string  m_strMemPeakUsage;          // 内存使用峰值
  74.         string  m_strPageFaults;            // 页面错误
  75.         string  m_strPageSize;              // 虚拟内存使用率
  76.         string  m_strPagePoolUsage;         // 页面池使用率
  77.         string  m_strPageNonPollUsage;      // 非页面池使用率
  78.         string  m_strUserObject;            // 用户对象
  79.         string  m_strGDIObject;             // GDI对象
  80.         string  m_strSessionID;             // Session ID
  81.         string  m_strHandleCount;           // 句柄总数
  82.         string  m_strIORead;                // IO执行读取数
  83.         string  m_strIOReadByte;            // IO读取字节数
  84.         string  m_strIOWrite;               // IO执行写入数
  85.         string  m_strIOWriteByte;           // IO写入字节数
  86.         string  m_strIOOther;               // IO执行其他数
  87.         string  m_strIOOtherByte;           // IO其他字节数
  88.         string  m_strPriority;              // 进程优先级
  89.         string  m_strUserName;              // 进程关联用户名
  90.         string  m_strThreadCount;           // 进程包含线程数
  91.         string  m_strProcessPath;           // 进程执行路径
  92. };
  93. typedef vector<ProcessInfo> TvecProInfo;
  94. class EnumProcess
  95. {
  96.     public:
  97.         EnumProcess();
  98.         EnumProcess(const EnumProcess &src);
  99.         //EnumProcess &operator=(const EnumProcess &src);
  100.         virtual ~EnumProcess();
  101.         TvecProInfo &GetProcessInfo();
  102.         void Clear();       // 清空
  103.         void Init();        // 初始化
  104.         void Enum();        // 遍历进程时间
  105.     private:
  106.         void    GetProcessName(ProcessInfo &proInfo);
  107.         void    GetProcessID(ProcessInfo &proInfo,DWORD dwID);
  108.         void    GetCPUUsage(ProcessInfo &proInfo,DWORD dwID);
  109.         void    GetCPUTime(ProcessInfo &proInfo,DWORD dwID);
  110.         void    GetMemInfo(ProcessInfo &proInfo,DWORD dwID);
  111.         void    GetResourceObject(ProcessInfo &proInfo,DWORD dwID);
  112.         void    GetProcessSessionID(ProcessInfo &proInfo,DWORD dwID);
  113.         void    GetProcessHandleCount(ProcessInfo &proInfo,DWORD dwID);
  114.         void    GetProcessIOInfo(ProcessInfo &proInfo,DWORD dwID);
  115.         void    GetProcessPriority(ProcessInfo &proInfo,DWORD dwID);
  116.         void    GetProcessUserName(ProcessInfo &proInfo,DWORD dwID);
  117.         void    GetThreadCount(ProcessInfo &proInfo,DWORD dwCount);
  118.         void    GetProcessPath(ProcessInfo &proInfo,DWORD dwID);
  119.         void    GetProcessIcon(ProcessInfo &proInfo,LPCTSTR lpszPath);
  120.     private:
  121.         void    TranslateFilename(LPCTSTR szFilename, LPTSTR szWin32Name);  // 转换路径帮助函数
  122.         void    FormatNumber(DWORD dwNumber, TCHAR *szNumber, TCHAR cSeparator, DWORD GroupLength);// 转换数据格式帮助函数
  123.     public:
  124.         TvecProInfo m_vecProInfo;
  125. };  // end of class
  126. };  // end of namespace
  127. #endif

从这个遍历进程信息的类头文件中,可以看出需要得到指定进程的信息,只要知道进程的ID,然后再通过API调用就可以得到信息。在这里,需要特别提一下NtQuerySystemInformation,这个函数功能十分强大,强大到超出你的想象~但是MSDN上用大大的红字提示我们

[NtQueryInformationProcess may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]

所以,我还是决定放弃使用这个函数,相应的我只能通过各个API来组合达到目的了。在这里,只需要说明几个特别的地方就可以了。

进程的CPU使用率:计算进程CPU的使用率就是计算进程占用CPU的时间:

  1. CPUsage = 100 * CurrentProcessCPUsage / TotalProcessCPUsage;
  2. CurrentProcessCPUsage = CurrentProcess.KernelTime + CurrentProcess.UserTime
  3. TotalProcessCPUsage = TotalProcess.KernelTime + TotalProcess.UserTime

进程CPU使用时间是GetProcessTime中KernelTime加上UserTime得来的,同时需要转换成系统时间

进程的内存使用信息可以通过GetProcessMemoryInfo获取,其中结构PROCESS_MEMORY_COUNTERS提供了许多有用的信息,具体察看MSDN吧

进程的User Objects和GDI Objects是通过GetGuiResources来获取的

进程的IO信息是GetProcessIoCounters

进程的映像路径GetModuleFileNameEx,然后就可以通过这个路径获取进程的icon了SHGetFileInfo

进程的用户名是

  1. // 获取进程用户名
  2. void EnumProcess::GetProcessUserName(ProcessInfo &proInfo,DWORD dwID)
  3. {
  4.     HANDLE hProcess =NULL;
  5.     HANDLE hToken   =NULL;
  6.     BOOL bResult    =FALSE;
  7.     DWORD dwSize    =0;
  8.     static TCHAR szUserName[MAX_PATH]   ={0};
  9.     static TCHAR szDomain[MAX_PATH]     ={0};
  10.     DWORD dwDomainSize                  =MAX_PATH;
  11.     DWORD dwNameSize                    =MAX_PATH;
  12.     SID_NAME_USE    SNU;
  13.     PTOKEN_USER pTokenUser=NULL;
  14.     __try
  15.     { 
  16.         hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION | TOKEN_ADJUST_PRIVILEGES,
  17.             FALSE,dwID);
  18.         if( hProcess==NULL )
  19.             __leave;
  20.         if( !::OpenProcessToken(hProcess,TOKEN_QUERY,&hToken) )
  21.         {
  22.             int nErr=::GetLastError();
  23.             bResult = FALSE;
  24.             __leave;
  25.         }
  26.         if( !::GetTokenInformation(hToken,TokenUser,pTokenUser,dwSize,&dwSize) )
  27.         {
  28.             if( ::GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  29.             {
  30.                 bResult = FALSE; 
  31.                 __leave;
  32.             }
  33.         }
  34.         pTokenUser = NULL;
  35.         pTokenUser = (PTOKEN_USER)malloc(dwSize);
  36.         if( pTokenUser == NULL )
  37.         {
  38.             bResult = FALSE;
  39.             __leave;
  40.         }
  41.         if( !::GetTokenInformation(hToken,TokenUser,pTokenUser,dwSize,&dwSize) )
  42.         {
  43.             bResult = FALSE;
  44.             __leave;
  45.         }
  46.         if( ::LookupAccountSid(NULL,pTokenUser->User.Sid,szUserName,&dwNameSize,szDomain,&dwDomainSize,&SNU) != 0 )
  47.         {
  48.             proInfo.m_strUserName+=_T("");
  49.             proInfo.m_strUserName+=szDomain;
  50.             proInfo.m_strUserName+=_T("//");
  51.             proInfo.m_strUserName+=szUserName;
  52.         }
  53.     }
  54.     __finally
  55.     {
  56.         if( hProcess!=NULL )
  57.             ::CloseHandle(hProcess);
  58.         if( hToken!=NULL )
  59.             ::CloseHandle(hToken);
  60.         if( pTokenUser!=NULL )
  61.             free(pTokenUser);
  62.     }
  63. }

其他好像没有什么难度了,只要知道相关的API就容易了。最后,附上参考了的文章链接吧,我觉得相当有用!

MS的官方介绍:http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/core/fneb_mon_oyjs.mspx?mfr=true

定制调试诊断工具和实用程序(这个也是MS的,不过这是翻译文档):http://www.vckbase.com/document/viewdoc/?id=1590

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值