KCoreAddons

kprocesslist_win.cpp
1/*
2 This file is part of the KDE Frameworks
3
4 SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies).
5 SPDX-FileCopyrightText: 2019 David Hallas <david@davidhallas.dk>
6
7 SPDX-License-Identifier: LGPL-2.1-only WITH Qt-LGPL-exception-1.1 OR LicenseRef-Qt-Commercial
8*/
9
10#include "kprocesslist.h"
11
12#include <QLibrary>
13#include <algorithm>
14
15// Enable Win API of XP SP1 and later
16#ifdef Q_OS_WIN
17#if !defined(_WIN32_WINNT)
18#define _WIN32_WINNT 0x0502
19#endif
20#include <qt_windows.h>
21#if !defined(PROCESS_SUSPEND_RESUME) // Check flag for MinGW
22#define PROCESS_SUSPEND_RESUME (0x0800)
23#endif // PROCESS_SUSPEND_RESUME
24#endif // Q_OS_WIN
25
26#include <psapi.h>
27#include <tlhelp32.h>
28
29using namespace KProcessList;
30
31// Resolve QueryFullProcessImageNameW out of kernel32.dll due
32// to incomplete MinGW import libs and it not being present
33// on Windows XP.
34static inline BOOL queryFullProcessImageName(HANDLE h, DWORD flags, LPWSTR buffer, DWORD *size)
35{
36 // Resolve required symbols from the kernel32.dll
37 typedef BOOL(WINAPI * QueryFullProcessImageNameWProtoType)(HANDLE, DWORD, LPWSTR, PDWORD);
38 static QueryFullProcessImageNameWProtoType queryFullProcessImageNameW = nullptr;
39 if (!queryFullProcessImageNameW) {
40 QLibrary kernel32Lib(QLatin1String("kernel32.dll"), 0);
41 if (kernel32Lib.isLoaded() || kernel32Lib.load()) {
42 queryFullProcessImageNameW = (QueryFullProcessImageNameWProtoType)kernel32Lib.resolve("QueryFullProcessImageNameW");
43 }
44 }
45 if (!queryFullProcessImageNameW)
46 return FALSE;
47 // Read out process
48 return (*queryFullProcessImageNameW)(h, flags, buffer, size);
49}
50
51struct ProcessInfo {
52 QString processOwner;
53 QString fullPath;
54};
55
56static inline ProcessInfo winProcessInfo(DWORD processId)
57{
58 ProcessInfo pi;
59 HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, TOKEN_READ, processId);
60 if (handle == INVALID_HANDLE_VALUE)
61 return pi;
62 HANDLE processTokenHandle = nullptr;
63 if (!OpenProcessToken(handle, TOKEN_READ, &processTokenHandle) || !processTokenHandle)
64 return pi;
65
66 TCHAR fullProcessPath[MAX_PATH] = {0};
67 DWORD fullProcessPathLength = MAX_PATH;
68 if (queryFullProcessImageName(handle, 0, fullProcessPath, &fullProcessPathLength)) {
69 pi.fullPath = QString::fromUtf16(reinterpret_cast<const char16_t *>(fullProcessPath));
70 }
71
72 DWORD size = 0;
73 GetTokenInformation(processTokenHandle, TokenUser, nullptr, 0, &size);
74
75 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
76 QByteArray buf;
77 buf.resize(size);
78 PTOKEN_USER userToken = reinterpret_cast<PTOKEN_USER>(buf.data());
79 if (userToken && GetTokenInformation(processTokenHandle, TokenUser, userToken, size, &size)) {
80 SID_NAME_USE sidNameUse;
81 TCHAR user[MAX_PATH] = {0};
82 DWORD userNameLength = MAX_PATH;
83 TCHAR domain[MAX_PATH] = {0};
84 DWORD domainNameLength = MAX_PATH;
85
86 if (LookupAccountSid(nullptr, userToken->User.Sid, user, &userNameLength, domain, &domainNameLength, &sidNameUse))
87 pi.processOwner = QString::fromUtf16(reinterpret_cast<const char16_t *>(user));
88 }
89 }
90
91 CloseHandle(processTokenHandle);
92 CloseHandle(handle);
93 return pi;
94}
95
96KProcessInfoList KProcessList::processInfoList()
97{
99
100 PROCESSENTRY32 pe;
101 pe.dwSize = sizeof(PROCESSENTRY32);
102 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
103 if (snapshot == INVALID_HANDLE_VALUE)
104 return rc;
105
106 for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) {
107 const ProcessInfo processInf = winProcessInfo(pe.th32ProcessID);
108 const QString commandName = QString::fromUtf16(reinterpret_cast<char16_t *>(pe.szExeFile));
109 if (processInf.fullPath.isEmpty()) {
110 rc.push_back(KProcessInfo(pe.th32ProcessID, commandName, processInf.processOwner));
111 } else {
112 rc.push_back(KProcessInfo(pe.th32ProcessID, processInf.fullPath, commandName, processInf.processOwner));
113 }
114 }
115 CloseHandle(snapshot);
116 return rc;
117}
118
119KProcessInfo KProcessList::processInfo(qint64 pid)
120{
121 KProcessInfoList processInfoList = KProcessList::processInfoList();
122 auto testProcessIterator = std::find_if(processInfoList.begin(), processInfoList.end(), [pid](const KProcessList::KProcessInfo &info) {
123 return info.pid() == pid;
124 });
125 if (testProcessIterator != processInfoList.end()) {
126 return *testProcessIterator;
127 }
128 return KProcessInfo();
129}
Contains information about a process.
char * data()
void resize(qsizetype newSize, char c)
iterator begin()
iterator end()
void push_back(parameter_type value)
QString fromUtf16(const char16_t *unicode, qsizetype size)
bool isEmpty() const const
typedef HANDLE
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:00:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.