From: Zhiyi Zhang zzhang@codeweavers.com
Some filters such as STATUS and CPUTIME are not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48596 --- programs/tasklist/tasklist.c | 173 ++++++++++++++++++++++++++++- programs/tasklist/tasklist.h | 32 ++++++ programs/tasklist/tasklist.rc | 1 + programs/tasklist/tests/tasklist.c | 104 +++++++++++++++++ 4 files changed, 305 insertions(+), 5 deletions(-)
diff --git a/programs/tasklist/tasklist.c b/programs/tasklist/tasklist.c index c8cb8804c3a..4f866f6b727 100644 --- a/programs/tasklist/tasklist.c +++ b/programs/tasklist/tasklist.c @@ -173,6 +173,9 @@ static BOOL tasklist_get_process_info(const PROCESSENTRY32W *process_entry, stru if (info->memory_usage[0] == '\0') wcscpy(info->memory_usage, L"N/A");
+ info->pid_value = process_entry->th32ProcessID; + info->memory_usage_value = memory_counters.WorkingSetSize / 1024; + info->session_id_value = session_id; wcscpy(info->image_name, process_entry->szExeFile); swprintf(info->pid, ARRAY_SIZE(info->pid), L"%u", process_entry->th32ProcessID); wcscpy(info->session_name, session_id == 0 ? L"Services" : L"Console"); @@ -180,6 +183,67 @@ static BOOL tasklist_get_process_info(const PROCESSENTRY32W *process_entry, stru return TRUE; }
+static BOOL tasklist_check_filters(const struct tasklist_filter *filter, + const struct tasklist_process_info *info) +{ + DWORD left_dword_operand, right_dword_operand; + const WCHAR *left_string_operand = NULL; + BOOL eval; + + while (filter) + { + left_string_operand = NULL; + left_dword_operand = 0; + eval = FALSE; + + if (filter->name == IMAGENAME) + left_string_operand = info->image_name; + else if (filter->name == SESSIONNAME) + left_string_operand = info->session_name; + else if (filter->name == PID) + left_dword_operand = info->pid_value; + else if (filter->name == SESSION) + left_dword_operand = info->session_id_value; + else if (filter->name == MEMUSAGE) + left_dword_operand = info->memory_usage_value; + + if (left_string_operand) + { + eval = wcsicmp(left_string_operand, filter->value); + if (filter->op == EQ) + eval = !eval; + } + else + { + if (swscanf(filter->value, L"%lu", &right_dword_operand) != 1) + { + WINE_ERR("Invalid filter operand %s.\n", wine_dbgstr_w(filter->value)); + return FALSE; + } + + if (filter->op == EQ) + eval = left_dword_operand == right_dword_operand; + else if (filter->op == NE) + eval = left_dword_operand != right_dword_operand; + else if (filter->op == GT) + eval = left_dword_operand > right_dword_operand; + else if (filter->op == LT) + eval = left_dword_operand < right_dword_operand; + else if (filter->op == GE) + eval = left_dword_operand >= right_dword_operand; + else if (filter->op == LE) + eval = left_dword_operand <= right_dword_operand; + } + + if (!eval) + return FALSE; + + filter = filter->next; + } + + return TRUE; +} + static void tasklist_print(const struct tasklist_options *options) { struct tasklist_process_info header, info; @@ -207,6 +271,9 @@ static void tasklist_print(const struct tasklist_options *options) if (!tasklist_get_process_info(&process_list[i], &info)) continue;
+ if (!tasklist_check_filters(options->filters, &info)) + continue; + if (options->format == TABLE) wprintf(L"%-25.25s %8.8s %-16.16s %11.11s %12s\n", info.image_name, info.pid, info.session_name, info.session_number, info.memory_usage); @@ -232,7 +299,9 @@ static void tasklist_print(const struct tasklist_options *options) int __cdecl wmain(int argc, WCHAR *argv[]) { struct tasklist_options options = {0}; - int i; + struct tasklist_filter *filter, *next, **filter_ptr = &options.filters; + WCHAR *filter_name, *filter_op, *buffer; + int i, ret = 0;
for (i = 0; i < argc; i++) WINE_TRACE("%s ", wine_dbgstr_w(argv[i])); @@ -243,7 +312,7 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (!wcscmp(argv[i], L"/?")) { tasklist_message(STRING_USAGE); - return 0; + goto done; } else if (!wcsicmp(argv[i], L"/nh")) { @@ -254,7 +323,8 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (i + 1 >= argc) { tasklist_error(STRING_INVALID_SYNTAX); - return 1; + ret = 1; + goto done; } else if (!wcsicmp(argv[i + 1], L"TABLE")) { @@ -271,9 +341,93 @@ int __cdecl wmain(int argc, WCHAR *argv[]) else { tasklist_error(STRING_INVALID_SYNTAX); - return 1; + ret = 1; + goto done; } } + else if (!wcsicmp(argv[i], L"/fi")) + { + if (i + 1 >= argc || !(filter_name = wcstok(argv[i + 1], L" ", &buffer))) + { + tasklist_error(STRING_INVALID_SYNTAX); + ret = 1; + goto done; + } + + filter = calloc(1, sizeof(*filter)); + if (!filter) + { + WINE_ERR("Out of memory.\n"); + ret = 1; + goto done; + } + + if (!wcsicmp(filter_name, L"IMAGENAME")) + filter->name = IMAGENAME; + else if (!wcsicmp(filter_name, L"PID")) + filter->name = PID; + else if (!wcsicmp(filter_name, L"SESSION")) + filter->name = SESSION; + else if (!wcsicmp(filter_name, L"SESSIONNAME")) + filter->name = SESSIONNAME; + else if (!wcsicmp(filter_name, L"MEMUSAGE")) + filter->name = MEMUSAGE; + else + { + WINE_WARN("Ignoring filter %s.\n", wine_dbgstr_w(filter_name)); + free(filter); + continue; + } + + filter_op = wcstok(NULL, L" ", &buffer); + if (!filter_op) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + if (!wcsicmp(filter_op, L"EQ")) + filter->op = EQ; + else if (!wcsicmp(filter_op, L"NE")) + filter->op = NE; + else if (!wcsicmp(filter_op, L"GT")) + filter->op = GT; + else if (!wcsicmp(filter_op, L"LT")) + filter->op = LT; + else if (!wcsicmp(filter_op, L"GE")) + filter->op = GE; + else if (!wcsicmp(filter_op, L"LE")) + filter->op = LE; + else + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + if (filter->op >= GT && filter->name != PID && filter->name != SESSION && filter->name != MEMUSAGE) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + filter->value = wcstok(NULL, L" ", &buffer); + if (!filter->value) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + *filter_ptr = filter; + filter_ptr = &filter->next; + } else { WINE_WARN("Ignoring option %s\n", wine_dbgstr_w(argv[i])); @@ -281,5 +435,14 @@ int __cdecl wmain(int argc, WCHAR *argv[]) }
tasklist_print(&options); - return 0; + +done: + next = options.filters; + while (next) + { + filter = next->next; + free(next); + next = filter; + } + return ret; } diff --git a/programs/tasklist/tasklist.h b/programs/tasklist/tasklist.h index 5e4e90960ea..7b05224757f 100644 --- a/programs/tasklist/tasklist.h +++ b/programs/tasklist/tasklist.h @@ -28,6 +28,7 @@ #define STRING_MEM_USAGE 106 #define STRING_K 107 #define STRING_INVALID_SYNTAX 108 +#define STRING_FILTER_NOT_RECOGNIZED 109
enum tasklist_format { @@ -36,8 +37,38 @@ enum tasklist_format LIST = 2, };
+enum tasklist_filter_name +{ + IMAGENAME = 1, + PID = 2, + SESSION = 3, + SESSIONNAME = 4, + MEMUSAGE = 5, +}; + +enum tasklist_filter_operator +{ + EQ = 0, + NE = 1, + GT = 2, + LT = 3, + GE = 4, + LE = 5, +}; + +struct tasklist_filter +{ + enum tasklist_filter_name name; + enum tasklist_filter_operator op; + WCHAR *value; + struct tasklist_filter *next; +}; + struct tasklist_process_info { + DWORD pid_value; + DWORD memory_usage_value; + DWORD session_id_value; WCHAR image_name[32]; WCHAR pid[32]; WCHAR session_name[32]; @@ -49,4 +80,5 @@ struct tasklist_options { BOOL no_header; enum tasklist_format format; + struct tasklist_filter *filters; }; diff --git a/programs/tasklist/tasklist.rc b/programs/tasklist/tasklist.rc index f92b0348f72..b5aaccc5391 100644 --- a/programs/tasklist/tasklist.rc +++ b/programs/tasklist/tasklist.rc @@ -33,6 +33,7 @@ STRINGTABLE STRING_MEM_USAGE, "Mem Usage" STRING_K, "K" STRING_INVALID_SYNTAX, "ERROR: Invalid syntax\n" + STRING_FILTER_NOT_RECOGNIZED, "ERROR: The search filter cannot be recognized.\n" }
#define WINE_FILEDESCRIPTION_STR "Wine tasklist" diff --git a/programs/tasklist/tests/tasklist.c b/programs/tasklist/tests/tasklist.c index 011bfdeb382..28c15ed3984 100644 --- a/programs/tasklist/tests/tasklist.c +++ b/programs/tasklist/tests/tasklist.c @@ -17,6 +17,7 @@ */
#include <windows.h> +#include <psapi.h> #include "wine/test.h"
#define MAX_BUFFER 65536 @@ -164,6 +165,108 @@ static void test_format(void) ok(!!pos, "Failed to list tasklist.exe.\n"); }
+static void test_filter(void) +{ + char options[256], *pos, basename[64]; + HANDLE current_process; + DWORD current_pid; + + current_pid = GetCurrentProcessId(); + current_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, current_pid); + GetModuleBaseNameA(current_process, NULL, basename, ARRAY_SIZE(basename)); + CloseHandle(current_process); + + /* /fi */ + /* no value for fi */ + run_tasklist("/fi", 1); + ok(stdout_size == 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size > 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + + /* IMAGENAME eq */ + sprintf(options, "/fi "IMAGENAME eq %s"", basename); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* IMAGENAME ne */ + sprintf(options, "/fi "IMAGENAME ne %s"", basename); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!pos, "Got %s.\n", basename); + pos = strstr(stdout_buffer, "tasklist.exe"); + ok(!!pos, "Failed to list tasklist.exe.\n"); + + /* PID eq */ + sprintf(options, "/fi "PID eq %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* PID ne */ + sprintf(options, "/fi "PID ne %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!pos, "Got %s.\n", basename); + pos = strstr(stdout_buffer, "tasklist.exe"); + ok(!!pos, "Failed to list tasklist.exe.\n"); + + /* PID gt */ + sprintf(options, "/fi "PID gt %ld"", current_pid - 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* PID lt */ + sprintf(options, "/fi "PID lt %ld"", current_pid + 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* PID ge */ + sprintf(options, "/fi "PID ge %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* PID le */ + sprintf(options, "/fi "PID le %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* IMAGENAME eq + PID eq */ + sprintf(options, "/fi "IMAGENAME eq %s" /fi "PID eq %ld"", basename, current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!!pos, "Failed to list %s.\n", basename); + + /* IMAGENAME eq + PID eq with wrong PID */ + sprintf(options, "/fi "IMAGENAME eq %s" /fi "PID eq %ld"", basename, current_pid + 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, basename); + ok(!pos, "Got %s.\n", basename); +} + START_TEST(tasklist) { if (PRIMARYLANGID(GetUserDefaultUILanguage()) != LANG_ENGLISH) @@ -175,4 +278,5 @@ START_TEST(tasklist) test_basic(); test_no_header(); test_format(); + test_filter(); }