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