本項目將通過MFC實現一個進程管理器,如下圖詳細信息頁所示:
一.首先創建一個基于對話框的MFC項目,在靜態庫中使用MFC
二.在項目默認的對話框中添加一個列表
三.列表添加變量
四.初始化列表
1.設置列表風格和表頭
2.填充列表內容
我們需要在列表中填充操作系統中運行的各種進程的信息,因此我們需要一個函數幫助我們遍歷運行的進程并獲取相關信息
注意:遍歷進程時所使用的API,我們需要在對話框頭文件中包含相應的頭文件
首先聲明一個遍歷進程填充函數
然后實現這個遍歷進程填充函數
3.完善列表初始化
完成以上代碼書寫以后,便實現了一個簡單的沒有功能的任務管理器
五.功能實現
接下來實現任務管理器的右鍵可以結束進程或打開線程列表。線程列表右鍵結束線程或掛起恢復線程等等功能
1.列表添加一個右鍵消息處理函數
2.添加一個菜單
3.列表實現點擊右鍵彈出菜單
4.實現刷新功能
5.實現結束進程功能
6.實現創建進程功能
以下是我手搓的代碼,建議諸位參考上文的演示,自己也寫一個,有助于加深理解
// 任務管理器Dlg.cpp: 實現文件
//#include "pch.h"
#include "framework.h"
#include "任務管理器.h"
#include "任務管理器Dlg.h"
#include "afxdialogex.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于應用程序“關于”菜單項的 CAboutDlg 對話框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 對話框數據
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 實現
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// C任務管理器Dlg 對話框C任務管理器Dlg::C任務管理器Dlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_MY_DIALOG, pParent)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void C任務管理器Dlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, m_ProcessList);
}BEGIN_MESSAGE_MAP(C任務管理器Dlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_NOTIFY(NM_RCLICK, IDC_LIST1, &C任務管理器Dlg::OnRclickList1)ON_COMMAND(ID_32771, &C任務管理器Dlg::OnProcessList)ON_COMMAND(ID_32772, &C任務管理器Dlg::OnKillProcess)ON_COMMAND(ID_32773, &C任務管理器Dlg::OnCreateProcess)
END_MESSAGE_MAP()// C任務管理器Dlg 消息處理程序BOOL C任務管理器Dlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 將“關于...”菜單項添加到系統菜單中。// IDM_ABOUTBOX 必須在系統命令范圍內。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動// 執行此操作SetIcon(m_hIcon, TRUE); // 設置大圖標SetIcon(m_hIcon, FALSE); // 設置小圖標// TODO: 在此添加額外的初始化代碼m_ProcessList.SetExtendedStyle(LVS_EX_AUTOSIZECOLUMNS | LVS_EX_COLUMNSNAPPOINTS | LVS_EX_FLATSB | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);m_ProcessList.InsertColumn(0, L"進程名", LVCFMT_LEFT, 150 );m_ProcessList.InsertColumn(1, L"進程ID", LVCFMT_LEFT, 100);m_ProcessList.InsertColumn(2, L"父進程ID", LVCFMT_LEFT, 100);m_ProcessList.InsertColumn(3, L"線程數", LVCFMT_LEFT, 100);m_ProcessList.InsertColumn(4, L"優先級", LVCFMT_LEFT, 100);m_ProcessList.InsertColumn(5, L"進程路徑", LVCFMT_LEFT, 300);InitProcessList();return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}void C任務管理器Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪制該圖標。 對于使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。void C任務管理器Dlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于繪制的設備上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使圖標在工作區矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 繪制圖標dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR C任務管理器Dlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}void C任務管理器Dlg::InitProcessList()
{HANDLE hSnp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };WCHAR wcth32ProcessID[MAX_PATH];//進程IDWCHAR wcth32ParentProcessID[MAX_PATH];//父進程ID WCHAR wccntThreads[MAX_PATH];//線程數WCHAR wcpcPriClassBase[MAX_PATH];//優先級WCHAR wcProcessPath[MAX_PATH];//進程路徑BOOL Success = Process32First(hSnp, &pe);DWORD Index = 0;while (Success){HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);GetModuleFileNameEx(Process, NULL, wcProcessPath, MAX_PATH);if (Process == NULL){swprintf(wcProcessPath, L"System Module");}swprintf(wcth32ProcessID, L"%d", pe.th32ProcessID);swprintf(wcth32ParentProcessID, L"%d", pe.th32ParentProcessID);swprintf(wccntThreads, L"%d", pe.cntThreads);swprintf(wcpcPriClassBase, L"%d", pe.pcPriClassBase);m_ProcessList.InsertItem(Index, pe.szExeFile);m_ProcessList.SetItemText(Index, 1, wcth32ProcessID);m_ProcessList.SetItemText(Index, 2, wcth32ParentProcessID);m_ProcessList.SetItemText(Index, 3, wccntThreads);m_ProcessList.SetItemText(Index, 4, wcpcPriClassBase);m_ProcessList.SetItemText(Index, 5, wcProcessPath);Index++;Success = Process32Next(hSnp, &pe);}}void C任務管理器Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);// TODO: 在此添加控件通知處理程序代碼POINT pt = {};GetCursorPos(&pt);HMENU hMenu = LoadMenu(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_MENU1));hMenu = GetSubMenu(hMenu, 0);TrackPopupMenu(hMenu, TPM_CENTERALIGN, pt.x, pt.y, 0, m_hWnd, NULL);*pResult = 0;
}void C任務管理器Dlg::OnProcessList()
{// TODO: 在此添加命令處理程序代碼m_ProcessList.DeleteAllItems();InitProcessList();
}void C任務管理器Dlg::OnKillProcess()
{// TODO: 在此添加命令處理程序代碼DWORD dwIndex = (DWORD)m_ProcessList.GetFirstSelectedItemPosition();dwIndex--;CString ProcssID = m_ProcessList.GetItemText(dwIndex, 1);DWORD nProcessID = _ttoi(ProcssID);HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, nProcessID);TerminateProcess(hProcess, 1);}void C任務管理器Dlg::OnCreateProcess()
{// TODO: 在此添加命令處理程序代碼CFileDialog file(TRUE, L"exe", L"*.exe", OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY, L"可執行文件|*.exe|所有文件|.*", NULL);if (file.DoModal() == IDOK){CString FilePath = file.GetPathName();STARTUPINFO si = {};si.cb = sizeof(STARTUPINFO);PROCESS_INFORMATION pi = {};CreateProcess(FilePath, NULL, NULL, NULL, NULL, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);}}