问题遇到的现象和发生背景
我本来想写一个qt的任务管理器,但是写着写着就发现,他的展开设置不管用了。
遇到的现象和发生背景,请写出第一个错误信息
如果给SelectProcessByPID的最后一个参数传入true那它就会进入保存模式。但是我在保存后输出了expandedPids,却发现它只是一个空的QList的对象,就像没有保存成功一样的。
用代码块功能插入代码,请勿粘贴截图。 不用代码块回答率下降 50%
#include <QApplication>
#include <QMainWindow>
#include <QTreeView>
#include <QStandardItemModel>
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <QMenu>
#include <QAction>
#include <QTimer>
#include <QModelIndexList>
#include <QItemSelectionModel>
#include <QMessageBox>
#include <QString>
#include <winternl.h>
#include <vector>
#include <string>
#include <winternl.h>
#include <map>
#include <sddl.h>
#include <shellapi.h>
#include <tchar.h>
#include <QPixmap>
#include <QIcon>
#include <QImage>
#include <QMap>
#include <shlobj.h>
#include <unordered_map>
#include <QScrollBar>
enum ProcessState {
Running,
Suspend,
Unknow
};
enum ProcessPriority{
INORMAL,
IDLE,
BELOW_NORMAL,
ABOVE_NORMAL,
HIGH,
REALTIME
};
struct ProcessInfo {
DWORD pid;
QString name;
double cpuUsage;
SIZE_T memoryUsage;
ProcessState State;
std::string User;
int theadCount;
ProcessPriority Priority;
DWORD parentPID;
};
// 需要一个新的结构来保存进程信息并构建树
struct ProcessTreeNode {
ProcessInfo info;
std::vector<ProcessTreeNode*> children;
};
// 获取当前选中的 PID
QList<DWORD> selectedPids;
QList<DWORD> expandedPids;
std::unordered_map<DWORD, ProcessTreeNode*> processMap;
// 全局变量,用于标记用户是否正在操作滚动条
bool isUserScrolling = false;
//在原结构之后加上不影响结构大小的线程数组,巧妙运用越界带来的跨结构访问后面的线程结构
typedef struct _MYSYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG PageDirectoryBase;
VM_COUNTERS VirtualMemoryCounters;
SIZE_T PrivatePageCount;
IO_COUNTERS IoCounters;
//以上为原结构内容
SYSTEM_THREAD_INFORMATION Threads[0];
} MYSYSTEM_PROCESS_INFORMATION, *PMYSYSTEM_PROCESS_INFORMATION;
//覆盖原定义
#define SYSTEM_PROCESS_INFORMATION MYSYSTEM_PROCESS_INFORMATION
#define PSYSTEM_PROCESS_INFORMATION PMYSYSTEM_PROCESS_INFORMATION
bool isTokenSystem(HANDLE hToken) {
// 获取 SYSTEM 用户的 SID
PSID pSystemSid;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid)) {
qDebug() << "Failed to allocate SYSTEM SID. Error:" << GetLastError();
return false;
}
// 查询令牌信息大小
DWORD dwLengthNeeded;
if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLengthNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
qDebug() << "Failed to get token information size. Error:" << GetLastError();
FreeSid(pSystemSid);
return false;
}
// 分配缓冲区获取令牌信息
PTOKEN_USER pTokenUser = (PTOKEN_USER)GlobalAlloc(GPTR, dwLengthNeeded);
if (pTokenUser == NULL) {
qDebug() << "Failed to allocate memory for token information.";
FreeSid(pSystemSid);
return false;
}
// 获取令牌信息
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwLengthNeeded, &dwLengthNeeded)) {
qDebug() << "Failed to get token information. Error:" << GetLastError();
GlobalFree(pTokenUser);
FreeSid(pSystemSid);
return false;
}
// 比较用户 SID
BOOL bIsSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
GlobalFree(pTokenUser);
FreeSid(pSystemSid);
return (bIsSystem == TRUE);
}
bool checkToken() {
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
qDebug() << "Failed to open process token. Error:" << GetLastError();
return true;
}
if (isTokenSystem(hToken)) {
return true;
} else {
return false;
}
CloseHandle(hToken);
}
ProcessPriority GetProcessPriority(DWORD processID){
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processID);
DWORD priorityClass = GetPriorityClass(hProcess);
if (priorityClass == REALTIME_PRIORITY_CLASS){
return REALTIME;
} else if (priorityClass == IDLE_PRIORITY_CLASS){
return IDLE;
} else if (priorityClass == HIGH_PRIORITY_CLASS){
return HIGH;
} else if (priorityClass == BELOW_NORMAL_PRIORITY_CLASS){
return BELOW_NORMAL;
} else if (priorityClass == ABOVE_NORMAL_PRIORITY_CLASS){
return ABOVE_NORMAL;
} else {
return INORMAL;
}
}
std::unordered_map<DWORD, QIcon> iconCache;
//这里省略获取图标、提权的方法
//定义函数原型
typedef NTSTATUS(NTSYSAPI NTAPI *FunNtQuerySystemInformation)
(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL);
struct MtheadInfo
{
std::map<DWORD, ProcessState> State;
std::map<DWORD, int> count;
};
MtheadInfo GetProcessState() {
// 使用 std::map,键为 DWORD,值为 ProcessState 枚举类型
std::map<DWORD, ProcessState> processStates;
std::map<DWORD, int> theadCount;
MtheadInfo MInfo;
//取函数地址
FunNtQuerySystemInformation mNtQuerySystemInformation = FunNtQuerySystemInformation(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation"));
//先调用一次,获取所需缓冲区大小
DWORD dwSize;
mNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &dwSize);
//申请缓冲区
HGLOBAL hBuffer = GlobalAlloc(LPTR, dwSize);
if (hBuffer == NULL)
return MInfo;
PSYSTEM_PROCESS_INFORMATION pInfo = PSYSTEM_PROCESS_INFORMATION(hBuffer);
//查询
NTSTATUS lStatus = mNtQuerySystemInformation(SystemProcessInformation, pInfo, dwSize, 0);
if (!NT_SUCCESS(lStatus)) {
GlobalFree(hBuffer);
return MInfo;
}
//遍历进程
ProcessState State;
while (true) {
State = Suspend;
//遍历线程
ULONG NfThreads = pInfo->NumberOfThreads;
for (ULONG i = 0; i < NfThreads; i++) {
//如果不是在挂起,就表明程序存活,可以返回(堵塞、无响应不算挂起)
if (pInfo->Threads[i].WaitReason != Suspended) {
State = Running;
break;
}
}
processStates[((DWORD)(ULONG_PTR) pInfo->UniqueProcessId)] = State;
theadCount[((DWORD)(ULONG_PTR) pInfo->UniqueProcessId)] = static_cast<int>(NfThreads);
//遍历进程完成
if (pInfo->NextEntryOffset == 0)
break;
//移动到下一个进程信息结构的地址
pInfo = PSYSTEM_PROCESS_INFORMATION(PBYTE(pInfo) + pInfo->NextEntryOffset);
}
//释放缓冲区
GlobalFree(hBuffer);
MInfo.State = processStates;
MInfo.count = theadCount;
return MInfo;
}
std::wstring GetLastErrorAsString(DWORD errorMessageID) {
if (errorMessageID == 0) {
return std::wstring();
}
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&messageBuffer), 0, nullptr);
std::wstring message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
}
typedef NTSTATUS(WINAPI *PFN_NT_QUERY_INFORMATION_PROCESS)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
// 省略获取进程的用户名
bool GetProcessInfo(DWORD pid, double& cpuUsage, SIZE_T& memoryUsage) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL) {
return false;
}
FILETIME createTime, exitTime, kernelTime, userTime;
if (!GetProcessTimes(hProcess, &createTime, &exitTime, &kernelTime, &userTime)) {
CloseHandle(hProcess);
return false;
}
ULARGE_INTEGER createTime64, exitTime64, kernelTime64, userTime64;
createTime64.LowPart = createTime.dwLowDateTime;
createTime64.HighPart = createTime.dwHighDateTime;
exitTime64.LowPart = exitTime.dwLowDateTime;
exitTime64.HighPart = exitTime.dwHighDateTime;
kernelTime64.LowPart = kernelTime.dwLowDateTime;
kernelTime64.HighPart = kernelTime.dwHighDateTime;
userTime64.LowPart = userTime.dwLowDateTime;
userTime64.HighPart = userTime.dwHighDateTime;
FILETIME now;
GetSystemTimeAsFileTime(&now);
ULARGE_INTEGER now64;
now64.LowPart = now.dwLowDateTime;
now64.HighPart = now.dwHighDateTime;
double totalKernelTimeMs = (kernelTime64.QuadPart - createTime64.QuadPart) / 10000.0;
double totalUserTimeMs = (userTime64.QuadPart - createTime64.QuadPart) / 10000.0;
double totalTimeMs = (now64.QuadPart - createTime64.QuadPart) / 10000.0;
cpuUsage = (totalKernelTimeMs + totalUserTimeMs) / totalTimeMs;
PROCESS_MEMORY_COUNTERS_EX pmc;
if (!GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
CloseHandle(hProcess);
return false;
}
memoryUsage = pmc.WorkingSetSize;
CloseHandle(hProcess);
return true;
}
std::vector<ProcessInfo> EnumerateProcesses() {
std::vector<ProcessInfo> processes;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return processes;
}
PROCESSENTRY32 pe32;
double cpuUsage;
SIZE_T memoryUsage;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe32)) {
CloseHandle(hSnapshot);
return processes;
}
MtheadInfo MInfo = GetProcessState();
std::map ProccesState = MInfo.State;
std::map theadCount = MInfo.count;
do {
ProcessInfo info;
info.pid = pe32.th32ProcessID;
info.name = QString::fromWCharArray(pe32.szExeFile);
info.State = ProccesState[info.pid];
info.theadCount = theadCount[info.pid];
info.Priority = GetProcessPriority(info.pid);
info.parentPID = pe32.th32ParentProcessID;
if (GetProcessInfo(info.pid, cpuUsage, memoryUsage)) {
info.cpuUsage = cpuUsage;
info.memoryUsage = memoryUsage;
info.User = GetProcessUser(info.pid);
if (info.User.empty()){
info.User = static_cast<char>(*"未知");
}
processes.push_back(info);
} else {
info.cpuUsage = 0;
info.memoryUsage = 0;
info.User = GetProcessUser(info.pid);
if (info.User.empty()){
info.User = static_cast<char>(*"未知");
}
processes.push_back(info);
}
} while (Process32Next(hSnapshot, &pe32));
CloseHandle(hSnapshot);
return processes;
}
省略挂起恢复方法
BOOL IsRunAsAdmin()
{
BOOL bIsRunAsAdmin = FALSE;
PSID pAdminSid = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSid))
{
if (!CheckTokenMembership(NULL, pAdminSid, &bIsRunAsAdmin))
{
bIsRunAsAdmin = FALSE;
}
FreeSid(pAdminSid);
}
return bIsRunAsAdmin;
}
void gly()
{
TCHAR szModule[MAX_PATH];
GetModuleFileName(NULL, szModule, MAX_PATH);
SHELLEXECUTEINFO shExecInfo;
memset(&shExecInfo, 0, sizeof(SHELLEXECUTEINFO));
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = _T("runas"); // 请求管理员权限
shExecInfo.lpFile = szModule; // 当前程序路径
shExecInfo.lpParameters = _T(""); // 如果不需要传递参数,可以设置为空字符串
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_SHOW;
shExecInfo.hInstApp = NULL;
ShellExecuteEx(&shExecInfo);
ExitProcess(0);
}
void openProcessProperties(DWORD processId) {
// Construct the command to open process properties
wchar_t command[MAX_PATH];
swprintf_s(command, L"\"C:\\Windows\\System32\\taskmgr.exe\" /FI \"PID eq %u\"", processId);
// Create process info
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Create the process
CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
// Close process and thread handles
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
// 辅助函数:通过PID查找对应的父节点
ProcessTreeNode* FindParentNode(std::unordered_map<DWORD, ProcessTreeNode*>& processMap, DWORD processID) {
DWORD parentPID = processMap[processID]->info.parentPID;
auto it = processMap.find(parentPID);
if (it != processMap.end()) {
return it->second;
}
return nullptr;
}
ProcessTreeNode* BuildProcessTree(const std::vector<ProcessInfo>& processes) {
processMap.clear();
ProcessTreeNode* root = new ProcessTreeNode();
// 创建所有进程节点
for (const auto& process : processes) {
ProcessTreeNode* node = new ProcessTreeNode();
node->info = process;
processMap[process.pid] = node;
}
// 设置父子关系
for (const auto& process : processes) {
ProcessTreeNode* node = processMap[process.pid];
DWORD parentPID = node->info.parentPID; // 使用系统 API 获取父进程 ID
// 如果有父进程,添加为子节点;否则,添加到根节点下
if (parentPID != 0) {
auto it = processMap.find(parentPID);
if (it != processMap.end()) {
ProcessTreeNode* parent = it->second;
parent->children.push_back(node); // 添加为子节点
} else {
root->children.push_back(node); // 没有父进程,添加到根节点
}
}
}
// 如果根节点下有进程,转移这些进程为新的根节点
ProcessTreeNode* newRoot = new ProcessTreeNode();
for (auto child : root->children) {
newRoot->children.push_back(child);
}
delete root; // 释放原根节点
return newRoot; // 返回新的根节点
}
void AddProcessToModel(ProcessTreeNode* node, QStandardItem* parentItem) {
QList<QStandardItem*> rowItems;
QStandardItem* iconItem = new QStandardItem();
QIcon icon = GetProcessIcon(node->info.pid);
iconItem->setIcon(icon);
rowItems.append(iconItem);
// 进程名称
rowItems.append(new QStandardItem(node->info.name));
// 进程ID
rowItems.append(new QStandardItem(QString::number(node->info.pid)));
// 进程状态
QString stateStr;
switch (node->info.State) {
case Running: stateStr = "运行中"; break;
case Suspend: stateStr = "已挂起"; break;
case Unknow: stateStr = "未知"; break;
}
rowItems.append(new QStandardItem(stateStr));
// CPU使用率
rowItems.append(new QStandardItem(QString::number(node->info.cpuUsage * 5 / (1024.0 * 1024.0 * 1024.0 * 1024.0), 'f', 2) + " %"));
// 内存使用情况
rowItems.append(new QStandardItem(QString::number((float)node->info.memoryUsage / (1024.0 * 1024.0))));
// 运行用户
rowItems.append(new QStandardItem(QString::fromStdString(node->info.User)));
// 线程数量
rowItems.append(new QStandardItem(QString::number(node->info.theadCount)));
// 基本优先级
QString priorityStr;
switch (node->info.Priority) {
case INORMAL: priorityStr = "正常"; break;
case IDLE: priorityStr = "低"; break;
case BELOW_NORMAL: priorityStr = "低于正常"; break;
case ABOVE_NORMAL: priorityStr = "高于正常"; break;
case HIGH: priorityStr = "高"; break;
case REALTIME: priorityStr = "实时"; break;
}
rowItems.append(new QStandardItem(priorityStr));
// 添加到模型中
parentItem->appendRow(rowItems);
QStandardItem* selfitem = rowItems.at(0);
// 递归处理子进程
for (auto child : node->children) {
AddProcessToModel(child, selfitem);
}
}
void SelectProcessByPID(QStandardItemModel *model, const QModelIndex &parentIndex, QTreeView* treeView, bool save=false) {
for (int row = 0; row < model->rowCount(parentIndex); ++row) {
QModelIndex index = model->index(row, 2, parentIndex); // 假设 PID 存储在第三列
QStandardItem *item = model->itemFromIndex(index);
DWORD pid = item->text().toInt();
if (item&&index.isValid()) {
if (treeView->isExpanded(index)&&save) expandedPids.append(pid);
if (expandedPids.contains(pid)&&!save) treeView->expand(index);
if (selectedPids.contains(pid)) treeView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
SelectProcessByPID(model, model->index(row, 0, parentIndex), treeView, save);
}
}
}
void RefreshProcessTree(QStandardItemModel* model) {
// 获取进程列表
std::vector<ProcessInfo> processes = EnumerateProcesses();
// 构建进程树
ProcessTreeNode* root = BuildProcessTree(processes);
model->clear();
model->setHorizontalHeaderLabels({"图标", "进程名称", "进程ID", "进程状态", "CPU使用", "内存使用(MB)", "运行用户", "线程数量", "基本优先级"});
// 将新的根节点的子节点(即顶层进程)添加到模型
for (auto child : root->children) {
AddProcessToModel(child, model->invisibleRootItem());
}
delete root; // 释放原根节点
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
if (!IsRunAsAdmin()) gly();
if (!checkToken()){
try{
EnablePrivilege(SE_DEBUG_NAME);
EnablePrivilege(SE_IMPERSONATE_NAME);
//ImpersonateSystem();
}
catch (std::exception e){
QMessageBox::critical(NULL, "错误", e.what());
}
}
SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);
QMainWindow mainWindow;
mainWindow.setGeometry(100, 100, 600, 400);
mainWindow.setWindowTitle("任务管理器");
//mainWindow.setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
QTreeView *treeView = new QTreeView(&mainWindow);
QStandardItemModel* model = new QStandardItemModel();
model->setHorizontalHeaderLabels({"图标","进程名称", "进程ID", "进程状态","CPU使用", "内存使用(MB)","运行用户","线程数量","基本优先级"});
treeView->setModel(model);
QTimer timer;
timer.setInterval(500);
QObject::connect(&timer, &QTimer::timeout, [&]() {
selectedPids.clear();
QModelIndexList selectedIndices = treeView->selectionModel()->selectedIndexes();
foreach (const QModelIndex &index, selectedIndices) {
DWORD pid = index.data().toInt();
selectedPids.append(pid);
}
expandedPids.clear();
// 保存当前展开状态
SelectProcessByPID(model, model->invisibleRootItem()->index(), treeView, true);
qDebug()<<expandedPids;
// 保存滚动条位置
QScrollBar* verticalScrollBar = treeView->verticalScrollBar();
int currentV = verticalScrollBar->value();
// 刷新进程树
RefreshProcessTree(model);
// 恢复展开状态
SelectProcessByPID(model, model->invisibleRootItem()->index(), treeView);
// 恢复滚动条位置,但只有在用户没有操作滚动条时
if (!isUserScrolling && verticalScrollBar) {
verticalScrollBar->setSliderPosition(currentV);
}
});
QMenu contextMenu(treeView);
QAction actionKill("结束进程", &contextMenu);
contextMenu.addAction(&actionKill);
QAction actionSuspend("挂起进程", &contextMenu);
contextMenu.addAction(&actionSuspend);
QAction actionResume("恢复进程", &contextMenu);
contextMenu.addAction(&actionResume);
QAction actionFile("文件位置", &contextMenu);
contextMenu.addAction(&actionFile);
QObject::connect(&actionKill, &QAction::triggered, [&]() {
QModelIndexList selectedIndexes = treeView->selectionModel()->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
QModelIndex index = selectedIndexes.first();
DWORD pid = model->item(index.row(), 2)->text().toInt();
if (!TerminateProcess(OpenProcess(PROCESS_TERMINATE, FALSE, pid),1)){
DWORD errorMessageID = GetLastError();
std::wstring errorMessage = GetLastErrorAsString(errorMessageID);
QMessageBox::critical(&mainWindow, "错误", "错误原因:"+QString::fromStdWString(errorMessage));
}
}
});
QObject::connect(&actionSuspend, &QAction::triggered, [&]() {
QModelIndexList selectedIndexes = treeView->selectionModel()->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
QModelIndex index = selectedIndexes.first();
DWORD pid = model->item(index.row(), 2)->text().toInt();
SuspendProcess(pid,mainWindow);
}
});
QObject::connect(&actionResume, &QAction::triggered, [&]() {
QModelIndexList selectedIndexes = treeView->selectionModel()->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
QModelIndex index = selectedIndexes.first();
DWORD pid = model->item(index.row(), 2)->text().toInt();
ResumeProcess(pid,mainWindow);
}
});
QObject::connect(&actionFile, &QAction::triggered, [&]() {
QModelIndexList selectedIndexes = treeView->selectionModel()->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
QModelIndex index = selectedIndexes.first();
DWORD pid = model->item(index.row(), 2)->text().toInt();
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL) {
DWORD errorMessageID = GetLastError();
std::wstring errorMessage = GetLastErrorAsString(errorMessageID);
QMessageBox::critical(&mainWindow, "错误", "错误原因:" + QString::fromStdWString(errorMessage));
return 1;
}
TCHAR szProcessFilePath[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, szProcessFilePath, MAX_PATH) == 0) {
DWORD errorMessageID = GetLastError();
std::wstring errorMessage = GetLastErrorAsString(errorMessageID);
QMessageBox::critical(&mainWindow, "错误", "错误原因:" + QString::fromStdWString(errorMessage));
CloseHandle(hProcess);
return 1;
}
CloseHandle(hProcess);
std::wstring folderPath(szProcessFilePath);
std::wstring commandLine = L"explorer.exe /select,\"" + folderPath + L"\"";
STARTUPINFO si = { sizeof(si) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, (LPWSTR)commandLine.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
DWORD errorMessageID = GetLastError();
std::wstring errorMessage = GetLastErrorAsString(errorMessageID);
QMessageBox::critical(&mainWindow, "错误", "错误原因:" + QString::fromStdWString(errorMessage));
return 1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
QMessageBox::critical(&mainWindow, "错误", "错误原因:进程不存在。");
return 1;
});
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(treeView, &QTreeView::customContextMenuRequested, [&](const QPoint &pos) {
contextMenu.exec(treeView->mapToGlobal(pos));
});
timer.start();
mainWindow.setCentralWidget(treeView);
mainWindow.show();
return a.exec();
}
运行结果及详细报错内容
他好像是没有报错。但是就是更新后没有办法重新设置展开内容。
我的解答思路和尝试过的方法,不写自己思路的,回答率下降 60%
我倒是试过其他方法,比如说,把expandedPids写成结构体和selectedPids合并这就导致了两个都没有办法使用。