File indexing completed on 2024-05-12 05:21:08

0001 /**
0002  * This file is part of the kpimutils library.
0003  *
0004  * SPDX-FileCopyrightText: 2008 Jarosław Staniek <staniek@kde.org>
0005  * SPDX-FileCopyrightText: 2012 Andre Heinecke <aheinecke@intevation.de>
0006  *
0007  * SPDX-License-Identifier: LGPL-2.1-or-later
0008  */
0009 /**
0010   @file
0011   This file is part of the KDEPIM Utilities library and provides
0012   static methods for process handling (Windows only at this time).
0013 
0014   @author Jarosław Staniek \<staniek@kde.org\>
0015 */
0016 
0017 // krazy:excludeall=captruefalse,null
0018 
0019 #include "processes.h"
0020 using namespace KontactInterface;
0021 
0022 #ifdef Q_OS_WIN
0023 
0024 // windows.h needs to come first
0025 // clang-format off
0026 #include <windows.h>
0027 #include <psapi.h>
0028 #include <signal.h>
0029 #include <tlhelp32.h>
0030 // clang-format on
0031 
0032 #include "kontactinterface_debug.h"
0033 #include <QCoreApplication>
0034 
0035 // Copy from kdelibs/kinit/kinit_win.cpp
0036 PSID copySid(PSID from)
0037 {
0038     if (!from) {
0039         return 0;
0040     }
0041 
0042     int sidLength = GetLengthSid(from);
0043     PSID to = (PSID)malloc(sidLength);
0044     CopySid(sidLength, to, from);
0045     return to;
0046 }
0047 
0048 // Copy from kdelibs/kinit/kinit_win.cpp
0049 static PSID getProcessOwner(HANDLE hProcess)
0050 {
0051     HANDLE hToken = NULL;
0052     PSID sid;
0053 
0054     OpenProcessToken(hProcess, TOKEN_READ, &hToken);
0055     if (hToken) {
0056         DWORD size;
0057         PTOKEN_USER userStruct;
0058 
0059         // check how much space is needed
0060         GetTokenInformation(hToken, TokenUser, NULL, 0, &size);
0061         if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
0062             userStruct = reinterpret_cast<PTOKEN_USER>(new BYTE[size]);
0063             GetTokenInformation(hToken, TokenUser, userStruct, size, &size);
0064 
0065             sid = copySid(userStruct->User.Sid);
0066             CloseHandle(hToken);
0067             delete[] userStruct;
0068             return sid;
0069         }
0070     }
0071     return 0;
0072 }
0073 
0074 // Copy from kdelibs/kinit/kinit_win.cpp
0075 static HANDLE getProcessHandle(int processID)
0076 {
0077     return OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, false, processID);
0078 }
0079 
0080 void KontactInterface::getProcessesIdForName(const QString &processName, QList<int> &pids)
0081 {
0082     HANDLE h;
0083     PROCESSENTRY32 pe32;
0084 
0085     h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
0086     if (h == INVALID_HANDLE_VALUE) {
0087         return;
0088     }
0089 
0090     pe32.dwSize = sizeof(PROCESSENTRY32); // Necessary according to MSDN
0091     if (!Process32First(h, &pe32)) {
0092         return;
0093     }
0094 
0095     pids.clear();
0096 
0097     do {
0098         if (QString::fromWCharArray(pe32.szExeFile) == processName) {
0099             PSID user_sid = getProcessOwner(GetCurrentProcess());
0100             if (user_sid) {
0101                 // Also check that we are the Owner of that process
0102                 HANDLE hProcess = getProcessHandle(pe32.th32ProcessID);
0103                 if (!hProcess) {
0104                     continue;
0105                 }
0106 
0107                 PSID sid = getProcessOwner(hProcess);
0108                 PSID userSid = getProcessOwner(GetCurrentProcess());
0109                 if (!sid || userSid && !EqualSid(userSid, sid)) {
0110                     free(sid);
0111                     continue;
0112                 }
0113             }
0114             pids.append((int)pe32.th32ProcessID);
0115             qCDebug(KONTACTINTERFACE_LOG) << "found PID: " << (int)pe32.th32ProcessID;
0116         }
0117     } while (Process32Next(h, &pe32));
0118     CloseHandle(h);
0119 }
0120 
0121 struct EnumWindowsStruct {
0122     EnumWindowsStruct()
0123         : windowId(0)
0124     {
0125     }
0126     int pid;
0127     HWND windowId;
0128 };
0129 
0130 BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
0131 {
0132     if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) {
0133         DWORD pidwin;
0134 
0135         GetWindowThreadProcessId(hwnd, &pidwin);
0136         if (pidwin == ((EnumWindowsStruct *)lParam)->pid) {
0137             ((EnumWindowsStruct *)lParam)->windowId = hwnd;
0138             return FALSE;
0139         }
0140     }
0141     return TRUE;
0142 }
0143 
0144 void KontactInterface::activateWindowForProcess(const QString &executableName)
0145 {
0146     QList<int> pids;
0147     KontactInterface::getProcessesIdForName(executableName, pids);
0148     int myPid = QCoreApplication::applicationPid();
0149     int foundPid = 0;
0150     for (int pid : std::as_const(pids)) {
0151         if (myPid != pid) {
0152             qCDebug(KONTACTINTERFACE_LOG) << "activateWindowForProcess(): PID to activate:" << pid;
0153             foundPid = pid;
0154             break;
0155         }
0156     }
0157     if (foundPid == 0) {
0158         return;
0159     }
0160     EnumWindowsStruct winStruct;
0161     winStruct.pid = foundPid;
0162     EnumWindows(EnumWindowsProc, (LPARAM)&winStruct);
0163     if (winStruct.windowId == 0) {
0164         return;
0165     }
0166     SetForegroundWindow(winStruct.windowId);
0167 }
0168 
0169 #endif // Q_OS_WIN