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 }