ReactOS  0.4.14-dev-606-g14ebc0b
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);
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  {
184  return FALSE;
185  }
186 
187  if (!GetModuleBaseNameW(process, module, buf, chars))
188  {
190  return FALSE;
191  }
192 
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 
342  if (!process)
343  {
345  status_code = 128;
346  continue;
347  }
348 
349  if (!TerminateProcess(process, 0))
350  {
352  status_code = 1;
354  continue;
355  }
356 
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 
382  if (!process)
383  {
385  status_code = 128;
386  continue;
387  }
388 
389  if (!TerminateProcess(process, 0))
390  {
392  status_code = 1;
394  continue;
395  }
396 
397  found_process = TRUE;
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)
541  else
543 
545  return status_code;
546 }
#define STRING_CLOSE_PID_SEARCH
Definition: taskkill.h:30
static const WCHAR invalid[]
Definition: assoc.c:39
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
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
#define TRUE
Definition: types.h:120
static BOOL force_termination
Definition: taskkill.c:32
#define CloseHandle
Definition: compat.h:406
HMODULE module
Definition: main.cpp:47
#define WideCharToMultiByte
Definition: compat.h:101
static static const char __ms_va_list
Definition: printf.c:76
#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
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
#define argv
Definition: mplay32.c:18
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)
int wmain(int argc, WCHAR *argv[])
Definition: taskkill.c:529
struct status_code status_code
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define STRING_MISSING_PARAM
Definition: taskkill.h:28
unsigned int BOOL
Definition: ntddk_ex.h:94
__WINE_SERVER_LIST_INLINE unsigned int list_count(const struct list *list)
Definition: list.h:155
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2453
#define STRING_MISSING_OPTION
Definition: taskkill.h:27
DWORD WINAPI GetWindowThreadProcessId(HWND, PDWORD)
smooth NULL
Definition: ftsmooth.c:416
LONG_PTR LPARAM
Definition: windef.h:208
GLuint index
Definition: glext.h:6031
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 EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded)
Definition: psapi.c:542
#define GetProcessHeap()
Definition: compat.h:403
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static int taskkill_message(int msg)
Definition: taskkill.c:104
__wchar_t WCHAR
Definition: xmlstorage.h:180
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:1227
#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:1532
#define HeapReAlloc
Definition: compat.h:401
WINE_UNICODE_INLINE int isdigitW(WCHAR wc)
Definition: unicode.h:170
#define __ms_va_end(list)
Definition: windef.h:458
#define msg(x)
Definition: auth_time.c:54
#define PROCESS_VM_READ
Definition: pstypes.h:153
#define __ms_va_start(list, arg)
Definition: windef.h:457
Definition: name.c:38
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:847
#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:402
#define STRING_MUTUAL_EXCLUSIVE
Definition: taskkill.h:29
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1158
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