diff --git a/programs/taskkill/En.rc b/programs/taskkill/En.rc index ccad8855a86..a37321de116 100644 --- a/programs/taskkill/En.rc +++ b/programs/taskkill/En.rc @@ -32,5 +32,7 @@ STRINGTABLE STRING_MISSING_PARAM, "Error: Option %s expects a command line parameter.\n" STRING_MUTUAL_EXCLUSIVE, "Error: Options /im and /pid are mutually exclusive.\n" STRING_CLOSE_PID_SEARCH, "Close message sent to top-level windows of process with PID %u.\n" + STRING_CLOSE_PROC_SRCH, "Close message sent to top-level windows of process \"%s\" with PID %u.\n" STRING_SEARCH_FAILED, "Error: Could not find process \"%s\".\n" + STRING_ENUM_FAILED, "Error: Unable to enumerate the process list.\n" } diff --git a/programs/taskkill/Makefile.in b/programs/taskkill/Makefile.in index 9dce65a7143..b3bfff33c06 100644 --- a/programs/taskkill/Makefile.in +++ b/programs/taskkill/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -DWINE_NO_UNICODE_MACROS MODULE = taskkill.exe APPMODE = -mconsole -municode -IMPORTS = user32 +IMPORTS = psapi user32 C_SRCS = taskkill.c diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index 4b9fb94438c..f24883b2c75 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -123,6 +124,72 @@ static BOOL CALLBACK pid_enum_proc(HWND hwnd, LPARAM lParam) return TRUE; } +static DWORD *enumerate_processes(DWORD *list_count) +{ + DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes; + + pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes); + if (!pid_list) + return NULL; + + for (;;) + { + DWORD *realloc_list; + + if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes)) + { + HeapFree(GetProcessHeap(), 0, pid_list); + return NULL; + } + + /* EnumProcesses can't signal an insufficient buffer condition, so the + * only way to possibly determine whether a larger buffer is required + * is to see whether the written number of bytes is the same as the + * buffer size. If so, the buffer will be reallocated to twice the + * size. */ + if (alloc_bytes != needed_bytes) + break; + + alloc_bytes *= 2; + realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes); + if (!realloc_list) + { + HeapFree(GetProcessHeap(), 0, pid_list); + return NULL; + } + pid_list = realloc_list; + } + + *list_count = needed_bytes / sizeof(*pid_list); + return pid_list; +} + +static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) +{ + HANDLE process; + HMODULE module; + DWORD required_size; + + process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (!process) + return FALSE; + + if (!EnumProcessModules(process, &module, sizeof(module), &required_size)) + { + CloseHandle(process); + return FALSE; + } + + if (!GetModuleBaseNameW(process, module, buf, chars)) + { + CloseHandle(process); + return FALSE; + } + + CloseHandle(process); + return TRUE; +} + /* The implemented task enumeration and termination behavior does not * exactly match native behavior. On Windows: * @@ -139,9 +206,17 @@ static BOOL CALLBACK pid_enum_proc(HWND hwnd, LPARAM lParam) * system processes. */ static int send_close_messages(void) { + DWORD *pid_list, pid_list_size; unsigned int i; int status_code = 0; + pid_list = enumerate_processes(&pid_list_size); + if (!pid_list) + { + taskkill_message(STRING_ENUM_FAILED); + return 1; + } + for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; @@ -172,9 +247,34 @@ static int send_close_messages(void) } } else - WINE_FIXME("Termination by name is not implemented\n"); + { + DWORD index; + BOOL found_process = FALSE; + + for (index = 0; index < pid_list_size; index++) + { + WCHAR process_name[MAX_PATH]; + + if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) && + !strcmpiW(process_name, task_list[i])) + { + struct pid_close_info info = { pid_list[index] }; + + found_process = TRUE; + EnumWindows(pid_enum_proc, (LPARAM)&info); + taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]); + } + } + + if (!found_process) + { + taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + status_code = 128; + } + } } + HeapFree(GetProcessHeap(), 0, pid_list); return status_code; } diff --git a/programs/taskkill/taskkill.h b/programs/taskkill/taskkill.h index 1cc09af54eb..802d5237223 100644 --- a/programs/taskkill/taskkill.h +++ b/programs/taskkill/taskkill.h @@ -28,4 +28,6 @@ #define STRING_MISSING_PARAM 105 #define STRING_MUTUAL_EXCLUSIVE 106 #define STRING_CLOSE_PID_SEARCH 107 -#define STRING_SEARCH_FAILED 108 +#define STRING_CLOSE_PROC_SRCH 108 +#define STRING_SEARCH_FAILED 109 +#define STRING_ENUM_FAILED 110