diff --git a/base/applications/cmdutils/taskkill/lang/de-DE.rc b/base/applications/cmdutils/taskkill/lang/de-DE.rc index 54a408fcc8a..01da0f287f9 100644 --- a/base/applications/cmdutils/taskkill/lang/de-DE.rc +++ b/base/applications/cmdutils/taskkill/lang/de-DE.rc @@ -2,7 +2,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL STRINGTABLE { - STRING_USAGE, "Usage: taskkill [/?] [/f] [/im Prozess Name | /pid Prozess ID]\n" + STRING_USAGE, "Usage: taskkill [/?] [/f] [/im Prozess Name | /pid Prozess ID] [/t]\n" STRING_INVALID_OPTION, "Fehler: Unbekannte oder ungülige Kommandozeilenoption angegeben.\n" STRING_INVALID_PARAM, "Fehler: Ungültiger Kommandozeilenparameter angegeben.\n" STRING_MISSING_OPTION, "Fehler: Eine der Optionen /im oder /pid muss angegeben werden.\n" @@ -16,6 +16,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Fehler: Prozessliste kann nicht aufgebaut werden.\n" STRING_TERMINATE_FAILED, "Fehler: Prozess ""%1"" kann nicht beendet werden.\n" STRING_SELF_TERMINATION, "Fehler: Der Prozess kann sich nicht selbst beenden.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Error: Invalid syntax. '%1' option is not allowed more than '%2!d!' time(s).\n" STRING_INVALID_SYNTAX, "Error: Invalid syntax.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/en-US.rc b/base/applications/cmdutils/taskkill/lang/en-US.rc index e34b34bad25..b1151dcacb2 100644 --- a/base/applications/cmdutils/taskkill/lang/en-US.rc +++ b/base/applications/cmdutils/taskkill/lang/en-US.rc @@ -2,7 +2,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT STRINGTABLE { - STRING_USAGE, "Usage: taskkill [/?] [/f] [/im ProcessName | /pid ProcessID]\n" + STRING_USAGE, "Usage: taskkill [/?] [/f] [/im ProcessName | /pid ProcessID] [/t]\n" STRING_INVALID_OPTION, "Error: Unknown or invalid command line option specified.\n" STRING_INVALID_PARAM, "Error: Invalid command line parameter specified.\n" STRING_MISSING_OPTION, "Error: One of options /im or /pid must be specified.\n" @@ -16,6 +16,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Error: Unable to enumerate the process list.\n" STRING_TERMINATE_FAILED, "Error: Unable to terminate process ""%1"".\n" STRING_SELF_TERMINATION, "Error: Process self-termination is not permitted.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Error: Invalid syntax. '%1' option is not allowed more than '%2!d!' time(s).\n" STRING_INVALID_SYNTAX, "Error: Invalid syntax.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/it-IT.rc b/base/applications/cmdutils/taskkill/lang/it-IT.rc index 0cb456bd91e..3c9ebf0f2ce 100644 --- a/base/applications/cmdutils/taskkill/lang/it-IT.rc +++ b/base/applications/cmdutils/taskkill/lang/it-IT.rc @@ -9,7 +9,7 @@ LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL STRINGTABLE { - STRING_USAGE, "Uso: taskkill [/?] [/f] [/im NomeProcesso | /pid IDProcesso]\n" + STRING_USAGE, "Uso: taskkill [/?] [/f] [/im NomeProcesso | /pid IDProcesso] [/t]\n" STRING_INVALID_OPTION, "Errore: L'opzione specificata è invalida o sconosciuta.\n" STRING_INVALID_PARAM, "Errore: Il parametro di comando a riga è invalido.\n" STRING_MISSING_OPTION, "Errore: Specifica una delle opzioni /im oppure /pid.\n" @@ -23,6 +23,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Errore: Impossibile enumerare la lista dei processi.\n" STRING_TERMINATE_FAILED, "Errore: Impossibile terminare il processo ""%1"".\n" STRING_SELF_TERMINATION, "Errore: L'auto-terminazione non è consentita.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Error: Invalid syntax. '%1' option is not allowed more than '%2!d!' time(s).\n" STRING_INVALID_SYNTAX, "Error: Invalid syntax.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/pl-PL.rc b/base/applications/cmdutils/taskkill/lang/pl-PL.rc index 5dd0f3ed463..9731945e3e4 100644 --- a/base/applications/cmdutils/taskkill/lang/pl-PL.rc +++ b/base/applications/cmdutils/taskkill/lang/pl-PL.rc @@ -9,7 +9,7 @@ LANGUAGE LANG_POLISH, SUBLANG_DEFAULT STRINGTABLE { - STRING_USAGE, "Sposób użycia: taskkill [/?] [/f] [/im nazwa_procesu | /pid id_procesu]\n" + STRING_USAGE, "Sposób użycia: taskkill [/?] [/f] [/im nazwa_procesu | /pid id_procesu] [/t]\n" STRING_INVALID_OPTION, "Błąd: Określono nieznaną lub nieprawidłową opcję.\n" STRING_INVALID_PARAM, "Błąd: Nieprawidłowy parametr.\n" STRING_MISSING_OPTION, "Błąd: Nie określono opcji /im ani /pid.\n" @@ -23,6 +23,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Błąd: Nie można wyliczyć listy procesów.\n" STRING_TERMINATE_FAILED, "Błąd: Nie można zakończyć procesu ""%1"".\n" STRING_SELF_TERMINATION, "Błąd: Proces nie może zakończyć sam siebie.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Błąd: Nieprawidłowa składnia. Opcja '%1' nie jest dozwolona więcej niż '%2!d!' razy.\n" STRING_INVALID_SYNTAX, "Błąd: Nieprawidłowa składnia.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/ro-RO.rc b/base/applications/cmdutils/taskkill/lang/ro-RO.rc index 476201fb5e1..585d025fa09 100644 --- a/base/applications/cmdutils/taskkill/lang/ro-RO.rc +++ b/base/applications/cmdutils/taskkill/lang/ro-RO.rc @@ -10,7 +10,7 @@ LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL STRINGTABLE { - STRING_USAGE, "Utilizare: taskkill [/?] [/f] [/im NumeProces | /pid IdProces]\n" + STRING_USAGE, "Utilizare: taskkill [/?] [/f] [/im NumeProces | /pid IdProces] [/t]\n" STRING_INVALID_OPTION, "Eroare: Opțiune specificată nevalidă sau necunoscută.\n" STRING_INVALID_PARAM, "Eroare: Parametrul de comandă specificat este nevalid.\n" STRING_MISSING_OPTION, "Eroare: Trebuie specificată una dintre opțiunile /im sau /pid.\n" @@ -24,6 +24,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Eroare: Nu se poate enumera lista de procese.\n" STRING_TERMINATE_FAILED, "Eroare: Procesul «%1» nu poate fi oprit.\n" STRING_SELF_TERMINATION, "Eroare: Auto-terminarea nu este permisă.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Eroare: Sintaxă nevalidă. Opțiunea '%1' nu este permisă mai mult de '%2!d!' dată(dăți).\n" STRING_INVALID_SYNTAX, "Eroare: Sintaxă nevalidă.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/ru-RU.rc b/base/applications/cmdutils/taskkill/lang/ru-RU.rc index 69ddc4bc113..730475871b0 100644 --- a/base/applications/cmdutils/taskkill/lang/ru-RU.rc +++ b/base/applications/cmdutils/taskkill/lang/ru-RU.rc @@ -4,7 +4,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT STRINGTABLE { - STRING_USAGE, "Использование: TASKKILL [/F] [/IM <образ> | /PID <процесс>]\n" + STRING_USAGE, "Использование: TASKKILL [/F] [/IM <образ> | /PID <процесс>] [/t]\n" STRING_INVALID_OPTION, "Ошибка: Указаны неверные параметры командной строки.\n" STRING_INVALID_PARAM, "Ошибка: Указаны неверные параметры командной строки.\n" STRING_MISSING_OPTION, "Ошибка: Должен быть указан параметр /im или /pid.\n" @@ -18,6 +18,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Ошибка: Не удается получить список процессов.\n" STRING_TERMINATE_FAILED, "Ошибка: Не удается завершить процесс ""%1"".\n" STRING_SELF_TERMINATION, "Ошибка: Процесс не может завершить сам себя.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Ошибка: Неверный синтаксис. Нельзя использовать опцию '%1' больше '%2!d!' раз(а).\n" STRING_INVALID_SYNTAX, "Ошибка: Неверный синтаксис.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/sq-AL.rc b/base/applications/cmdutils/taskkill/lang/sq-AL.rc index 85878177488..d4300272d66 100644 --- a/base/applications/cmdutils/taskkill/lang/sq-AL.rc +++ b/base/applications/cmdutils/taskkill/lang/sq-AL.rc @@ -6,7 +6,7 @@ LANGUAGE LANG_ALBANIAN, SUBLANG_NEUTRAL STRINGTABLE { - STRING_USAGE, "Usage: taskkill [/?] [/f] [/im ProcessName | /pid ProcessID]\n" + STRING_USAGE, "Usage: taskkill [/?] [/f] [/im ProcessName | /pid ProcessID] [/t]\n" STRING_INVALID_OPTION, "Gabim: Panjohur ose i pavlefshëm opsioni linjes komandes i specifikuar.\n" STRING_INVALID_PARAM, "Gabim: Pavlefshëm parametri i specifikuar ne linjen e komandes.\n" STRING_MISSING_OPTION, "Gabim: Njera nga opsionet /im ose /pid duhet te specifikohet.\n" @@ -20,6 +20,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Gabim: Në pamundësi për të numëruar listën proceseve.\n" STRING_TERMINATE_FAILED, "Gabim: Pamundur mbyllja e proceseve ""%1"".\n" STRING_SELF_TERMINATION, "Gabim: Procesi vetë-përfundimi nuk është i lejuar.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Error: Invalid syntax. '%1' option is not allowed more than '%2!d!' time(s).\n" STRING_INVALID_SYNTAX, "Error: Invalid syntax.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/tr-TR.rc b/base/applications/cmdutils/taskkill/lang/tr-TR.rc index d3f28161a2f..c990b148429 100644 --- a/base/applications/cmdutils/taskkill/lang/tr-TR.rc +++ b/base/applications/cmdutils/taskkill/lang/tr-TR.rc @@ -4,7 +4,7 @@ LANGUAGE LANG_TURKISH, SUBLANG_NEUTRAL STRINGTABLE { - STRING_USAGE, "Kullanım: taskkill [/?] [/f] [/im işlem adı | /pid işlem kimliği]\n" + STRING_USAGE, "Kullanım: taskkill [/?] [/f] [/im işlem adı | /pid işlem kimliği] [/t]\n" STRING_INVALID_OPTION, "Hata: Bilinmeyen veya geçersiz komut satırı seçeneği belirtildi.\n" STRING_INVALID_PARAM, "Hata: Geçersiz komut satırı değişkeni belirtildi.\n" STRING_MISSING_OPTION, "Hata: /im ve /pid seçeneklerinden biri belirtilmeli.\n" @@ -18,6 +18,9 @@ STRINGTABLE STRING_ENUM_FAILED, "Hata: İşlem numaralandırılamıyor.\n" STRING_TERMINATE_FAILED, "Hata: ""%1"" işlemi sonlandırılamıyor.\n" STRING_SELF_TERMINATION, "Hata: İşlemi kendi kendine sonlandırmaya izin verilmedi.\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "Hata: Geçersiz sözdizimi. '%1' seçeneğine '%2!d!'den fazla kez izin verilmiyor..\n" STRING_INVALID_SYNTAX, "Hata: Geçersiz sözdizimi.\n" } diff --git a/base/applications/cmdutils/taskkill/lang/zh-CN.rc b/base/applications/cmdutils/taskkill/lang/zh-CN.rc index 008e3f7005f..6ebea33f39f 100644 --- a/base/applications/cmdutils/taskkill/lang/zh-CN.rc +++ b/base/applications/cmdutils/taskkill/lang/zh-CN.rc @@ -7,7 +7,7 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED STRINGTABLE { - STRING_USAGE, "用法:taskkill [/?] [/f] [/im 进程名称 | /pid 进程 ID]\n" + STRING_USAGE, "用法:taskkill [/?] [/f] [/im 进程名称 | /pid 进程 ID] [/t]\n" STRING_INVALID_OPTION, "错误:指定了未知或无效的命令行选项。\n" STRING_INVALID_PARAM, "错误:指定了无效的命令行参数。\n" STRING_MISSING_OPTION, "错误:必须指定选项 /im 或 /pid。\n" @@ -21,6 +21,9 @@ STRINGTABLE STRING_ENUM_FAILED, "错误:无法枚举进程列表。\n" STRING_TERMINATE_FAILED, "错误:无法终止进程“%1”。\n" STRING_SELF_TERMINATION, "错误:不允许终止自身。\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "错误:无效语法。选项“%1”不允许超过“%2!d!”次。\n" STRING_INVALID_SYNTAX, "错误:无效语法。\n" } diff --git a/base/applications/cmdutils/taskkill/lang/zh-TW.rc b/base/applications/cmdutils/taskkill/lang/zh-TW.rc index 9f2b3637ceb..a6a746dcb7d 100644 --- a/base/applications/cmdutils/taskkill/lang/zh-TW.rc +++ b/base/applications/cmdutils/taskkill/lang/zh-TW.rc @@ -11,7 +11,7 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL STRINGTABLE { - STRING_USAGE, "用法: taskkill [/?] [/f] [/im 處理程序名稱 | /pid PID]\n" + STRING_USAGE, "用法: taskkill [/?] [/f] [/im 處理程序名稱 | /pid PID] [/t]\n" STRING_INVALID_OPTION, "錯誤: 指定了不明或不正確的命令列選項。\n" STRING_INVALID_PARAM, "錯誤: 指定了不正確的命令列參數。\n" STRING_MISSING_OPTION, "錯誤: 必須指定選項 /im 或 /pid 的其中之一。\n" @@ -25,6 +25,9 @@ STRINGTABLE STRING_ENUM_FAILED, "錯誤: 無法列舉處理程序清單。\n" STRING_TERMINATE_FAILED, "錯誤: 無法終止處理程序 '%1'。\n" STRING_SELF_TERMINATION, "錯誤: 處理程序不允許自我終止。\n" + STRING_CLOSE_CHILD, "Close message sent to top-level windows of process with PID %1!u!, child of PID %2!u!.\n" + STRING_TERM_CHILD, "Process with PID %1!u! was forcibly terminated, child of PID %2!u!.\n" + STRING_TERM_CHILD_FAILED, "Error: Unable to terminate process with PID %1!u!, child of PID %2!u!.\n" STRING_PARAM_TOO_MUCH, "錯誤: 無效的語法。'%1' 選項不允許超過 '%2!d!' 次。\n" STRING_INVALID_SYNTAX, "錯誤: 無效的語法。\n" } diff --git a/base/applications/cmdutils/taskkill/taskkill.c b/base/applications/cmdutils/taskkill/taskkill.c index 75706a66491..f0f301acfa9 100644 --- a/base/applications/cmdutils/taskkill/taskkill.c +++ b/base/applications/cmdutils/taskkill/taskkill.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(taskkill); static BOOL force_termination = FALSE; +static BOOL kill_child_processes = FALSE; static WCHAR **task_list; static unsigned int task_count; @@ -230,11 +232,74 @@ static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) * A PID of zero causes taskkill to warn about the inability to terminate * system processes. */ -#ifndef __REACTOS__ + +static BOOL get_pid_creation_time(DWORD pid, FILETIME *time) +{ + HANDLE process = INVALID_HANDLE_VALUE; + FILETIME t1 = { 0 }, t2 = { 0 }, t3 = { 0 }; + + process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!process) + { + return FALSE; + } + + if (!GetProcessTimes(process, time, &t1, &t2, &t3)) + { + CloseHandle(process); + return FALSE; + } + + CloseHandle(process); + return TRUE; +} + +static void send_close_messages_tree(DWORD ppid) +{ + FILETIME parent_creation_time = { 0 }; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32W pe = { 0 }; + pe.dwSize = sizeof(PROCESSENTRY32W); + + if (!get_pid_creation_time(ppid, &parent_creation_time) || !h) + { + CloseHandle(h); + return; + } + + if (Process32FirstW(h, &pe)) + { + do + { + FILETIME child_creation_time = { 0 }; + struct pid_close_info info = { pe.th32ProcessID }; + + if (!get_pid_creation_time(pe.th32ProcessID, &child_creation_time)) + { + continue; + } + + // Compare creation time to avoid reuse PID, thanks to @ThFabba + if (pe.th32ParentProcessID == ppid && + CompareFileTime(&parent_creation_time, &child_creation_time) < 0) + { + // Use recursion to browse all child processes + send_close_messages_tree(pe.th32ProcessID); + EnumWindows(pid_enum_proc, (LPARAM)&info); + if (info.found) + { + taskkill_message_printfW(STRING_CLOSE_CHILD, pe.th32ProcessID, ppid); + } + } + } while (Process32NextW(h, &pe)); + } + + CloseHandle(h); +} static int send_close_messages(void) { - DWORD *pid_list, pid_list_size; + DWORD *pid_list, pid_list_size, *pkill_list; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; @@ -246,10 +311,17 @@ static int send_close_messages(void) return 1; } + pkill_list = HeapAlloc(GetProcessHeap(), 0, pid_list_size * sizeof(DWORD)); + if (!pkill_list) + return 1; + for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; BOOL is_numeric = TRUE; + DWORD pkill_size = 0, index = 0; + + memset(pkill_list, 0, pid_list_size * sizeof(DWORD)); /* Determine whether the string is not numeric. */ while (*p) @@ -261,9 +333,43 @@ static int send_close_messages(void) } } + // Find processes to kill if (is_numeric) { - DWORD pid = atoiW(task_list[i]); + WCHAR ps_name[MAX_PATH] = { 0 }; + if (get_process_name_from_pid(atoiW(task_list[i]), ps_name, MAX_PATH)) + { + pkill_list[pkill_size] = atoiW(task_list[i]); + pkill_size++; + } + } + else + { + 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])) + { + pkill_list[pkill_size] = pid_list[index]; + pkill_size++; + } + } + } + + // Can't find any process same as name or PID + if (pkill_size == 0) + { + taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + status_code = 128; + continue; + } + + // Try to send close messages to process in `pkill_list` + for (index = 0; index < pkill_size; index++) + { + DWORD pid = pkill_list[index]; + WCHAR process_name[MAX_PATH] = { 0 }; struct pid_close_info info = { pid }; if (pid == self_pid) @@ -273,63 +379,90 @@ static int send_close_messages(void) continue; } + // Send close messages to child first + if (kill_child_processes) + { + send_close_messages_tree(pid); + } + + get_process_name_from_pid(pid, process_name, MAX_PATH); EnumWindows(pid_enum_proc, (LPARAM)&info); if (info.found) - taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, pid); - else { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - } - } - else - { - 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])) + if (is_numeric) { - struct pid_close_info info = { pid_list[index] }; - - found_process = TRUE; - if (pid_list[index] == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - - EnumWindows(pid_enum_proc, (LPARAM)&info); - taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]); + taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, pid); + } + else + { + taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid); } - } - - if (!found_process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; } } } + HeapFree(GetProcessHeap(), 0, pkill_list); HeapFree(GetProcessHeap(), 0, pid_list); return status_code; } -#endif // __REACTOS__ - -#ifdef __REACTOS__ -static int terminate_processes(BOOL force_termination) -#else -static int terminate_processes(void) -#endif +static void terminate_process_tree(DWORD ppid) { - DWORD *pid_list, pid_list_size; + FILETIME parent_creation_time = { 0 }; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32W pe = { 0 }; + pe.dwSize = sizeof(PROCESSENTRY32W); + + if (!get_pid_creation_time(ppid, &parent_creation_time) || !h) + { + CloseHandle(h); + return; + } + + if (Process32FirstW(h, &pe)) + { + do + { + FILETIME child_creation_time = { 0 }; + + if (!get_pid_creation_time(pe.th32ProcessID, &child_creation_time)) + { + continue; + } + + // Compare creation time to avoid reuse PID, thanks to @ThFabba + if (pe.th32ParentProcessID == ppid && + CompareFileTime(&parent_creation_time, &child_creation_time) < 0) + { + HANDLE process = INVALID_HANDLE_VALUE; + + // Use recursion to browse all child processes + terminate_process_tree(pe.th32ProcessID); + process = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID); + if (!process) + { + continue; + } + + if (!TerminateProcess(process, 0)) + { + taskkill_message_printfW(STRING_TERM_CHILD_FAILED, pe.th32ProcessID, ppid); + CloseHandle(process); + continue; + } + + taskkill_message_printfW(STRING_TERM_CHILD, pe.th32ProcessID, ppid); + CloseHandle(process); + } + } while (Process32NextW(h, &pe)); + } + + CloseHandle(h); +} + +static int terminate_processes(void) +{ + DWORD *pid_list, pid_list_size, *pkill_list; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; @@ -341,10 +474,17 @@ static int terminate_processes(void) return 1; } + pkill_list = HeapAlloc(GetProcessHeap(), 0, pid_list_size * sizeof(DWORD)); + if (!pkill_list) + return 1; + for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; BOOL is_numeric = TRUE; + DWORD pkill_size = 0, index = 0; + + memset(pkill_list, 0, pid_list_size * sizeof(DWORD)); /* Determine whether the string is not numeric. */ while (*p) @@ -356,12 +496,44 @@ static int terminate_processes(void) } } + // Find processes to kill if (is_numeric) { - DWORD pid = atoiW(task_list[i]); -#ifndef __REACTOS__ - HANDLE process; -#endif + WCHAR ps_name[MAX_PATH] = { 0 }; + if (get_process_name_from_pid(atoiW(task_list[i]), ps_name, MAX_PATH)) + { + pkill_list[pkill_size] = atoiW(task_list[i]); + pkill_size++; + } + } + else + { + 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])) + { + pkill_list[pkill_size] = pid_list[index]; + pkill_size++; + } + } + } + + // Can't find any process same as name or PID + if (!pkill_size) + { + taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + status_code = 128; + continue; + } + + // Try to terminate to process in `pkill_list` + for (index = 0; index < pkill_size; index++) + { + DWORD pid = pkill_list[index]; + WCHAR process_name[MAX_PATH] = { 0 }; + HANDLE process = INVALID_HANDLE_VALUE; if (pid == self_pid) { @@ -370,13 +542,14 @@ static int terminate_processes(void) continue; } -#ifdef __REACTOS__ - if (force_termination) + // Terminate child first + if (kill_child_processes) { - HANDLE process; -#endif + terminate_process_tree(pid); + } + process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - if (!process) + if (get_process_name_from_pid(pid, process_name, MAX_PATH) && !process) { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; @@ -385,102 +558,25 @@ static int terminate_processes(void) if (!TerminateProcess(process, 0)) { - taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); + taskkill_message_printfW(STRING_TERMINATE_FAILED, process_name); status_code = 1; CloseHandle(process); continue; } - taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); - CloseHandle(process); -#ifdef __REACTOS__ + if (is_numeric) + { + taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); } else { - struct pid_close_info info = { pid }; - - EnumWindows(pid_enum_proc, (LPARAM)&info); - if (info.found) - taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, pid); - else - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - } - } -#endif - } - else - { - 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])) - { -#ifdef __REACTOS__ - found_process = TRUE; -#else - HANDLE process; -#endif - - if (pid_list[index] == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - -#ifdef __REACTOS__ - if (force_termination) - { - HANDLE process; -#endif - process = OpenProcess(PROCESS_TERMINATE, FALSE, pid_list[index]); - if (!process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - continue; - } - - if (!TerminateProcess(process, 0)) - { - taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); - status_code = 1; - CloseHandle(process); - continue; - } - -#ifndef __REACTOS__ - found_process = TRUE; -#endif - taskkill_message_printfW(STRING_TERM_PROC_SEARCH, task_list[i], pid_list[index]); - CloseHandle(process); -#ifdef __REACTOS__ - } - else - { - struct pid_close_info info = { pid_list[index] }; - EnumWindows(pid_enum_proc, (LPARAM)&info); - taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]); - } -#endif - } - } - - if (!found_process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; + taskkill_message_printfW(STRING_TERM_PROC_SEARCH, process_name, pid); } + CloseHandle(process); } } + HeapFree(GetProcessHeap(), 0, pkill_list); HeapFree(GetProcessHeap(), 0, pid_list); return status_code; } @@ -535,10 +631,6 @@ static int get_argument_type(WCHAR* argument) return OP_PARAM_INVALID; } -/* FIXME -argument T not supported -*/ - static BOOL process_arguments(int argc, WCHAR* argv[]) { BOOL has_im = FALSE, has_pid = FALSE, has_help = FALSE; @@ -612,7 +704,14 @@ static BOOL process_arguments(int argc, WCHAR* argv[]) } case OP_PARAM_TERMINATE_CHILD: { - WINE_FIXME("argument T not supported\n"); + if (kill_child_processes == TRUE) + { + // -t already specified + taskkill_message_printfW(STRING_PARAM_TOO_MUCH, argv[i], 1); + taskkill_message(STRING_USAGE); + return FALSE; + } + kill_child_processes = TRUE; break; } case OP_PARAM_INVALID: @@ -691,8 +790,8 @@ static BOOL process_arguments(int argc, WCHAR *argv[]) argdata++; if (!strcmpiW(opTerminateChildren, argdata)) - WINE_FIXME("argument T not supported\n"); - if (!strcmpiW(opForceTerminate, argdata)) + kill_child_processes = TRUE; + else if (!strcmpiW(opForceTerminate, argdata)) force_termination = TRUE; /* Options /IM and /PID appear to behave identically, except for * the fact that they cannot be specified at the same time. */ @@ -751,14 +850,10 @@ int wmain(int argc, WCHAR *argv[]) return 1; } -#ifdef __REACTOS__ - status_code = terminate_processes(force_termination); -#else if (force_termination) status_code = terminate_processes(); else status_code = send_close_messages(); -#endif HeapFree(GetProcessHeap(), 0, task_list); return status_code; diff --git a/base/applications/cmdutils/taskkill/taskkill.h b/base/applications/cmdutils/taskkill/taskkill.h index 03312fa8c9c..68f84fe8159 100644 --- a/base/applications/cmdutils/taskkill/taskkill.h +++ b/base/applications/cmdutils/taskkill/taskkill.h @@ -35,6 +35,8 @@ #define STRING_ENUM_FAILED 112 #define STRING_TERMINATE_FAILED 113 #define STRING_SELF_TERMINATION 114 -#define STRING_PARAM_TOO_MUCH 115 -#define STRING_INVALID_SYNTAX 116 - +#define STRING_CLOSE_CHILD 115 +#define STRING_TERM_CHILD 116 +#define STRING_TERM_CHILD_FAILED 117 +#define STRING_PARAM_TOO_MUCH 118 +#define STRING_INVALID_SYNTAX 119