MFC实现遍历系统进程

今天我们来枚举系统中的进程和结束系统中进程。

认识几个API

1)CreateToolhelp32Snapshot

用于创建系统快照

cpp 复制代码
HANDLE WINAPI CreateToolhelp32Snapshot(       
  __in          DWORD dwFlags,               //指定快照中包含的系统内容
  __in          DWORD th32ProcessID         //指定将要快照的进程ID。如果该参数为0表示快照当前进程。
);

2) Process32First

当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,我们可以利用process32First函数来获得第一个进程的句柄.其原型为(用的是vfp)

cpp 复制代码
BOOL WINAPI Process32First(
  __in          HANDLE hSnapshot,         //CreateToolhelp32Snapshot  返回的句柄
  __in_out      LPPROCESSENTRY32 lppe     //PROCESSENTRY32 结构提的指针
);

3) Process32Next

当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,我们可以利用Process32Next函数来获得下一个进程的句柄

cpp 复制代码
BOOL WINAPI Process32Next(
  __in          HANDLE hSnapshot,        //CreateToolhelp32Snapshot  返回的句柄
  __out         LPPROCESSENTRY32 lppe    //PROCESSENTRY32 结构提的指针
);

4)OpenProcess

用来打开一个已存在的进程对象,并返回进程的句柄。

cpp 复制代码
HANDLE WINAPI OpenProcess(
  __in          DWORD dwDesiredAccess,       //打开的标识
  __in          BOOL bInheritHandle,        //是否继承句柄
  __in          DWORD dwProcessId           //被打开的进程句柄
);

5) EnumProcessModules

枚举进程里的模块

cpp 复制代码
BOOL WINAPI EnumProcessModules(
  __in          HANDLE hProcess,         //进程句柄
  __out         HMODULE* lphModule,      //返回进程里的模块
  __in          DWORD cb,                 //模块的个数
  __out         LPDWORD lpcbNeeded         //存储的模块的空间大小
);

6)GetModuleFileNameEx

得到模块的名字

cpp 复制代码
DWORD WINAPI GetModuleFileNameEx(
  __in          HANDLE hProcess,        //进程的句柄
  __in          HMODULE hModule,       //模块的句柄
  __out         LPTSTR lpFilename,     //返回模块的名字
  __in          DWORD nSize            //缓冲区大小
);

7)关闭进程

cpp 复制代码
BOOL WINAPI TerminateProcess(
  __in          HANDLE hProcess,       //进程的句柄
  __in          UINT uExitCode          //进程的退出值
);

创建一个ProcessDemo 基于对话框的工程

选择基于对话框和在静态库中使用MFC

拖出来一个listCtrl,然后为变量命名m_list

添加函数initList

添加代码:

cpp 复制代码
// 初始化列表
void CProcessDemoDlg::initList()
{
	m_list.SetExtendedStyle(LVS_EX_FLATSB | LVS_EX_FULLROWSELECT);
	m_list.InsertColumn(0, "映像名称", LVCFMT_LEFT, 100);
	m_list.InsertColumn(1, "PID", LVCFMT_LEFT, 50);
	m_list.InsertColumn(2, "程序路径", LVCFMT_LEFT, 340);
	EnumProcess();
}

结果报错,参数不匹配

这是因为第二个参数的编码问题,我们将项目的字符集修改为多字节即可

添加EnumProcess函数

添加函数实现的代码

cpp 复制代码
#include<Windows.h>
#include<TlHelp32.h>
#include<Psapi.h>
#pragma comment(lib,"Iphlpapi.lib")
#pragma comment(lib,"Psapi.lib")

// 遍历进程
void CProcessDemoDlg::EnumProcess()
{
	m_list.DeleteAllItems();
	DebugPrivilege(SE_DEBUG_NAME, TRUE);

	HANDLE			hSnapshot = NULL;
	HANDLE			hProcess = NULL;
	HMODULE			hModules = NULL;
	PROCESSENTRY32	pe32 = { 0 };
	DWORD			cbNeeded;
	char			strProcessName[MAX_PATH] = { 0 };
	LPBYTE			lpBuffer = NULL;
	DWORD			dwOffset = 0;
	DWORD			dwLength = 0;
	CString strProcessID;
	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    //创建系统快照  

	if (hSnapshot == INVALID_HANDLE_VALUE)
		return;

	pe32.dwSize = sizeof(PROCESSENTRY32);

	if (Process32First(hSnapshot, &pe32))       //枚举首个系统进程句柄
	{
		do
		{
			//打开进程句柄
			hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID);
			if ((pe32.th32ProcessID != 0) && (pe32.th32ProcessID != 4) && (pe32.th32ProcessID != 8))
			{
				//枚举进程的第一个模块其实就是自身
				EnumProcessModules(hProcess, &hModules, sizeof(hModules), &cbNeeded);
				//根据模块得到模块的名字
				GetModuleFileNameEx(hProcess, hModules, strProcessName, sizeof(strProcessName));

				m_list.InsertItem(0, pe32.szExeFile);       //进程的名字
				strProcessID.Format("%d", pe32.th32ProcessID);
				m_list.SetItemText(0, 1, strProcessID);      //进程的ID
				m_list.SetItemText(0, 2, strProcessName);    //进程 的完整名称
			}
		} while (Process32Next(hSnapshot, &pe32));         //得到快照中下一个进程
	}

	DebugPrivilege(SE_DEBUG_NAME, FALSE);
	CloseHandle(hSnapshot);                     //关闭快照
}

添加提权函数以便获取更高的权限可以遍历系统进程

cpp 复制代码
// 提权
bool CProcessDemoDlg::DebugPrivilege(const char* PName, bool bEnable)
{
	BOOL              bResult = TRUE;
	HANDLE            hToken;
	TOKEN_PRIVILEGES  TokenPrivileges;

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
	{
		bResult = FALSE;
		return bResult;
	}
	TokenPrivileges.PrivilegeCount = 1;
	TokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;

	LookupPrivilegeValue(NULL, PName, &TokenPrivileges.Privileges[0].Luid);
	AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
	if (GetLastError() != ERROR_SUCCESS)
	{
		bResult = FALSE;
	}

	CloseHandle(hToken);
	return bResult;
}

添加"刷新" 按钮并添加消息代码:

cpp 复制代码
EnumProcess();

添加"结束"按钮并添加 代码:

cpp 复制代码
void CProcessDemoDlg::OnBnClickedButtonTerminate()
{
	HANDLE hProcess = NULL;
	CString strProcessID;
	DWORD dwProcessID;
	int nSelect = m_list.GetSelectionMark();       //得到选中的条目
	if (nSelect < 0)
	{
		return;
	}
	DebugPrivilege(SE_DEBUG_NAME, TRUE);
	strProcessID = m_list.GetItemText(nSelect, 1);        //得到要结束进程的ID
	dwProcessID = atoi(strProcessID);

	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);    //打开进程获得其句柄
	TerminateProcess(hProcess, 0);       //结束进程
	CloseHandle(hProcess);      //关闭打开的句柄
	DebugPrivilege(SE_DEBUG_NAME, FALSE);
	// 稍稍Sleep下,防止出错
	Sleep(100);
	EnumProcess();
}

此时运行项目还是显示不出来条目,我们需要将2个列表的属性》视图:ICon 改为 Report:

同时不要忘记调用函数

这样我们的进程遍历工具就做好了,而且也可以刷新和结束指定进程

如果你也想修改MFC的图标可以看我这篇文章:修改MFC图标

好了今天的内容就到这里了,喜欢的话记得多多关注噢 🧡🧡🧡

相关推荐
王磊鑫1 小时前
C语言小项目——通讯录
c语言·开发语言
幽兰的天空2 小时前
介绍 HTTP 请求如何实现跨域
网络·网络协议·http
lisenustc2 小时前
HTTP post请求工具类
网络·网络协议·http
心平气和️2 小时前
HTTP 配置与应用(不同网段)
网络·网络协议·计算机网络·http
Gworg2 小时前
网站HTTP改成HTTPS
网络协议·http·https
Mbblovey3 小时前
Picsart美易照片编辑器和视频编辑器
网络·windows·软件构建·需求分析·软件需求
仟濹3 小时前
【贪心算法】洛谷P1106 - 删数问题
c语言·c++·算法·贪心算法
7ACE4 小时前
Wireshark TS | 虚假的 TCP Spurious Retransmission
网络·网络协议·tcp/ip·wireshark·tcpdump
graceyun4 小时前
C语言初阶牛客网刷题——HJ73 计算日期到天数转换【难度:简单】
c语言·开发语言
大丈夫立于天地间5 小时前
ISIS基础知识
网络·网络协议·学习·智能路由器·信息与通信