1 /* Console Task Manager
3 ctm.c - main program file
5 Written by: Aleksey Bragin (aleksey@studiocerebral.com)
7 Most of the code dealing with getting system parameters is taken from
8 ReactOS Task Manager written by Brian Palmer (brianp@reactos.org)
11 09 April 2003 - v0.1, fixed bugs, added features, ported to mingw
12 20 March 2003 - v0.03, works good under ReactOS, and allows process
14 18 March 2003 - Initial version 0.01, doesn't work under RectOS
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
31 //#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows //headers
40 #include <ddk/ntddk.h>
42 #include <ntos/zwtypes.h>
55 //PROCNTQSI NtQuerySystemInformation= NULL;
57 const int ProcPerScreen
= 17; // 17 processess are displayed on one page
58 ULONG ProcessCountOld
= 0;
59 ULONG ProcessCount
= 0;
64 LARGE_INTEGER liOldIdleTime
= {{0,0}};
65 double OldKernelTime
= 0;
66 LARGE_INTEGER liOldSystemTime
= {{0,0}};
68 PPERFDATA pPerfDataOld
= NULL
; // Older perf data (saved to establish delta values)
69 PPERFDATA pPerfData
= NULL
; // Most recent copy of perf data
72 int scrolled
=0; // offset from which process start showing
76 void *PsaiMalloc(SIZE_T size
) { return malloc(size
); }
77 void *PsaiRealloc(void *ptr
, SIZE_T size
) { return realloc(ptr
, size
); }
78 void PsaiFree(void *ptr
) { free(ptr
); }
81 unsigned int GetKeyPressed();
83 void GetInputOutputHandles()
86 HANDLE console
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
87 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
88 0, CONSOLE_TEXTMODE_BUFFER
, 0);
90 if (SetConsoleActiveScreenBuffer(console
) == FALSE
)
92 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);
93 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
97 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);//console;
101 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);
102 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
106 void RestoreConsole()
108 SetConsoleMode(hStdin
, inConMode
);
109 SetConsoleMode(hStdout
, outConMode
);
112 SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE
));
125 pos
.X
= 2; pos
.Y
= 2;
126 strcpy(lpStr
, "Console TaskManager v0.1 by Aleksey Bragin <aleksey@studiocerebral.com>");
127 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
129 pos
.X
= 2; pos
.Y
= 3;
130 strcpy(lpStr
, "+-------------------------------+-------+-----+-----------+-------------+");
131 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
133 pos
.X
= 2; pos
.Y
= 4;
134 strcpy(lpStr
, "| Image name | PID | CPU | Mem Usage | Page Faults |");
135 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
137 pos
.X
= 2; pos
.Y
= 5;
138 strcpy(lpStr
, "+-------------------------------+-------+-----+-----------+-------------+");
139 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
142 pos
.X
= 2; pos
.Y
= 23;
143 strcpy(lpStr
, "+-------------------------------+-------+-----+-----------+-------------+");
144 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
147 pos
.X
= 2; pos
.Y
= 24;
148 strcpy(lpStr
, "Press: q - quit, k - kill process ");
149 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &numChars
);
152 lines
= ProcessCount
;
153 if (lines
> MAX_PROC
)
155 for (idx
=0; idx
<lines
; idx
++)
158 char imgName
[MAX_PATH
];
162 char lpPageFaults
[15];
167 pos
.X
= 3; pos
.Y
= 6+idx
;
168 memset(imgName
, 0, MAX_PATH
);
169 WideCharToMultiByte(CP_ACP
, 0, pPerfData
[scrolled
+idx
].ImageName
, -1,
170 imgName
, MAX_PATH
, NULL
, NULL
);
171 len
= strlen(imgName
);
172 WriteConsoleOutputCharacter(hStdout
, " ", 30, pos
, &numChars
);
173 WriteConsoleOutputCharacter(hStdout
, imgName
, (len
> 30) ? 30 : len
, pos
, &numChars
);
176 pos
.X
= 35; pos
.Y
= 6+idx
;
177 sprintf(lpPid
, "%6ld", pPerfData
[scrolled
+idx
].ProcessId
);
178 WriteConsoleOutputCharacter(hStdout
, lpPid
, strlen(lpPid
), pos
, &numChars
);
181 pos
.X
= 43; pos
.Y
= 6+idx
;
182 sprintf(lpCpu
, "%3d%%", pPerfData
[scrolled
+idx
].CPUUsage
);
183 WriteConsoleOutputCharacter(hStdout
, lpCpu
, strlen(lpCpu
), pos
, &numChars
);
186 pos
.X
= 49; pos
.Y
= 6+idx
;
187 sprintf(lpMemUsg
, "%6ld", pPerfData
[scrolled
+idx
].WorkingSetSizeBytes
/ 1024);
188 WriteConsoleOutputCharacter(hStdout
, lpMemUsg
, strlen(lpMemUsg
), pos
, &numChars
);
191 pos
.X
= 61; pos
.Y
= 6+idx
;
192 sprintf(lpPageFaults
, "%12ld", pPerfData
[scrolled
+idx
].PageFaultCount
);
193 WriteConsoleOutputCharacter(hStdout
, lpPageFaults
, strlen(lpPageFaults
), pos
, &numChars
);
196 pos
.X
= 2; pos
.Y
= 6+idx
;
197 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
198 pos
.X
= 34; pos
.Y
= 6+idx
;
199 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
200 pos
.X
= 42; pos
.Y
= 6+idx
;
201 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
202 pos
.X
= 48; pos
.Y
= 6+idx
;
203 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
204 pos
.X
= 60; pos
.Y
= 6+idx
;
205 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
206 pos
.X
= 74; pos
.Y
= 6+idx
;
207 WriteConsoleOutputCharacter(hStdout
, "|", 1, pos
, &numChars
);
211 pos
.X
= 3; pos
.Y
= 6+idx
;
212 if (selection
== idx
)
214 wColor
= BACKGROUND_GREEN
|
221 wColor
= BACKGROUND_BLUE
|
227 FillConsoleOutputAttribute(
228 hStdout
, // screen buffer handle
229 wColor
, // color to fill with
230 31, // number of cells to fill
231 pos
, // first cell to write to
232 &numChars
); // actual number written
238 // returns TRUE if exiting
239 int ProcessKeys(int numEvents
)
241 if ((ProcessCount
-scrolled
< 17) && (ProcessCount
> 17))
242 scrolled
= ProcessCount
-17;
244 unsigned char key
= GetKeyPressed(numEvents
);
247 else if (key
== VK_K
)
249 // user wants to kill some process, get his acknowledgement
254 pos
.X
= 2; pos
.Y
= 24;
255 strcpy(lpStr
, "Are you sure you want to kill this process? (y/n)");
256 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &pId
);
259 GetNumberOfConsoleInputEvents(hStdin
, &pId
);
260 key
= GetKeyPressed(pId
);
266 pId
= pPerfData
[selection
+scrolled
].ProcessId
;
267 hProcess
= OpenProcess(PROCESS_TERMINATE
, FALSE
, pId
);
271 if (!TerminateProcess(hProcess
, 0))
273 strcpy(lpStr
, "Unable to terminate this process... ");
274 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &pId
);
278 CloseHandle(hProcess
);
282 sprintf(lpStr
, "Unable to terminate process %3d (unable to OpenProcess) ", pId
);
283 WriteConsoleOutputCharacter(hStdout
, lpStr
, strlen(lpStr
), pos
, &pId
);
288 else if (key
== VK_UP
)
292 else if ((selection
== 0) && (scrolled
> 0))
295 else if (key
== VK_DOWN
)
297 if ((selection
< MAX_PROC
-1) && (selection
< ProcessCount
-1))
299 else if ((selection
== MAX_PROC
-1) && (selection
+scrolled
< ProcessCount
-1))
308 // NtQuerySystemInformation = //(PROCNTQSI)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), //"NtQuerySystemInformation");
311 void PerfDataRefresh()
319 HANDLE hProcessToken
;
320 PSYSTEM_PROCESSES pSPI
;
322 TCHAR szTemp
[MAX_PATH
];
324 double CurrentKernelTime
;
325 PSYSTEM_PROCESSORTIME_INFO SysProcessorTimeInfo
;
326 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo
;
327 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo
;
330 // Get new system time
331 status
= NtQuerySystemInformation(SystemTimeInformation
, &SysTimeInfo
, sizeof(SysTimeInfo
), 0);
332 if (status
!= NO_ERROR
)
335 // Get new CPU's idle time
336 status
= NtQuerySystemInformation(SystemPerformanceInformation
, &SysPerfInfo
, sizeof(SysPerfInfo
), NULL
);
337 if (status
!= NO_ERROR
)
340 // Get processor information
341 SysProcessorTimeInfo
= (PSYSTEM_PROCESSORTIME_INFO
)malloc(sizeof(SYSTEM_PROCESSORTIME_INFO
) * 1/*SystemBasicInfo.bKeNumberProcessors*/);
342 status
= NtQuerySystemInformation(SystemProcessorTimes
, SysProcessorTimeInfo
, sizeof(SYSTEM_PROCESSORTIME_INFO
) * 1/*SystemBasicInfo.bKeNumberProcessors*/, &ulSize
);
345 // Get process information
346 PsaCaptureProcessesAndThreads((PSYSTEM_PROCESSES
*)&pBuffer
);
349 for (CurrentKernelTime
=0, Idx
=0; Idx
<1/*SystemBasicInfo.bKeNumberProcessors*/; Idx
++) {
350 CurrentKernelTime
+= Li2Double(SysProcessorTimeInfo
[Idx
].KernelTime
);
351 CurrentKernelTime
+= Li2Double(SysProcessorTimeInfo
[Idx
].DpcTime
);
352 CurrentKernelTime
+= Li2Double(SysProcessorTimeInfo
[Idx
].InterruptTime
);
355 // If it's a first call - skip idle time calcs
356 if (liOldIdleTime
.QuadPart
!= 0) {
357 // CurrentValue = NewValue - OldValue
358 dbIdleTime
= Li2Double(SysPerfInfo
.liIdleTime
) - Li2Double(liOldIdleTime
);
359 dbKernelTime
= CurrentKernelTime
- OldKernelTime
;
360 dbSystemTime
= Li2Double(SysTimeInfo
.CurrentTime
) - Li2Double(liOldSystemTime
);
362 // CurrentCpuIdle = IdleTime / SystemTime
363 dbIdleTime
= dbIdleTime
/ dbSystemTime
;
364 dbKernelTime
= dbKernelTime
/ dbSystemTime
;
366 // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
367 dbIdleTime
= 100.0 - dbIdleTime
* 100.0; /* / (double)SystemBasicInfo.bKeNumberProcessors;// + 0.5; */
368 dbKernelTime
= 100.0 - dbKernelTime
* 100.0; /* / (double)SystemBasicInfo.bKeNumberProcessors;// + 0.5; */
371 // Store new CPU's idle and system time
372 liOldIdleTime
= SysPerfInfo
.liIdleTime
;
373 liOldSystemTime
= SysTimeInfo
.CurrentTime
;
374 OldKernelTime
= CurrentKernelTime
;
377 // Determine the process count
378 // We loop through the data we got from PsaCaptureProcessesAndThreads
379 // and count how many structures there are (until PsaWalkNextProcess
381 ProcessCountOld
= ProcessCount
;
383 pSPI
= PsaWalkFirstProcess((PSYSTEM_PROCESSES
)pBuffer
);
386 pSPI
= PsaWalkNextProcess(pSPI
);
389 // Now alloc a new PERFDATA array and fill in the data
391 //delete[] pPerfDataOld;
394 pPerfDataOld
= pPerfData
;
395 //pPerfData = new PERFDATA[ProcessCount];
396 pPerfData
= (PPERFDATA
)malloc(sizeof(PERFDATA
) * ProcessCount
);
397 pSPI
= PsaWalkFirstProcess((PSYSTEM_PROCESSES
)pBuffer
);
398 for (Idx
=0; Idx
<ProcessCount
; Idx
++) {
399 // Get the old perf data for this process (if any)
400 // so that we can establish delta values
402 for (Idx2
=0; Idx2
<ProcessCountOld
; Idx2
++) {
403 if (pPerfDataOld
[Idx2
].ProcessId
== pSPI
->ProcessId
) {
404 pPDOld
= &pPerfDataOld
[Idx2
];
409 // Clear out process perf data structure
410 memset(&pPerfData
[Idx
], 0, sizeof(PERFDATA
));
412 if (pSPI
->ProcessName
.Buffer
)
413 wcsncpy(pPerfData
[Idx
].ImageName
, pSPI
->ProcessName
.Buffer
, pSPI
->ProcessName
.MaximumLength
);
415 wcscpy(pPerfData
[Idx
].ImageName
, L
"System Idle Process");
417 pPerfData
[Idx
].ProcessId
= pSPI
->ProcessId
;
421 double CurTime
= Li2Double(pSPI
->KernelTime
) + Li2Double(pSPI
->UserTime
);
422 double OldTime
= Li2Double(pPDOld
->KernelTime
) + Li2Double(pPDOld
->UserTime
);
423 double CpuTime
= (CurTime
- OldTime
) / dbSystemTime
;
424 CpuTime
= CpuTime
* 100.0; /* / (double)SystemBasicInfo.bKeNumberProcessors;// + 0.5;*/
426 pPerfData
[Idx
].CPUUsage
= (ULONG
)CpuTime
;
428 pPerfData
[Idx
].CPUUsage
= 0;
432 pPerfData
[Idx
].CPUTime
.QuadPart
= pSPI
->UserTime
.QuadPart
+ pSPI
->KernelTime
.QuadPart
;
433 pPerfData
[Idx
].WorkingSetSizeBytes
= pSPI
->VmCounters
.WorkingSetSize
;
434 pPerfData
[Idx
].PeakWorkingSetSizeBytes
= pSPI
->VmCounters
.PeakWorkingSetSize
;
436 pPerfData
[Idx
].WorkingSetSizeDelta
= labs((LONG
)pSPI
->VmCounters
.WorkingSetSize
- (LONG
)pPDOld
->WorkingSetSizeBytes
);
438 pPerfData
[Idx
].WorkingSetSizeDelta
= 0;
439 pPerfData
[Idx
].PageFaultCount
= pSPI
->VmCounters
.PageFaultCount
;
441 pPerfData
[Idx
].PageFaultCountDelta
= labs((LONG
)pSPI
->VmCounters
.PageFaultCount
- (LONG
)pPDOld
->PageFaultCount
);
443 pPerfData
[Idx
].PageFaultCountDelta
= 0;
444 pPerfData
[Idx
].VirtualMemorySizeBytes
= pSPI
->VmCounters
.VirtualSize
;
445 pPerfData
[Idx
].PagedPoolUsagePages
= pSPI
->VmCounters
.QuotaPagedPoolUsage
;
446 pPerfData
[Idx
].NonPagedPoolUsagePages
= pSPI
->VmCounters
.QuotaNonPagedPoolUsage
;
447 pPerfData
[Idx
].BasePriority
= pSPI
->BasePriority
;
448 pPerfData
[Idx
].HandleCount
= pSPI
->HandleCount
;
449 pPerfData
[Idx
].ThreadCount
= pSPI
->ThreadCount
;
450 //pPerfData[Idx].SessionId = pSPI->SessionId;
453 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, pSPI
->ProcessId
);
455 if (OpenProcessToken(hProcess
, TOKEN_QUERY
|TOKEN_DUPLICATE
|TOKEN_IMPERSONATE
, &hProcessToken
)) {
456 ImpersonateLoggedOnUser(hProcessToken
);
457 memset(szTemp
, 0, sizeof(TCHAR
[MAX_PATH
]));
459 GetUserName(szTemp
, &dwSize
);
461 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, szTemp
, -1, pPerfData
[Idx
].UserName
, MAX_PATH
);
463 int MultiByteToWideChar(
464 UINT CodePage, // code page
465 DWORD dwFlags, // character-type options
466 LPCSTR lpMultiByteStr, // string to map
467 int cbMultiByte, // number of bytes in string
468 LPWSTR lpWideCharStr, // wide-character buffer
469 int cchWideChar // size of buffer
474 CloseHandle(hProcessToken
);
476 CloseHandle(hProcess
);
480 pPerfData
[Idx
].UserTime
.QuadPart
= pSPI
->UserTime
.QuadPart
;
481 pPerfData
[Idx
].KernelTime
.QuadPart
= pSPI
->KernelTime
.QuadPart
;
483 pSPI
= PsaWalkNextProcess(pSPI
);
486 PsaFreeCapture(pBuffer
);
488 free(SysProcessorTimeInfo
);
491 // Code partly taken from slw32tty.c from mc/slang
492 unsigned int GetKeyPressed(int events
)
500 for (i
=0; i
<events
; i
++)
502 if (!ReadConsoleInput(hStdin
, &record
, 1, &bytesRead
)) {
506 if (record
.EventType
== KEY_EVENT
&& record
.Event
.KeyEvent
.bKeyDown
)
507 return record
.Event
.KeyEvent
.wVirtualKeyCode
;//.uChar.AsciiChar;
514 int main(int *argc
, char **argv
)
516 GetInputOutputHandles();
518 if (hStdin
== INVALID_HANDLE_VALUE
|| hStdout
== INVALID_HANDLE_VALUE
)
520 printf("ctm: can't use console.");
524 if (GetConsoleMode(hStdin
, &inConMode
) == 0)
526 printf("ctm: can't GetConsoleMode() for input console.");
530 if (GetConsoleMode(hStdout
, &outConMode
) == 0)
532 printf("ctm: can't GetConsoleMode() for output console.");
536 SetConsoleMode(hStdin
, 0); //FIXME: Should check for error!
537 SetConsoleMode(hStdout
, 0); //FIXME: Should check for error!
548 //WriteConsole(hStdin, " ", 1, &numEvents, NULL); // TODO: Make another way (this is ugly, I know)
549 GetNumberOfConsoleInputEvents(hStdin
, &numEvents
);
553 if (ProcessKeys(numEvents
) == TRUE
)
557 Sleep(40); // TODO: Should be done more efficient (might be another thread handling input/etc)*/