Я бы не использовал Псапи. И это не слишком сложно:
#include <cstddef> // std::size_t
#include <vector> // std::vector<>
#include <string> // std::wstring
#include <sstream> // std::wostringstream
#include <windows.h>
#include <tlhelp32.h> // CreateToolhelp32Snapshot(), Process32FirstW(),
// Process32NextW(),
#include <commctrl.h> // InitCommonControlsEx(), ICC_LISTVIEW_CLASSES, WC_LISTVIEWW
#pragma comment(lib, "comctl32.lib") // tell Linker to link against the
// Windows Common Controls Library
struct process_data_t { // datastructure to represent a process
std::wstring pid; // number as string for convenience
std::wstring name; // the name of the executable
};
// function to get the current processes running on the system
void update_process_data(std::vector<process_data_t> &process_data)
{
// take a snapshot of the running processes
auto snapshot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
if (snapshot == INVALID_HANDLE_VALUE) { // validate the result
MessageBoxW(nullptr, L"CreateToolhelp32Snapshot() failed :(", L"Error:", MB_ICONEXCLAMATION);
return;
}
// Process32FirstW() and Process32NextW() will fill a structure of type
PROCESSENTRY32W pe{ sizeof pe }; // with info about one process at
if (!Process32FirstW(snapshot, &pe)) { // a time from the snapshot
MessageBoxW(nullptr, L"Process32FirstW() failed :(", L"Error:", MB_ICONEXCLAMATION);
CloseHandle(snapshot);
return;
}
BOOL result{ true }; // result of Process32NextW()
process_data.clear(); // discard the old data
for (std::size_t i{}; result; result = Process32NextW(snapshot, &pe), ++i) {
if (i + 1 > process_data.capacity()) // if we come close to the vectors
process_data.reserve(process_data.capacity() + 100); // capacity, increase it
std::wostringstream woss; // a stream to convert the process-id
woss << pe.th32ProcessID; // to a std::wstring
// add the data to our vector:
process_data.push_back({ woss.str(), pe.szExeFile });
}
// don't forget to close the handle opened by CreateToolhelp32Snapshot()
CloseHandle(snapshot); // better solution: use a `std::unique_ptr<>` with
}; // a custom deleter. Sorry, was to lazy to do so.
// Window procedure that will get called when our application receives messages
LRESULT APIENTRY window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
{
static HWND list_view; // a handle to the listview we'll create in WM_CREATE
static std::vector<process_data_t> process_data; // data about processes
// to display in the
// listview
switch (message) {
case WM_CREATE: // create child-windows when the parent gets created:
{
CREATESTRUCTW *create_struct{ reinterpret_cast<CREATESTRUCTW*>(lparam) };
list_view = CreateWindowW(WC_LISTVIEWW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_OWNERDATA,
5, 5, create_struct->cx - 10, create_struct->cy - 10,
window, (HMENU)100, create_struct->hInstance, nullptr);
if (!list_view) // abort window creation if
return -1; // creation of the listview child failed
LVCOLUMNW columns[2]; // to add 2 columns to our listview
columns[0].mask = columns[1].mask = LVCF_TEXT | LVCF_WIDTH;
columns[0].pszText = const_cast<wchar_t*>(L"PID");
columns[0].cx = 200; // width of the column
columns[1].pszText = const_cast<wchar_t*>(L"Name");
columns[1].cx = 800; // dito
for (std::size_t i{}; i < std::size(columns); ++i) {
// insert the column to the listview:
if (SendMessageW(list_view, LVM_INSERTCOLUMN, i, reinterpret_cast<LPARAM>(&columns[i])) == -1)
return -1;
}
update_process_data(process_data); // populate our process data
// tell the listview how many items to display:
SendMessageW(list_view, LVM_SETITEMCOUNT, process_data.size(), LVSICF_NOSCROLL);
// have Windows send us a message (WM_TIMER) every 250 ms
SetTimer(window, 0, 250, nullptr);
return 0; // all went well.
}
case WM_TIMER: // message we receive every 250 ms to update
update_process_data(process_data); // the process data
// and inform the listview about changes in the item count
SendMessageW(list_view, LVM_SETITEMCOUNT, process_data.size(), LVSICF_NOSCROLL);
return 0;
case WM_NOTIFY: // we will be notified when the listview wants us
// to provide data to display
if (reinterpret_cast<NMHDR*>(lparam)->code == LVN_GETDISPINFO) {
NMLVDISPINFO *dispinfo{ reinterpret_cast<NMLVDISPINFO*>(lparam) };
if (dispinfo->item.iSubItem) { // if the listview wants subitem
// at index dispinfo->item.iItem
dispinfo->item.pszText = const_cast<wchar_t*>(process_data[dispinfo->item.iItem].name.c_str()); // give it the process' name
}
else {
dispinfo->item.pszText = const_cast<wchar_t*>(process_data[dispinfo->item.iItem].pid.c_str()); // give it the pid
}
return TRUE;
}
return 0;
case WM_SIZE:
// resize our child-window along with its parent:
MoveWindow(list_view, 5, 5, LOWORD(lparam) - 10, HIWORD(lparam) - 10, TRUE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(window, message, wparam, lparam);
}
int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, char*, int show_state)
{
// initialize the Windows Common Controls library to use a listview
INITCOMMONCONTROLSEX iccex{ sizeof iccex, ICC_LISTVIEW_CLASSES };
if (!InitCommonControlsEx(&iccex)) {
MessageBoxW(nullptr, L"Initializing common windows controls library failed :(", L"Error", MB_ICONEXCLAMATION);
return 0;
}
// prepare the window class for our window:
WNDCLASSW wc{};
wc.lpfnWndProc = window_proc;
wc.lpszClassName = L"Poor Mans TaskMan Window Class";
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
// register the window class and check for possible error:
ATOM window_class{ RegisterClass(&wc) };
if (!window_class) {
MessageBoxW(nullptr, L"Registering window class failed :(", L"Error", MB_ICONEXCLAMATION);
return 0;
}
// create a window of our now registered window class and handle possible error:
HWND window{ CreateWindowW(reinterpret_cast<LPCWSTR>(window_class), L"Poor Mans TaskMan", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, instance,
nullptr)
};
if (!window) {
MessageBoxW(nullptr, L"Creating window failed :(", L"Error:", MB_ICONEXCLAMATION);
return 0;
}
// update and show the window:
UpdateWindow(window);
ShowWindow(window, show_state);
// message-pump:
MSG msg;
BOOL result;
while (result = GetMessageW(&msg, nullptr, 0, 0)) {
if (result == -1)
return msg.wParam;
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}