1 /*****************************************************************
2 * nsProcess NSIS plugin v1.5 *
3 * *
4 * 2006 Shengalts Aleksander aka Instructor (Shengalts@mail.ru) *
5 * *
6 * Source function FIND_PROC_BY_NAME based *
7 * upon the Ravi Kochhar (kochhar@physiology.wisc.edu) code *
8 * Thanks iceman_k (FindProcDLL plugin) and *
9 * DITMan (KillProcDLL plugin) for point me up *
10 *****************************************************************/
11
12
13 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
15 #include <Tlhelp32.h>
16 //#include "ConvFunc.h"
17 #include "pluginapi.h"
18
19 /* Defines */
20 #define NSIS_MAX_STRLEN 1024
21
22 #define SystemProcessInformation 5
23 #define STATUS_SUCCESS 0x00000000L
24 #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L
25
26 typedef struct _SYSTEM_THREAD_INFO {
27 FILETIME ftCreationTime;
28 DWORD dwUnknown1;
29 DWORD dwStartAddress;
30 DWORD dwOwningPID;
31 DWORD dwThreadID;
32 DWORD dwCurrentPriority;
33 DWORD dwBasePriority;
34 DWORD dwContextSwitches;
35 DWORD dwThreadState;
36 DWORD dwUnknown2;
37 DWORD dwUnknown3;
38 DWORD dwUnknown4;
39 DWORD dwUnknown5;
40 DWORD dwUnknown6;
41 DWORD dwUnknown7;
42 } SYSTEM_THREAD_INFO;
43
44 typedef struct _SYSTEM_PROCESS_INFO {
45 DWORD dwOffset;
46 DWORD dwThreadCount;
47 DWORD dwUnkown1[6];
48 FILETIME ftCreationTime;
49 DWORD dwUnkown2;
50 DWORD dwUnkown3;
51 DWORD dwUnkown4;
52 DWORD dwUnkown5;
53 DWORD dwUnkown6;
54 WCHAR *pszProcessName;
55 DWORD dwBasePriority;
56 DWORD dwProcessID;
57 DWORD dwParentProcessID;
58 DWORD dwHandleCount;
59 DWORD dwUnkown7;
60 DWORD dwUnkown8;
61 DWORD dwVirtualBytesPeak;
62 DWORD dwVirtualBytes;
63 DWORD dwPageFaults;
64 DWORD dwWorkingSetPeak;
65 DWORD dwWorkingSet;
66 DWORD dwUnkown9;
67 DWORD dwPagedPool;
68 DWORD dwUnkown10;
69 DWORD dwNonPagedPool;
70 DWORD dwPageFileBytesPeak;
71 DWORD dwPageFileBytes;
72 DWORD dwPrivateBytes;
73 DWORD dwUnkown11;
74 DWORD dwUnkown12;
75 DWORD dwUnkown13;
76 DWORD dwUnkown14;
77 SYSTEM_THREAD_INFO ati[ANYSIZE_ARRAY];
78 } SYSTEM_PROCESS_INFO;
79
80
81 /* Include conversion functions */
82 //#define xatoi
83 //#define xitoa
84 //#include "ConvFunc.h"
85
86 /* Global variables */
87 TCHAR szBuf[NSIS_MAX_STRLEN];
88
89 /* Funtions prototypes and macros */
90 int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose);
91
92 /* NSIS functions code */
_FindProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)93 void __declspec(dllexport) _FindProcess(HWND hwndParent, int string_size,
94 TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
95 {
96 EXDLL_INIT();
97 {
98 int nError;
99
100 popstringn(szBuf, NSIS_MAX_STRLEN);
101 nError=FIND_PROC_BY_NAME(szBuf, FALSE, FALSE);
102 pushint(nError);
103 }
104 }
105
_KillProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)106 void __declspec(dllexport) _KillProcess(HWND hwndParent, int string_size,
107 TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
108 {
109 EXDLL_INIT();
110 {
111 int nError=0;
112
113 popstringn(szBuf, NSIS_MAX_STRLEN);
114 nError=FIND_PROC_BY_NAME(szBuf, TRUE, FALSE);
115 pushint(nError);
116 }
117 }
118
_CloseProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)119 void __declspec(dllexport) _CloseProcess(HWND hwndParent, int string_size,
120 TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
121 {
122 EXDLL_INIT();
123 {
124 int nError=0;
125
126 popstringn(szBuf, NSIS_MAX_STRLEN);
127 nError=FIND_PROC_BY_NAME(szBuf, TRUE, TRUE);
128 pushint(nError);
129 }
130 }
131
_Unload(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)132 void __declspec(dllexport) _Unload(HWND hwndParent, int string_size,
133 TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
134 {
135 }
136
DllMain(HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)137 BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
138 {
139 return TRUE;
140 }
141
EnumWindowsProc(HWND hwnd,LPARAM lParam)142 BOOL CALLBACK EnumWindowsProc( HWND hwnd,
143 LPARAM lParam
144 )
145 {
146 HANDLE *data = lParam;
147 DWORD pid;
148 GetWindowThreadProcessId(hwnd, &pid);
149 if (pid == data[0])
150 {
151 PostMessage(data[1], WM_CLOSE, 0, 0);
152 data[1] = hwnd;
153 }
154 return TRUE;
155 }
156
NiceTerminate(DWORD id,BOOL bClose,BOOL * bSuccess,BOOL * bFailed)157 void NiceTerminate(DWORD id, BOOL bClose, BOOL *bSuccess, BOOL *bFailed)
158 {
159 HANDLE hProc;
160 HANDLE data[2];
161 DWORD ec;
162 BOOL bDone = FALSE;
163 if (hProc=OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, id))
164 {
165 data[0] = id;
166 data[1] = NULL;
167
168 if (bClose)
169 EnumWindows(EnumWindowsProc, data);
170 if (data[1] != NULL)
171 {
172 if (GetExitCodeProcess(hProc,&ec) && ec == STILL_ACTIVE)
173 if (WaitForSingleObject(hProc, 3000) == WAIT_OBJECT_0)
174 {
175 *bSuccess = bDone = TRUE;
176 }
177 else;
178 else
179 {
180 *bSuccess = bDone = TRUE;
181 }
182 }
183 if (!bDone)
184 {
185 // Open for termination
186 if (TerminateProcess(hProc, 0))
187 *bSuccess=TRUE;
188 else
189 *bFailed=TRUE;
190 }
191 CloseHandle(hProc);
192 }
193 }
194
FIND_PROC_BY_NAME(TCHAR * szProcessName,BOOL bTerminate,BOOL bClose)195 int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose)
196 // Find the process "szProcessName" if it is currently running.
197 // This works for Win95/98/ME and also WinNT/2000/XP.
198 // The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE"
199 // will both work. If bTerminate is TRUE, then process will be terminated.
200 //
201 // Return codes are as follows:
202 // 0 = Success
203 // 601 = No permission to terminate process
204 // 602 = Not all processes terminated successfully
205 // 603 = Process was not currently running
206 // 604 = Unable to identify system type
207 // 605 = Unsupported OS
208 // 606 = Unable to load NTDLL.DLL
209 // 607 = Unable to get procedure address from NTDLL.DLL
210 // 608 = NtQuerySystemInformation failed
211 // 609 = Unable to load KERNEL32.DLL
212 // 610 = Unable to get procedure address from KERNEL32.DLL
213 // 611 = CreateToolhelp32Snapshot failed
214 //
215 // Change history:
216 // created 06/23/2000 - Ravi Kochhar (kochhar@physiology.wisc.edu)
217 // http://www.neurophys.wisc.edu/ravi/software/
218 // modified 03/08/2002 - Ravi Kochhar (kochhar@physiology.wisc.edu)
219 // - Borland-C compatible if BORLANDC is defined as
220 // suggested by Bob Christensen
221 // modified 03/10/2002 - Ravi Kochhar (kochhar@physiology.wisc.edu)
222 // - Removed memory leaks as suggested by
223 // Jonathan Richard-Brochu (handles to Proc and Snapshot
224 // were not getting closed properly in some cases)
225 // modified 14/11/2005 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
226 // - Combine functions FIND_PROC_BY_NAME and KILL_PROC_BY_NAME
227 // - Code has been optimized
228 // - Now kill all processes with specified name (not only one)
229 // - Cosmetic improvements
230 // - Removed error 632 (Invalid process name)
231 // - Changed error 602 (Unable to terminate process for some other reason)
232 // - BORLANDC define not needed
233 // modified 04/01/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
234 // - Removed CRT dependency
235 // modified 21/04/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
236 // - Removed memory leak as suggested by {_trueparuex^}
237 // (handle to hSnapShot was not getting closed properly in some cases)
238 // modified 21/04/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
239 // - Removed memory leak as suggested by {_trueparuex^}
240 // (handle to hSnapShot was not getting closed properly in some cases)
241 // modified 19/07/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
242 // - Code for WinNT/2000/XP has been rewritten
243 // - Changed error codes
244 // modified 31/08/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
245 // - Removed memory leak as suggested by Daniel Vanesse
246 {
247 TCHAR szName[MAX_PATH];
248 OSVERSIONINFO osvi;
249 HMODULE hLib;
250 HANDLE hProc;
251 ULONG uError;
252 BOOL bFound=FALSE;
253 BOOL bSuccess=FALSE;
254 BOOL bFailed=FALSE;
255
256 // First check what version of Windows we're in
257 osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
258 if (!GetVersionEx(&osvi)) return 604;
259
260 if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT &&
261 osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
262 return 605;
263
264 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
265 {
266 // WinNT/2000/XP
267
268 SYSTEM_PROCESS_INFO *spi;
269 SYSTEM_PROCESS_INFO *spiCount;
270 DWORD dwSize=0x4000;
271 DWORD dwData;
272 ULONG (WINAPI *NtQuerySystemInformationPtr)(ULONG, PVOID, LONG, PULONG);
273
274 if (hLib=LoadLibraryW(L"NTDLL.DLL"))
275 {
276 NtQuerySystemInformationPtr=(ULONG(WINAPI *)(ULONG, PVOID, LONG, PULONG))GetProcAddress(hLib, "NtQuerySystemInformation");
277
278 if (NtQuerySystemInformationPtr)
279 {
280 while (1)
281 {
282 if (spi=LocalAlloc(LMEM_FIXED, dwSize))
283 {
284 uError=(*NtQuerySystemInformationPtr)(SystemProcessInformation, spi, dwSize, &dwData);
285
286 if (uError == STATUS_SUCCESS) break;
287
288 LocalFree(spi);
289
290 if (uError != STATUS_INFO_LENGTH_MISMATCH)
291 {
292 uError=608;
293 break;
294 }
295 }
296 else
297 {
298 uError=608;
299 break;
300 }
301 dwSize*=2;
302 }
303 }
304 else uError=607;
305
306 FreeLibrary(hLib);
307 }
308 else uError=606;
309
310 if (uError != STATUS_SUCCESS) return uError;
311
312 spiCount=spi;
313
314 while (1)
315 {
316 if (spiCount->pszProcessName)
317 {
318
319 #ifdef UNICODE
320 lstrcpyn(szName, spiCount->pszProcessName, MAX_PATH);
321 #else
322 WideCharToMultiByte(CP_ACP, 0, spiCount->pszProcessName, -1, szName, MAX_PATH, NULL, NULL);
323 #endif
324
325 if (!lstrcmpi(szName, szProcessName))
326 {
327 // Process found
328 bFound=TRUE;
329
330 if (bTerminate == TRUE)
331 {
332 NiceTerminate(spiCount->dwProcessID, bClose, &bSuccess, &bFailed);
333 }
334 else break;
335 }
336 }
337 if (spiCount->dwOffset == 0) break;
338 spiCount=(SYSTEM_PROCESS_INFO *)((char *)spiCount + spiCount->dwOffset);
339 }
340 LocalFree(spi);
341 }
342 else
343 {
344 // Win95/98/ME
345
346 PROCESSENTRY32 pe;
347 char *pName;
348 HANDLE hSnapShot;
349 BOOL bResult;
350 HANDLE (WINAPI *CreateToolhelp32SnapshotPtr)(DWORD, DWORD);
351 BOOL (WINAPI *Process32FirstPtr)(HANDLE, LPPROCESSENTRY32);
352 BOOL (WINAPI *Process32NextPtr)(HANDLE, LPPROCESSENTRY32);
353
354 if (hLib=LoadLibraryA("KERNEL32.DLL"))
355 {
356 CreateToolhelp32SnapshotPtr=(HANDLE(WINAPI *)(DWORD, DWORD)) GetProcAddress(hLib, "CreateToolhelp32Snapshot");
357 Process32FirstPtr=(BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32)) GetProcAddress(hLib, "Process32First");
358 Process32NextPtr=(BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32)) GetProcAddress(hLib, "Process32Next");
359
360 if (CreateToolhelp32SnapshotPtr && Process32NextPtr && Process32FirstPtr)
361 {
362 // Get a handle to a Toolhelp snapshot of all the systems processes.
363 if ((hSnapShot=(*CreateToolhelp32SnapshotPtr)(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
364 {
365 // Get the first process' information.
366 pe.dwSize=sizeof(PROCESSENTRY32);
367 bResult=(*Process32FirstPtr)(hSnapShot, &pe);
368
369 // While there are processes, keep looping and checking.
370 while (bResult)
371 {
372 //Get file name
373 for (pName=pe.szExeFile + lstrlen(pe.szExeFile) - 1; *pName != '\\' && *pName != '\0'; --pName);
374
375 ++pName;
376
377 #ifdef UNICODE
378 MultiByteToWideChar(CP_ACP, 0, pName, lstrlenA(pName)+1, szName, MAX_PATH);
379 #else
380 lstrcpyn(szName, pName, MAX_PATH);
381 #endif
382
383 if (!lstrcmpi(szName, szProcessName))
384 {
385 // Process found
386 bFound=TRUE;
387
388 if (bTerminate == TRUE)
389 {
390 // Open for termination
391 NiceTerminate(pe.th32ProcessID, bClose, &bSuccess, &bFailed);
392 }
393 else break;
394 }
395 //Keep looking
396 bResult=(*Process32NextPtr)(hSnapShot, &pe);
397 }
398 CloseHandle(hSnapShot);
399 }
400 else uError=611;
401 }
402 else uError=610;
403
404 FreeLibrary(hLib);
405 }
406 else uError=609;
407 }
408
409 if (bFound == FALSE) return 603;
410 if (bTerminate == TRUE)
411 {
412 if (bSuccess == FALSE) return 601;
413 if (bFailed == TRUE) return 602;
414 }
415 return 0;
416 }
417