ReactOS  0.4.12-dev-102-g4b7f1e0
taskkill.c
Go to the documentation of this file.
1 /*
2  * Task termination utility
3  *
4  * Copyright 2008 Andrew Riedi
5  * Copyright 2010 Andrew Nguyen
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 St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdlib.h>
23 #include <windows.h>
24 #include <psapi.h>
25 #include <wine/debug.h>
26 #include <wine/unicode.h>
27 
28 #include "taskkill.h"
29 
31 
33 
34 static WCHAR **task_list;
35 static unsigned int task_count;
36 
38 {
41 };
42 
43 static int taskkill_vprintfW(const WCHAR *msg, __ms_va_list va_args)
44 {
45  int wlen;
46  DWORD count, ret;
47  WCHAR msg_buffer[8192];
48 
49  wlen = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, msg_buffer,
50  ARRAY_SIZE(msg_buffer), &va_args);
51 
52  ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
53  if (!ret)
54  {
55  DWORD len;
56  char *msgA;
57 
58  /* On Windows WriteConsoleW() fails if the output is redirected. So fall
59  * back to WriteFile(), assuming the console encoding is still the right
60  * one in that case.
61  */
62  len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
63  NULL, 0, NULL, NULL);
64  msgA = HeapAlloc(GetProcessHeap(), 0, len);
65  if (!msgA)
66  return 0;
67 
68  WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
69  NULL, NULL);
70  WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
71  HeapFree(GetProcessHeap(), 0, msgA);
72  }
73 
74  return count;
75 }
76 
77 static int WINAPIV taskkill_printfW(const WCHAR *msg, ...)
78 {
79  __ms_va_list va_args;
80  int len;
81 
82  __ms_va_start(va_args, msg);
83  len = taskkill_vprintfW(msg, va_args);
84  __ms_va_end(va_args);
85 
86  return len;
87 }
88 
89 static int WINAPIV taskkill_message_printfW(int msg, ...)
90 {
91  __ms_va_list va_args;
92  WCHAR msg_buffer[8192];
93  int len;
94 
95  LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
96 
97  __ms_va_start(va_args, msg);
98  len = taskkill_vprintfW(msg_buffer, va_args);
99  __ms_va_end(va_args);
100 
101  return len;
102 }
103 
104 static int taskkill_message(int msg)
105 {
106  static const WCHAR formatW[] = {'%','1',0};
107  WCHAR msg_buffer[8192];
108 
109  LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
110 
111  return taskkill_printfW(formatW, msg_buffer);
112 }
113 
114 /* Post WM_CLOSE to all top-level windows belonging to the process with specified PID. */
116 {
117  struct pid_close_info *info = (struct pid_close_info *)lParam;
118  DWORD hwnd_pid;
119 
120  GetWindowThreadProcessId(hwnd, &hwnd_pid);
121 
122  if (hwnd_pid == info->pid)
123  {
124  PostMessageW(hwnd, WM_CLOSE, 0, 0);
125  info->found = TRUE;
126  }
127 
128  return TRUE;
129 }
130 
132 {
133  DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes;
134 
135  pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes);
136  if (!pid_list)
137  return NULL;
138 
139  for (;;)
140  {
141  DWORD *realloc_list;
142 
143  if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes))
144  {
145  HeapFree(GetProcessHeap(), 0, pid_list);
146  return NULL;
147  }
148 
149  /* EnumProcesses can't signal an insufficient buffer condition, so the
150  * only way to possibly determine whether a larger buffer is required
151  * is to see whether the written number of bytes is the same as the
152  * buffer size. If so, the buffer will be reallocated to twice the
153  * size. */
154  if (alloc_bytes != needed_bytes)
155  break;
156 
157  alloc_bytes *= 2;
158  realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes);
159  if (!realloc_list)
160  {
161  HeapFree(GetProcessHeap(), 0, pid_list);
162  return NULL;
163  }
164  pid_list = realloc_list;
165  }
166 
167  *list_count = needed_bytes / sizeof(*pid_list);
168  return pid_list;
169 }
170 
172 {
173  HANDLE process;
174  HMODULE module;
175  DWORD required_size;
176 
178  if (!process)
179  return FALSE;
180 
181  if (!EnumProcessModules(process, &module, sizeof(module), &required_size))
182  {
183  CloseHandle(process);
184  return FALSE;
185  }
186 
187  if (!GetModuleBaseNameW(process, module, buf, chars))
188  {
189  CloseHandle(process);
190  return FALSE;
191  }
192 
193  CloseHandle(process);
194  return TRUE;
195 }
196 
197 /* The implemented task enumeration and termination behavior does not
198  * exactly match native behavior. On Windows:
199  *
200  * In the case of terminating by process name, specifying a particular
201  * process name more times than the number of running instances causes
202  * all instances to be terminated, but termination failure messages to
203  * be printed as many times as the difference between the specification
204  * quantity and the number of running instances.
205  *
206  * Successful terminations are all listed first in order, with failing
207  * terminations being listed at the end.
208  *
209  * A PID of zero causes taskkill to warn about the inability to terminate
210  * system processes. */
211 static int send_close_messages(void)
212 {
213  DWORD *pid_list, pid_list_size;
214  DWORD self_pid = GetCurrentProcessId();
215  unsigned int i;
216  int status_code = 0;
217 
218  pid_list = enumerate_processes(&pid_list_size);
219  if (!pid_list)
220  {
222  return 1;
223  }
224 
225  for (i = 0; i < task_count; i++)
226  {
227  WCHAR *p = task_list[i];
228  BOOL is_numeric = TRUE;
229 
230  /* Determine whether the string is not numeric. */
231  while (*p)
232  {
233  if (!isdigitW(*p++))
234  {
235  is_numeric = FALSE;
236  break;
237  }
238  }
239 
240  if (is_numeric)
241  {
242  DWORD pid = atoiW(task_list[i]);
243  struct pid_close_info info = { pid };
244 
245  if (pid == self_pid)
246  {
248  status_code = 1;
249  continue;
250  }
251 
253  if (info.found)
255  else
256  {
258  status_code = 128;
259  }
260  }
261  else
262  {
263  DWORD index;
264  BOOL found_process = FALSE;
265 
266  for (index = 0; index < pid_list_size; index++)
267  {
268  WCHAR process_name[MAX_PATH];
269 
270  if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) &&
271  !strcmpiW(process_name, task_list[i]))
272  {
273  struct pid_close_info info = { pid_list[index] };
274 
275  found_process = TRUE;
276  if (pid_list[index] == self_pid)
277  {
279  status_code = 1;
280  continue;
281  }
282 
284  taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]);
285  }
286  }
287 
288  if (!found_process)
289  {
291  status_code = 128;
292  }
293  }
294  }
295 
296  HeapFree(GetProcessHeap(), 0, pid_list);
297  return status_code;
298 }
299 
300 static int terminate_processes(void)
301 {
302  DWORD *pid_list, pid_list_size;
303  DWORD self_pid = GetCurrentProcessId();
304  unsigned int i;
305  int status_code = 0;
306 
307  pid_list = enumerate_processes(&pid_list_size);
308  if (!pid_list)
309  {
311  return 1;
312  }
313 
314  for (i = 0; i < task_count; i++)
315  {
316  WCHAR *p = task_list[i];
317  BOOL is_numeric = TRUE;
318 
319  /* Determine whether the string is not numeric. */
320  while (*p)
321  {
322  if (!isdigitW(*p++))
323  {
324  is_numeric = FALSE;
325  break;
326  }
327  }
328 
329  if (is_numeric)
330  {
331  DWORD pid = atoiW(task_list[i]);
332  HANDLE process;
333 
334  if (pid == self_pid)
335  {
337  status_code = 1;
338  continue;
339  }
340 
341  process = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
342  if (!process)
343  {
345  status_code = 128;
346  continue;
347  }
348 
349  if (!TerminateProcess(process, 0))
350  {
352  status_code = 1;
353  CloseHandle(process);
354  continue;
355  }
356 
358  CloseHandle(process);
359  }
360  else
361  {
362  DWORD index;
363  BOOL found_process = FALSE;
364 
365  for (index = 0; index < pid_list_size; index++)
366  {
367  WCHAR process_name[MAX_PATH];
368 
369  if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) &&
370  !strcmpiW(process_name, task_list[i]))
371  {
372  HANDLE process;
373 
374  if (pid_list[index] == self_pid)
375  {
377  status_code = 1;
378  continue;
379  }
380 
381  process = OpenProcess(PROCESS_TERMINATE, FALSE, pid_list[index]);
382  if (!process)
383  {
385  status_code = 128;
386  continue;
387  }
388 
389  if (!TerminateProcess(process, 0))
390  {
392  status_code = 1;
393  CloseHandle(process);
394  continue;
395  }
396 
397  found_process = TRUE;
399  CloseHandle(process);
400  }
401  }
402 
403  if (!found_process)
404  {
406  status_code = 128;
407  }
408  }
409  }
410 
411  HeapFree(GetProcessHeap(), 0, pid_list);
412  return status_code;
413 }
414 
416 {
417  static unsigned int list_size = 16;
418 
419  if (!task_list)
420  {
422  list_size * sizeof(*task_list));
423  if (!task_list)
424  return FALSE;
425  }
426  else if (task_count == list_size)
427  {
428  void *realloc_list;
429 
430  list_size *= 2;
431  realloc_list = HeapReAlloc(GetProcessHeap(), 0, task_list,
432  list_size * sizeof(*task_list));
433  if (!realloc_list)
434  return FALSE;
435 
436  task_list = realloc_list;
437  }
438 
440  return TRUE;
441 }
442 
443 /* FIXME Argument processing does not match behavior observed on Windows.
444  * Stringent argument counting and processing is performed, and unrecognized
445  * options are detected as parameters when placed after options that accept one. */
447 {
448  static const WCHAR opForceTerminate[] = {'f',0};
449  static const WCHAR opImage[] = {'i','m',0};
450  static const WCHAR opPID[] = {'p','i','d',0};
451  static const WCHAR opHelp[] = {'?',0};
452  static const WCHAR opTerminateChildren[] = {'t',0};
453 
454  if (argc > 1)
455  {
456  int i;
457  WCHAR *argdata;
458  BOOL has_im = FALSE, has_pid = FALSE;
459 
460  /* Only the lone help option is recognized. */
461  if (argc == 2)
462  {
463  argdata = argv[1];
464  if ((*argdata == '/' || *argdata == '-') && !strcmpW(opHelp, argdata + 1))
465  {
467  exit(0);
468  }
469  }
470 
471  for (i = 1; i < argc; i++)
472  {
473  BOOL got_im = FALSE, got_pid = FALSE;
474 
475  argdata = argv[i];
476  if (*argdata != '/' && *argdata != '-')
477  goto invalid;
478  argdata++;
479 
480  if (!strcmpiW(opTerminateChildren, argdata))
481  WINE_FIXME("argument T not supported\n");
482  if (!strcmpiW(opForceTerminate, argdata))
484  /* Options /IM and /PID appear to behave identically, except for
485  * the fact that they cannot be specified at the same time. */
486  else if ((got_im = !strcmpiW(opImage, argdata)) ||
487  (got_pid = !strcmpiW(opPID, argdata)))
488  {
489  if (!argv[i + 1])
490  {
493  return FALSE;
494  }
495 
496  if (got_im) has_im = TRUE;
497  if (got_pid) has_pid = TRUE;
498 
499  if (has_im && has_pid)
500  {
503  return FALSE;
504  }
505 
506  if (!add_to_task_list(argv[i + 1]))
507  return FALSE;
508  i++;
509  }
510  else
511  {
512  invalid:
515  return FALSE;
516  }
517  }
518  }
519  else
520  {
523  return FALSE;
524  }
525 
526  return TRUE;
527 }
528 
529 int wmain(int argc, WCHAR *argv[])
530 {
531  int status_code = 0;
532 
533  if (!process_arguments(argc, argv))
534  {
536  return 1;
537  }
538 
539  if (force_termination)
540  status_code = terminate_processes();
541  else
542  status_code = send_close_messages();
543 
545  return status_code;
546 }
#define STRING_CLOSE_PID_SEARCH
Definition: taskkill.h:30
static const WCHAR invalid[]
Definition: assoc.c:39
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
static int argc
Definition: ServiceArgs.c:12
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
#define STRING_USAGE
Definition: resource.h:26
#define STRING_CLOSE_PROC_SRCH
Definition: taskkill.h:31
static const char __ms_va_list
Definition: printf.c:70
#define TRUE
Definition: types.h:120
static BOOL force_termination
Definition: taskkill.c:32
#define CloseHandle
Definition: compat.h:398
HMODULE module
Definition: main.cpp:47
#define WideCharToMultiByte
Definition: compat.h:101
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:158
#define STRING_ENUM_FAILED
Definition: taskkill.h:35
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleW(IN HANDLE hConsoleOutput, IN CONST VOID *lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved)
Definition: readwrite.c:1449
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define FORMAT_MESSAGE_FROM_STRING
Definition: winbase.h:402
static int terminate_processes(void)
Definition: taskkill.c:300
static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars)
Definition: taskkill.c:171
#define STRING_TERM_PROC_SEARCH
Definition: taskkill.h:33
#define CALLBACK
Definition: compat.h:27
static int taskkill_vprintfW(const WCHAR *msg, __ms_va_list va_args)
Definition: taskkill.c:43
static HANDLE process
Definition: process.c:76
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
WINE_DEFAULT_DEBUG_CHANNEL(taskkill)
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
static char ** argv
Definition: ServiceArgs.c:11
int wmain(int argc, WCHAR *argv[])
Definition: taskkill.c:529
struct status_code status_code
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define STRING_MISSING_PARAM
Definition: taskkill.h:28
__WINE_SERVER_LIST_INLINE unsigned int list_count(const struct list *list)
Definition: list.h:155
LONG_PTR LPARAM
Definition: windef.h:208
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2453
#define STRING_MISSING_OPTION
Definition: taskkill.h:27
DWORD WINAPI GetWindowThreadProcessId(HWND, PDWORD)
UINT msg
Definition: msvc.h:92
smooth NULL
Definition: ftsmooth.c:416
static WCHAR ** task_list
Definition: taskkill.c:34
DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, LPWSTR lpBaseName, DWORD nSize)
Definition: psapi.c:930
#define STRING_SELF_TERMINATION
Definition: taskkill.h:37
static int WINAPIV taskkill_printfW(const WCHAR *msg,...)
Definition: taskkill.c:77
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded)
Definition: psapi.c:542
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static int taskkill_message(int msg)
Definition: taskkill.c:104
static BOOL add_to_task_list(WCHAR *name)
Definition: taskkill.c:415
#define WM_CLOSE
Definition: winuser.h:1603
static int send_close_messages(void)
Definition: taskkill.c:211
#define MAX_PATH
Definition: compat.h:26
BOOL WINAPI EnumWindows(_In_ WNDENUMPROC, _In_ LPARAM)
unsigned long DWORD
Definition: ntddk_ex.h:95
static BOOL process_arguments(int argc, WCHAR *argv[])
Definition: taskkill.c:446
static DWORD * enumerate_processes(DWORD *list_count)
Definition: taskkill.c:131
int ret
#define index(s, c)
Definition: various.h:29
GLenum GLsizei len
Definition: glext.h:6722
#define STRING_TERMINATE_FAILED
Definition: taskkill.h:36
#define STD_OUTPUT_HANDLE
Definition: winbase.h:265
#define WINAPIV
Definition: sdbpapi.h:64
#define strcmpiW(s1, s2)
Definition: unicode.h:39
static BOOL CALLBACK pid_enum_proc(HWND hwnd, LPARAM lParam)
Definition: taskkill.c:115
static int WINAPIV taskkill_message_printfW(int msg,...)
Definition: taskkill.c:89
HANDLE WINAPI OpenProcess(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwProcessId)
Definition: proc.c:1257
#define PROCESS_TERMINATE
Definition: pstypes.h:149
BOOL WINAPI EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded)
Definition: psapi.c:458
#define STRING_SEARCH_FAILED
Definition: taskkill.h:34
#define ARRAY_SIZE(a)
Definition: main.h:24
BOOL WINAPI TerminateProcess(IN HANDLE hProcess, IN UINT uExitCode)
Definition: proc.c:1562
#define HeapReAlloc
Definition: compat.h:393
WINE_UNICODE_INLINE int isdigitW(WCHAR wc)
Definition: unicode.h:170
#define __ms_va_end(list)
Definition: windef.h:448
#define PROCESS_VM_READ
Definition: pstypes.h:153
#define __ms_va_start(list, arg)
Definition: windef.h:447
Definition: name.c:36
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
WINE_UNICODE_INLINE int strcmpW(const WCHAR *str1, const WCHAR *str2)
Definition: unicode.h:229
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:845
#define STRING_INVALID_OPTION
Definition: resource.h:53
#define STRING_TERM_PID_SEARCH
Definition: taskkill.h:32
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
static unsigned int task_count
Definition: taskkill.c:35
LPARAM lParam
Definition: combotst.c:139
#define HeapFree(x, y, z)
Definition: compat.h:394
#define STRING_MUTUAL_EXCLUSIVE
Definition: taskkill.h:29
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1188
WINE_UNICODE_INLINE int atoiW(const WCHAR *str)
Definition: unicode.h:315
#define WINE_FIXME
Definition: debug.h:365
GLuint const GLchar * name
Definition: glext.h:6031