1 | /** |
2 | * This file is part of the kpimutils library. |
3 | * |
4 | * Copyright (C) 2008 Jarosław Staniek <staniek@kde.org> |
5 | * Copyright (C) 2012 Andre Heinecke <aheinecke@intevation.de> |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
20 | * 02110-1301 USA |
21 | */ |
22 | /** |
23 | @file |
24 | This file is part of the KDEPIM Utilities library and provides |
25 | static methods for process handling (Windows only at this time). |
26 | |
27 | @author Jarosław Staniek \<staniek@kde.org\> |
28 | */ |
29 | |
30 | //krazy:excludeall=captruefalse,null |
31 | |
32 | #include "processes.h" |
33 | using namespace KPIMUtils; |
34 | |
35 | #ifdef Q_WS_WIN |
36 | |
37 | #include <windows.h> |
38 | #include <tlhelp32.h> |
39 | #include <psapi.h> |
40 | #include <signal.h> |
41 | #include <unistd.h> |
42 | |
43 | #include <QtCore/QList> |
44 | #include <QtCore/QtDebug> |
45 | |
46 | #include <KDebug> |
47 | |
48 | // Copy from kdelibs/kinit/kinit_win.cpp |
49 | PSID copySid( PSID from ) |
50 | { |
51 | if ( !from ) { |
52 | return 0; |
53 | } |
54 | |
55 | int sidLength = GetLengthSid( from ); |
56 | PSID to = (PSID) malloc( sidLength ); |
57 | CopySid( sidLength, to, from ); |
58 | return to; |
59 | } |
60 | |
61 | // Copy from kdelibs/kinit/kinit_win.cpp |
62 | static PSID getProcessOwner( HANDLE hProcess ) |
63 | { |
64 | HANDLE hToken = NULL; |
65 | PSID sid; |
66 | |
67 | OpenProcessToken( hProcess, TOKEN_READ, &hToken ); |
68 | if ( hToken ) { |
69 | DWORD size; |
70 | PTOKEN_USER userStruct; |
71 | |
72 | // check how much space is needed |
73 | GetTokenInformation( hToken, TokenUser, NULL, 0, &size ); |
74 | if ( ERROR_INSUFFICIENT_BUFFER == GetLastError() ) { |
75 | userStruct = reinterpret_cast<PTOKEN_USER>( new BYTE[size] ); |
76 | GetTokenInformation( hToken, TokenUser, userStruct, size, &size ); |
77 | |
78 | sid = copySid( userStruct->User.Sid ); |
79 | CloseHandle( hToken ); |
80 | delete [] userStruct; |
81 | return sid; |
82 | } |
83 | } |
84 | return 0; |
85 | } |
86 | |
87 | // Copy from kdelibs/kinit/kinit_win.cpp |
88 | static HANDLE getProcessHandle( int processID ) |
89 | { |
90 | return OpenProcess( SYNCHRONIZE | |
91 | PROCESS_QUERY_INFORMATION | |
92 | PROCESS_VM_READ | |
93 | PROCESS_TERMINATE, |
94 | false, processID ); |
95 | } |
96 | |
97 | void KPIMUtils::getProcessesIdForName( const QString &processName, QList<int> &pids ) |
98 | { |
99 | HANDLE h; |
100 | PROCESSENTRY32 pe32; |
101 | |
102 | h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); |
103 | if ( h == INVALID_HANDLE_VALUE ) { |
104 | return; |
105 | } |
106 | |
107 | pe32.dwSize = sizeof( PROCESSENTRY32 ); // Necessary according to MSDN |
108 | if ( !Process32First( h, &pe32 ) ) { |
109 | return; |
110 | } |
111 | |
112 | pids.clear(); |
113 | |
114 | do { |
115 | if ( QString::fromWCharArray( pe32.szExeFile ) == processName ) { |
116 | PSID user_sid = getProcessOwner( GetCurrentProcess() ); |
117 | if ( user_sid ) { |
118 | // Also check that we are the Owner of that process |
119 | HANDLE hProcess = getProcessHandle( pe32.th32ProcessID ); |
120 | if ( !hProcess ) { |
121 | continue; |
122 | } |
123 | |
124 | PSID sid = getProcessOwner( hProcess ); |
125 | PSID userSid = getProcessOwner( GetCurrentProcess() ); |
126 | if ( !sid || userSid && !EqualSid( userSid, sid ) ) { |
127 | free ( sid ); |
128 | continue; |
129 | } |
130 | } |
131 | pids.append( (int)pe32.th32ProcessID ); |
132 | kDebug() << "found PID: " << (int)pe32.th32ProcessID; |
133 | } |
134 | } while ( Process32Next( h, &pe32 ) ); |
135 | CloseHandle( h ); |
136 | } |
137 | |
138 | bool KPIMUtils::otherProcessesExist( const QString &processName ) |
139 | { |
140 | QList<int> pids; |
141 | getProcessesIdForName( processName, pids ); |
142 | int myPid = getpid(); |
143 | foreach ( int pid, pids ) { |
144 | if ( myPid != pid ) { |
145 | // kDebug() << "Process ID is " << pid; |
146 | return true; |
147 | } |
148 | } |
149 | return false; |
150 | } |
151 | |
152 | bool KPIMUtils::killProcesses( const QString &processName ) |
153 | { |
154 | QList<int> pids; |
155 | getProcessesIdForName( processName, pids ); |
156 | if ( pids.empty() ) { |
157 | return true; |
158 | } |
159 | |
160 | qWarning() << "Killing process \"" << processName << " (pid=" << pids[0] << ").." ; |
161 | int overallResult = 0; |
162 | foreach ( int pid, pids ) { |
163 | int result; |
164 | result = kill( pid, SIGTERM ); |
165 | if ( result == 0 ) { |
166 | continue; |
167 | } |
168 | result = kill( pid, SIGKILL ); |
169 | if ( result != 0 ) { |
170 | overallResult = result; |
171 | } |
172 | } |
173 | return overallResult == 0; |
174 | } |
175 | |
176 | struct EnumWindowsStruct |
177 | { |
178 | EnumWindowsStruct() : windowId( 0 ) {} |
179 | int pid; |
180 | HWND windowId; |
181 | }; |
182 | |
183 | BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) |
184 | { |
185 | if ( GetWindowLong( hwnd, GWL_STYLE ) & WS_VISIBLE ) { |
186 | |
187 | DWORD pidwin; |
188 | |
189 | GetWindowThreadProcessId( hwnd, &pidwin ); |
190 | if ( pidwin == ( (EnumWindowsStruct *)lParam )->pid ) { |
191 | ( (EnumWindowsStruct *)lParam )->windowId = hwnd; |
192 | return FALSE; |
193 | } |
194 | } |
195 | return TRUE; |
196 | } |
197 | |
198 | void KPIMUtils::activateWindowForProcess( const QString &executableName ) |
199 | { |
200 | QList<int> pids; |
201 | KPIMUtils::getProcessesIdForName( executableName, pids ); |
202 | int myPid = getpid(); |
203 | int foundPid = 0; |
204 | foreach ( int pid, pids ) { |
205 | if ( myPid != pid ) { |
206 | kDebug() << "activateWindowForProcess(): PID to activate:" << pid; |
207 | foundPid = pid; |
208 | break; |
209 | } |
210 | } |
211 | if ( foundPid == 0 ) { |
212 | return; |
213 | } |
214 | EnumWindowsStruct winStruct; |
215 | winStruct.pid = foundPid; |
216 | EnumWindows( EnumWindowsProc, (LPARAM)&winStruct ); |
217 | if ( winStruct.windowId == 0 ) { |
218 | return; |
219 | } |
220 | SetForegroundWindow( winStruct.windowId ); |
221 | } |
222 | |
223 | #endif // Q_WS_WIN |
224 | |