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"
33using 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
49PSID 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
62static 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
88static 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
97void 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
138bool 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
152bool 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
176struct EnumWindowsStruct
177{
178 EnumWindowsStruct() : windowId( 0 ) {}
179 int pid;
180 HWND windowId;
181};
182
183BOOL 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
198void 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