2301_77518027 2024-09-22 08:13 采纳率: 0%
浏览 10
已结题

QT任务管理器无法正确获取展开,有悬赏15元速求,如何解决?(相关搜索:标识符|结构体)

问题遇到的现象和发生背景

我本来想写一个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合并这就导致了两个都没有办法使用。

我想要达到的结果,如果你需要快速回答,请尝试 “付费悬赏”
  • 写回答

24条回答 默认 最新

  • 妄北y 嵌入式领域优质创作者 2024-09-22 08:15
    关注

    以下参考免费微信小程序:皆我百晓生 作答,并由妄北y整理回复。

    从您的代码中可以看出,您正在尝试构建一个任务管理器,并且希望在每次刷新进程列表时保持之前展开的进程项。您遇到的问题是在刷新后展开状态没有被正确恢复。

    首先,让我们分析一下可能的问题和解决方案:

    1. 确保展开状态被正确保存:在刷新进程列表前,您需要确保所有的展开状态都已经保存到expandedPids列表中。您的SelectProcessByPID函数应该在每次刷新前被调用,并且save参数应该被设置为true

    2. 确保展开状态被正确应用:在刷新进程列表后,您需要遍历expandedPids列表,并确保每个PID对应的项都被展开。您的SelectProcessByPID函数应该在每次刷新后被调用,并且save参数应该被设置为false

    3. 确保模型更新后索引仍然有效:在Qt中,当模型(Model)发生变化时,之前的索引(Index)可能会变得无效。因此,您需要在每次刷新后重新获取每个进程项的索引。

    4. 处理可能的索引变化:由于进程项可能被重新排序或重新创建,您不能依赖于旧的索引。您需要根据PID重新查找每个进程项的索引。

    下面是一些改进您的代码的建议:

    • RefreshProcessTree函数中,在调用SelectProcessByPID之前,您应该先清空expandedPids列表,以避免重复添加相同的PID。
    void RefreshProcessTree(QStandardItemModel* model) {
        // ...
        expandedPids.clear(); // 清空展开状态列表
        SelectProcessByPID(model, model->invisibleRootItem()->index(), treeView, true); // 保存展开状态
        // ...
    }
    
    • 修改SelectProcessByPID函数,使其能够处理模型更新后的情况。您可能需要重新设计这个函数,使其能够根据PID查找模型中的项,而不仅仅是依赖于索引。

    • 确保在每次刷新后,您都重新应用了选中和展开的状态。

    • 如果您发现expandedPids列表为空,这可能意味着在保存展开状态时出现了问题。您需要检查SelectProcessByPID函数中的逻辑,确保在遍历模型时能够正确地识别和保存展开的项。

    • 最后,确保在每次刷新后,都调用了SelectProcessByPID函数来恢复展开状态。

    如果您在实现这些更改后仍然遇到问题,可能需要进一步调试您的代码,特别是在处理模型更新和索引变化时。您可能需要添加一些调试输出,以帮助您理解在每次刷新时发生了什么,以及为什么某些项没有被正确地展开。

    评论

报告相同问题?

问题事件

  • 系统已结题 今天
  • 创建了问题 9月22日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?