File indexing completed on 2024-05-12 03:55:00

0001 /*
0002     This file is part of the KDE Frameworks
0003 
0004     SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies).
0005     SPDX-FileCopyrightText: 2019 David Hallas <david@davidhallas.dk>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only WITH Qt-LGPL-exception-1.1 OR LicenseRef-Qt-Commercial
0008 */
0009 
0010 #include "kprocesslist.h"
0011 
0012 #include <QLibrary>
0013 #include <algorithm>
0014 
0015 // Enable Win API of XP SP1 and later
0016 #ifdef Q_OS_WIN
0017 #if !defined(_WIN32_WINNT)
0018 #define _WIN32_WINNT 0x0502
0019 #endif
0020 #include <qt_windows.h>
0021 #if !defined(PROCESS_SUSPEND_RESUME) // Check flag for MinGW
0022 #define PROCESS_SUSPEND_RESUME (0x0800)
0023 #endif // PROCESS_SUSPEND_RESUME
0024 #endif // Q_OS_WIN
0025 
0026 #include <psapi.h>
0027 #include <tlhelp32.h>
0028 
0029 using namespace KProcessList;
0030 
0031 // Resolve QueryFullProcessImageNameW out of kernel32.dll due
0032 // to incomplete MinGW import libs and it not being present
0033 // on Windows XP.
0034 static inline BOOL queryFullProcessImageName(HANDLE h, DWORD flags, LPWSTR buffer, DWORD *size)
0035 {
0036     // Resolve required symbols from the kernel32.dll
0037     typedef BOOL(WINAPI * QueryFullProcessImageNameWProtoType)(HANDLE, DWORD, LPWSTR, PDWORD);
0038     static QueryFullProcessImageNameWProtoType queryFullProcessImageNameW = 0;
0039     if (!queryFullProcessImageNameW) {
0040         QLibrary kernel32Lib(QLatin1String("kernel32.dll"), 0);
0041         if (kernel32Lib.isLoaded() || kernel32Lib.load()) {
0042             queryFullProcessImageNameW = (QueryFullProcessImageNameWProtoType)kernel32Lib.resolve("QueryFullProcessImageNameW");
0043         }
0044     }
0045     if (!queryFullProcessImageNameW)
0046         return FALSE;
0047     // Read out process
0048     return (*queryFullProcessImageNameW)(h, flags, buffer, size);
0049 }
0050 
0051 struct ProcessInfo {
0052     QString processOwner;
0053     QString fullPath;
0054 };
0055 
0056 static inline ProcessInfo winProcessInfo(DWORD processId)
0057 {
0058     ProcessInfo pi;
0059     HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, TOKEN_READ, processId);
0060     if (handle == INVALID_HANDLE_VALUE)
0061         return pi;
0062     HANDLE processTokenHandle = NULL;
0063     if (!OpenProcessToken(handle, TOKEN_READ, &processTokenHandle) || !processTokenHandle)
0064         return pi;
0065 
0066     TCHAR fullProcessPath[MAX_PATH] = {0};
0067     DWORD fullProcessPathLength = MAX_PATH;
0068     if (queryFullProcessImageName(handle, 0, fullProcessPath, &fullProcessPathLength)) {
0069         pi.fullPath = QString::fromUtf16(reinterpret_cast<const char16_t *>(fullProcessPath));
0070     }
0071 
0072     DWORD size = 0;
0073     GetTokenInformation(processTokenHandle, TokenUser, NULL, 0, &size);
0074 
0075     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
0076         QByteArray buf;
0077         buf.resize(size);
0078         PTOKEN_USER userToken = reinterpret_cast<PTOKEN_USER>(buf.data());
0079         if (userToken && GetTokenInformation(processTokenHandle, TokenUser, userToken, size, &size)) {
0080             SID_NAME_USE sidNameUse;
0081             TCHAR user[MAX_PATH] = {0};
0082             DWORD userNameLength = MAX_PATH;
0083             TCHAR domain[MAX_PATH] = {0};
0084             DWORD domainNameLength = MAX_PATH;
0085 
0086             if (LookupAccountSid(NULL, userToken->User.Sid, user, &userNameLength, domain, &domainNameLength, &sidNameUse))
0087                 pi.processOwner = QString::fromUtf16(reinterpret_cast<const char16_t *>(user));
0088         }
0089     }
0090 
0091     CloseHandle(processTokenHandle);
0092     CloseHandle(handle);
0093     return pi;
0094 }
0095 
0096 KProcessInfoList KProcessList::processInfoList()
0097 {
0098     KProcessInfoList rc;
0099 
0100     PROCESSENTRY32 pe;
0101     pe.dwSize = sizeof(PROCESSENTRY32);
0102     HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
0103     if (snapshot == INVALID_HANDLE_VALUE)
0104         return rc;
0105 
0106     for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) {
0107         const ProcessInfo processInf = winProcessInfo(pe.th32ProcessID);
0108         const QString commandName = QString::fromUtf16(reinterpret_cast<char16_t *>(pe.szExeFile));
0109         if (processInf.fullPath.isEmpty()) {
0110             rc.push_back(KProcessInfo(pe.th32ProcessID, commandName, processInf.processOwner));
0111         } else {
0112             rc.push_back(KProcessInfo(pe.th32ProcessID, processInf.fullPath, commandName, processInf.processOwner));
0113         }
0114     }
0115     CloseHandle(snapshot);
0116     return rc;
0117 }
0118 
0119 KProcessInfo KProcessList::processInfo(qint64 pid)
0120 {
0121     KProcessInfoList processInfoList = KProcessList::processInfoList();
0122     auto testProcessIterator = std::find_if(processInfoList.begin(), processInfoList.end(), [pid](const KProcessList::KProcessInfo &info) {
0123         return info.pid() == pid;
0124     });
0125     if (testProcessIterator != processInfoList.end()) {
0126         return *testProcessIterator;
0127     }
0128     return KProcessInfo();
0129 }