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,
87 &sidNameUse))
88 pi.processOwner = QString::fromUtf16(reinterpret_cast<const char16_t *>(user));
89 }
90 }
91
92 CloseHandle(processTokenHandle);
93 CloseHandle(handle);
94 return pi;
95}
96
97KProcessInfoList KProcessList::processInfoList()
98{
100
101 PROCESSENTRY32 pe;
102 pe.dwSize = sizeof(PROCESSENTRY32);
103 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
104 if (snapshot == INVALID_HANDLE_VALUE)
105 return rc;
106
107 for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) {
108 const ProcessInfo processInf = winProcessInfo(pe.th32ProcessID);
109 const QString commandName = QString::fromUtf16(reinterpret_cast<char16_t *>(pe.szExeFile));
110 if (processInf.fullPath.isEmpty()) {
111 rc.push_back(KProcessInfo(pe.th32ProcessID, commandName, processInf.processOwner));
112 } else {
113 rc.push_back(KProcessInfo(pe.th32ProcessID, processInf.fullPath, commandName, processInf.processOwner));
114 }
115 }
116 CloseHandle(snapshot);
117 return rc;
118}
119
120KProcessInfo KProcessList::processInfo(qint64 pid)
121{
122 KProcessInfoList processInfoList = KProcessList::processInfoList();
123 auto testProcessIterator = std::find_if(processInfoList.begin(), processInfoList.end(), [pid](const KProcessList::KProcessInfo &info) {
124 return info.pid() == pid;
125 });
126 if (testProcessIterator != processInfoList.end()) {
127 return *testProcessIterator;
128 }
129 return KProcessInfo();
130}
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 Jun 7 2024 12:01:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.