ReactOS  0.4.15-dev-2700-g4b4ffa9
tasklist.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Tasklist Command
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: Displays a list of currently running processes on the computer.
5  * COPYRIGHT: Copyright 2021 He Yang (1160386205@qq.com)
6  */
7 
8 #include "tasklist.h"
9 
10 // the strings in OptionList are the command-line options.
11 // should always correspond with the defines below, in sequence (except OPTION_INVALID)
12 static PCWSTR OptionList[] = { L"?", L"nh" };
13 
14 #define OPTION_INVALID -1
15 #define OPTION_HELP 0
16 #define OPTION_NOHEADER 1
17 
18 // the max string length PrintResString can handle
19 #define RES_STR_MAXLEN 64
20 
21 // Print split line
23 {
24  for (; Length; Length--)
25  {
26  ConPuts(StdOut, L"=");
27  }
28 }
29 
30 // Print spaces
32 {
33  ConPrintf(StdOut, L"%*ls", (INT)Length, L"");
34 }
35 
36 // Print a string.
37 // if bAlignLeft == TRUE then aligned to left, otherwise aligned to right
38 // MaxWidth is the width for printing.
39 VOID PrintString(LPCWSTR String, UINT MaxWidth, BOOL bAlignLeft)
40 {
41  ConPrintf(StdOut, bAlignLeft ? L"%-*.*ls" : L"%*.*ls", MaxWidth, MaxWidth, String);
42 }
43 
44 // Print a string from resource
45 // if bAlignLeft == TRUE then aligned to left, otherwise aligned to right
46 // MaxWidth is the width for printing.
47 // The string WILL be truncated if it's longer than RES_STR_MAXLEN
48 VOID PrintResString(HINSTANCE hInstance, UINT uID, UINT MaxWidth, BOOL bAlignLeft)
49 {
50  if (!hInstance)
51  return;
52 
55  PrintString(StringBuffer, MaxWidth, bAlignLeft);
56 }
57 
58 // Print a number, aligned to right.
59 // MaxWidth is the width for printing.
60 // the number WILL NOT be truncated if it's longer than MaxWidth
62 {
63  ConPrintf(StdOut, L"%*lld", MaxWidth, Number);
64 }
65 
66 // Print memory size using KB as unit, with comma-separated number, aligned to right.
67 // MaxWidth is the width for printing.
68 // the number WILL be truncated if it's longer than MaxWidth
69 BOOL PrintMemory(SIZE_T MemorySizeByte, UINT MaxWidth, HINSTANCE hInstance)
70 {
71  if (!hInstance)
72  return FALSE;
73 
74  SIZE_T MemorySize = MemorySizeByte >> 10;
75 
76  WCHAR NumberString[27] = { 0 }; // length 26 is enough to display ULLONG_MAX in decimal with comma, one more for zero-terminated.
77  C_ASSERT(sizeof(SIZE_T) <= 8);
78 
79  PWCHAR pNumberStr = NumberString;
80 
81  // calculate the length
82  UINT PrintLength = 0;
83  SIZE_T Tmp = MemorySize;
84  UINT Mod = 1;
85 
86  do
87  {
88  Tmp /= 10;
89  PrintLength++;
90  Mod *= 10;
91  } while (Tmp);
92 
93  for (UINT i = PrintLength; i; i--)
94  {
95  Mod /= 10;
96  *pNumberStr = L'0' + (MemorySize / Mod);
97  MemorySize %= Mod;
98  pNumberStr++;
99 
100  if (i != 1 && i % 3 == 1)
101  {
102  *pNumberStr = L',';
103  pNumberStr++;
104  }
105  }
106 
107  WCHAR FormatStr[RES_STR_MAXLEN];
108  LoadStringW(hInstance, IDS_MEMORY_STR, FormatStr, _countof(FormatStr));
109 
110  WCHAR String[RES_STR_MAXLEN + _countof(NumberString)] = { 0 };
111 
112  StringCchPrintfW(String, _countof(String), FormatStr, NumberString);
113  PrintString(String, MaxWidth, FALSE);
114 
115  return TRUE;
116 }
117 
119 {
120  if (!hInstance)
121  return;
122 
124  PrintSpace(1);
126  PrintSpace(1);
128  PrintSpace(1);
130 
131  ConPuts(StdOut, L"\n");
132 
134  PrintSpace(1);
136  PrintSpace(1);
138  PrintSpace(1);
140 
141  ConPuts(StdOut, L"\n");
142 }
143 
145 {
146  // Call NtQuerySystemInformation for the process information
147  ULONG ProcessInfoBufferLength = 0;
148  ULONG ResultLength = 0;
149  PBYTE ProcessInfoBuffer = NULL;
150 
151  // Get the buffer size we need
153 
154  // New process/thread might appear before we call for the actual data.
155  // Try to avoid this by retrying several times.
157  {
158  // (Re)allocate buffer
159  ProcessInfoBufferLength = ResultLength;
160  ResultLength = 0;
161  if (ProcessInfoBuffer)
162  {
163  PBYTE NewProcessInfoBuffer = HeapReAlloc(GetProcessHeap(), 0,
164  ProcessInfoBuffer,
165  ProcessInfoBufferLength);
166  if (NewProcessInfoBuffer)
167  {
168  ProcessInfoBuffer = NewProcessInfoBuffer;
169  }
170  else
171  {
172  // out of memory
174  HeapFree(GetProcessHeap(), 0, ProcessInfoBuffer);
175  return FALSE;
176  }
177  }
178  else
179  {
180  ProcessInfoBuffer = HeapAlloc(GetProcessHeap(), 0, ProcessInfoBufferLength);
181  if (!ProcessInfoBuffer)
182  {
183  // out of memory
185  return FALSE;
186  }
187  }
188 
189  // Query information
191  ProcessInfoBuffer,
192  ProcessInfoBufferLength,
193  &ResultLength);
195  {
196  break;
197  }
198  }
199 
200  if (!NT_SUCCESS(Status))
201  {
202  // tried NT_SYSTEM_QUERY_MAX_RETRY times, or failed with some other reason
204  HeapFree(GetProcessHeap(), 0, ProcessInfoBuffer);
205  return FALSE;
206  }
207 
209  assert(hInstance);
210 
211  ConPuts(StdOut, L"\n");
212 
213  if (!bNoHeader)
214  {
216  }
217 
219  pSPI = (PSYSTEM_PROCESS_INFORMATION)ProcessInfoBuffer;
220  while (pSPI)
221  {
222  PrintString(pSPI->UniqueProcessId ? pSPI->ImageName.Buffer : L"System Idle Process", COLUMNWIDTH_IMAGENAME, TRUE);
223  PrintSpace(1);
225  PrintSpace(1);
227  PrintSpace(1);
229 
230  ConPuts(StdOut, L"\n");
231 
232  if (pSPI->NextEntryOffset == 0)
233  break;
234  pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset);
235  }
236 
237  HeapFree(GetProcessHeap(), 0, ProcessInfoBuffer);
238  return TRUE;
239 }
240 
242 {
243  if (szOption[0] != L'/' && szOption[0] != L'-')
244  {
245  return OPTION_INVALID;
246  }
247  szOption++;
248 
249  for (UINT i = 0; i < _countof(OptionList); i++)
250  {
251  if (!_wcsicmp(OptionList[i], szOption))
252  {
253  return i;
254  }
255  }
256  return OPTION_INVALID;
257 }
258 
260 {
261  BOOL bHasHelp = FALSE, bHasNoHeader = FALSE;
262 
263  for (INT i = 1; i < argc; i++)
264  {
265  INT Option = GetOptionType(argv[i]);
266 
267  switch (Option)
268  {
269  case OPTION_HELP:
270  {
271  if (bHasHelp)
272  {
273  // -? already specified
276  return FALSE;
277  }
278  bHasHelp = TRUE;
279  break;
280  }
281  case OPTION_NOHEADER:
282  {
283  if (bHasNoHeader)
284  {
285  // -nh already specified
288  return FALSE;
289  }
290  bHasNoHeader = TRUE;
291  break;
292  }
293  case OPTION_INVALID:
294  default:
295  {
298  return FALSE;
299  }
300  }
301  }
302 
303  if (bHasHelp)
304  {
305  if (argc > 2) // any arguments other than -? exists
306  {
309  return FALSE;
310  }
311  else
312  {
315  return FALSE;
316  }
317  }
318  else
319  {
320  EnumProcessAndPrint(bHasNoHeader);
321  }
322  return TRUE;
323 }
324 
325 int wmain(int argc, WCHAR **argv)
326 {
327  /* Initialize the Console Standard Streams */
329 
330  if (!ProcessArguments(argc, argv))
331  {
332  return 1;
333  }
334  return 0;
335 }
#define IDS_OUT_OF_MEMORY
Definition: resource.h:5
static int argc
Definition: ServiceArgs.c:12
const uint16_t * PCWSTR
Definition: typedefs.h:57
NTSYSAPI NTSTATUS NTAPI NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
#define COLUMNWIDTH_IMAGENAME
Definition: tasklist.h:26
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
BOOL PrintMemory(SIZE_T MemorySizeByte, UINT MaxWidth, HINSTANCE hInstance)
Definition: tasklist.c:69
BOOL ProcessArguments(INT argc, WCHAR **argv)
Definition: tasklist.c:259
#define OPTION_NOHEADER
Definition: tasklist.c:16
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define COLUMNWIDTH_SESSION
Definition: tasklist.h:28
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define IDS_MEMORY_STR
Definition: resource.h:16
#define TRUE
Definition: types.h:120
int wmain(int argc, WCHAR **argv)
Definition: tasklist.c:325
#define NT_SYSTEM_QUERY_MAX_RETRY
Definition: tasklist.h:24
LONG NTSTATUS
Definition: precomp.h:26
#define assert(x)
Definition: debug.h:53
#define IDS_USAGE
Definition: resource.h:3
uint16_t * PWCHAR
Definition: typedefs.h:56
int32_t INT_PTR
Definition: typedefs.h:64
#define argv
Definition: mplay32.c:18
#define IDS_INVALID_OPTION
Definition: resource.h:7
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
int32_t INT
Definition: typedefs.h:58
#define IDS_DESCRIPTION
Definition: resource.h:4
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: fc.c:16
#define OPTION_INVALID
Definition: tasklist.c:14
#define IDS_HEADER_PID
Definition: resource.h:12
HINSTANCE hInstance
Definition: charmap.c:20
unsigned char * LPBYTE
Definition: typedefs.h:53
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2430
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
IN PSCSI_REQUEST_BLOCK IN OUT NTSTATUS IN OUT BOOLEAN * Retry
Definition: class2.h:49
#define C_ASSERT(e)
Definition: intsafe.h:71
INT GetOptionType(LPCWSTR szOption)
Definition: tasklist.c:241
static PCWSTR OptionList[]
Definition: tasklist.c:12
Status
Definition: gdiplustypes.h:24
int64_t LONGLONG
Definition: typedefs.h:68
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:67
#define _countof(array)
Definition: sndvol32.h:68
VOID PrintSplitLine(UINT Length)
Definition: tasklist.c:22
#define IDS_INVALID_SYNTAX
Definition: resource.h:6
VOID PrintString(LPCWSTR String, UINT MaxWidth, BOOL bAlignLeft)
Definition: tasklist.c:39
UNICODE_STRING ImageName
Definition: extypes.h:894
#define IDS_OPTION_TOO_MUCH
Definition: resource.h:5
#define IDS_HEADER_SESSION
Definition: resource.h:13
static const WCHAR L[]
Definition: oid.c:1250
static CONST DWORD MemorySize[]
Definition: svga.c:32
#define RES_STR_MAXLEN
Definition: tasklist.c:19
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
struct _SYSTEM_PROCESS_INFORMATION * PSYSTEM_PROCESS_INFORMATION
ULONG_PTR SIZE_T
Definition: typedefs.h:80
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 IDS_HEADER_IMAGENAME
Definition: resource.h:11
#define IDS_ENUM_FAILED
Definition: resource.h:8
#define HeapReAlloc
Definition: compat.h:593
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
#define OPTION_HELP
Definition: tasklist.c:15
VOID PrintHeader(HINSTANCE hInstance)
Definition: tasklist.c:118
#define COLUMNWIDTH_PID
Definition: tasklist.h:27
VOID PrintSpace(UINT Length)
Definition: tasklist.c:31
#define StdOut
Definition: fc.c:14
#define ConInitStdStreams()
Definition: fc.c:13
unsigned int ULONG
Definition: retypes.h:1
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
BOOL EnumProcessAndPrint(BOOL bNoHeader)
Definition: tasklist.c:144
VOID PrintNum(LONGLONG Number, UINT MaxWidth)
Definition: tasklist.c:61
WCHAR StringBuffer[156]
Definition: ldrinit.c:41
BYTE * PBYTE
Definition: pedump.c:66
#define HeapFree(x, y, z)
Definition: compat.h:594
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
INT __cdecl ConResMsgPrintf(IN PCON_STREAM Stream, IN DWORD dwFlags, IN UINT uID,...)
Definition: outstream.c:1461
#define COLUMNWIDTH_MEMUSAGE
Definition: tasklist.h:29
#define IDS_HEADER_MEMUSAGE
Definition: resource.h:14
VOID PrintResString(HINSTANCE hInstance, UINT uID, UINT MaxWidth, BOOL bAlignLeft)
Definition: tasklist.c:48
#define StdErr
Definition: fc.c:15