Patch by Michael Fritscher <michael@fritscher.net>
[reactos.git] / rosapps / sysutils / ctm / ctm.c
1 /* Console Task Manager
2
3 ctm.c - main program file
4
5 Written by: Aleksey Bragin (aleksey@studiocerebral.com)
6
7 Most of the code dealing with getting system parameters is taken from
8 ReactOS Task Manager written by Brian Palmer (brianp@reactos.org)
9
10 Localization features added by Hervé Poussineau (hpoussin@reactos.org)
11
12 History:
13 24 October 2004 - added localization features
14 09 April 2003 - v0.1, fixed bugs, added features, ported to mingw
15 20 March 2003 - v0.03, works good under ReactOS, and allows process
16 killing
17 18 March 2003 - Initial version 0.01, doesn't work under RectOS
18
19 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
32
33
34 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows //headers
35 #define WIN32_NO_STATUS
36 #include <windows.h>
37
38 #include <stdlib.h>
39 #include <malloc.h>
40 #include <memory.h>
41 #include <tchar.h>
42 #include <process.h>
43 #include <stdio.h>
44
45 #define NTOS_MODE_USER
46 #include <ndk/ntndk.h>
47
48 #include <epsapi/epsapi.h>
49
50 #include "ctm.h"
51 #include "resource.h"
52
53 #define TIMES
54
55 HANDLE hStdin;
56 HANDLE hStdout;
57 HINSTANCE hInst;
58
59 DWORD inConMode;
60 DWORD outConMode;
61
62 DWORD columnRightPositions[5];
63 TCHAR lpSeparator[80];
64 TCHAR lpHeader[80];
65 TCHAR lpMemUnit[3];
66 TCHAR lpIdleProcess[80];
67 TCHAR lpTitle[80];
68 TCHAR lpHeader[80];
69 TCHAR lpMenu[80];
70 TCHAR lpEmpty[80];
71
72 TCHAR KEY_QUIT, KEY_KILL;
73 TCHAR KEY_YES, KEY_NO;
74
75 int ProcPerScreen = 17; // 17 processess are displayed on one page
76 int ScreenLines=25;
77 ULONG ProcessCountOld = 0;
78 ULONG ProcessCount = 0;
79
80 double dbIdleTime;
81 double dbKernelTime;
82 double dbSystemTime;
83 LARGE_INTEGER liOldIdleTime = {{0,0}};
84 LARGE_INTEGER liOldKernelTime = {{0,0}};
85 LARGE_INTEGER liOldSystemTime = {{0,0}};
86
87 PPERFDATA pPerfDataOld = NULL; // Older perf data (saved to establish delta values)
88 PPERFDATA pPerfData = NULL; // Most recent copy of perf data
89
90 int selection=0;
91 int scrolled=0; // offset from which process start showing
92 int first = 0; // first time in DisplayScreen
93 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
94
95 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
96 #define NEW_CONSOLE
97
98 // Functions that are needed by epsapi
99 void *PsaiMalloc(SIZE_T size) { return malloc(size); }
100 void *PsaiRealloc(void *ptr, SIZE_T size) { return realloc(ptr, size); }
101 void PsaiFree(void *ptr) { free(ptr); }
102
103 // Prototypes
104 unsigned int GetKeyPressed();
105
106 void GetInputOutputHandles()
107 {
108 #ifdef NEW_CONSOLE
109 HANDLE console = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
110 FILE_SHARE_READ | FILE_SHARE_WRITE,
111 0, CONSOLE_TEXTMODE_BUFFER, 0);
112
113 if (SetConsoleActiveScreenBuffer(console) == FALSE)
114 {
115 hStdin = GetStdHandle(STD_INPUT_HANDLE);
116 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
117 }
118 else
119 {
120 hStdin = GetStdHandle(STD_INPUT_HANDLE);//console;
121 hStdout = console;
122 }
123 #else
124 hStdin = GetStdHandle(STD_INPUT_HANDLE);
125 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
126 #endif
127 }
128
129 void RestoreConsole()
130 {
131 SetConsoleMode(hStdin, inConMode);
132 SetConsoleMode(hStdout, outConMode);
133
134 #ifdef NEW_CONSOLE
135 SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
136 #endif
137 }
138
139 void DisplayScreen()
140 {
141 COORD pos;
142 COORD size;
143 TCHAR lpStr[80];
144 DWORD numChars;
145 int lines;
146 int idx;
147 GetConsoleScreenBufferInfo(hStdout,&screenBufferInfo);
148 size=screenBufferInfo.dwSize;
149 ScreenLines=size.Y;
150 ProcPerScreen = ScreenLines-7;
151 if (first == 0)
152 {
153 // Header
154 pos.X = 1; pos.Y = 1;
155 WriteConsoleOutputCharacter(hStdout, lpTitle, _tcslen(lpTitle), pos, &numChars);
156
157 pos.X = 1; pos.Y = 2;
158 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
159
160 pos.X = 1; pos.Y = 3;
161 WriteConsoleOutputCharacter(hStdout, lpHeader, _tcslen(lpHeader), pos, &numChars);
162
163 pos.X = 1; pos.Y = 4;
164 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
165
166 // Footer
167 pos.X = 1; pos.Y = ScreenLines-2;
168 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
169
170 // Menu
171 pos.X = 1; pos.Y = ScreenLines-1;
172 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
173 WriteConsoleOutputCharacter(hStdout, lpMenu, _tcslen(lpMenu), pos, &numChars);
174
175 first = 1;
176 }
177
178 // Processess
179 lines = ProcessCount;
180 if (lines > ProcPerScreen)
181 lines = ProcPerScreen;
182 for (idx=0; idx<ProcPerScreen; idx++)
183 {
184 int len, i;
185 TCHAR lpNumber[5];
186 TCHAR lpPid[8];
187 TCHAR lpCpu[6];
188 TCHAR lpMemUsg[12];
189 TCHAR lpPageFaults[15];
190 WORD wColor;
191
192 for (i = 0; i < 80; i++)
193 lpStr[i] = _T(' ');
194
195 // data
196 if (idx < lines && scrolled + idx < ProcessCount)
197 {
198
199 // number
200 _stprintf(lpNumber, _T("%3d"), idx+scrolled);
201 _tcsncpy(&lpStr[2], lpNumber, 3);
202
203 // image name
204 #ifdef _UNICODE
205 len = wcslen(pPerfData[scrolled+idx].ImageName);
206 #else
207 WideCharToMultiByte(CP_ACP, 0, pPerfData[scrolled+idx].ImageName, -1,
208 imgName, MAX_PATH, NULL, NULL);
209 len = strlen(imgName);
210 #endif
211 if (len > columnRightPositions[1])
212 {
213 len = columnRightPositions[1];
214 }
215 #ifdef _UNICODE
216 wcsncpy(&lpStr[columnRightPositions[0]+3], pPerfData[scrolled+idx].ImageName, len);
217 #else
218 strncpy(&lpStr[columnRightPositions[0]+3], imgName, len);
219 #endif
220
221 // PID
222 _stprintf(lpPid, _T("%6ld"), pPerfData[scrolled+idx].ProcessId);
223 _tcsncpy(&lpStr[columnRightPositions[2] - 6], lpPid, 6);
224
225 #ifdef TIMES
226 // CPU
227 _stprintf(lpCpu, _T("%3d%%"), pPerfData[scrolled+idx].CPUUsage);
228 _tcsncpy(&lpStr[columnRightPositions[3] - 4], lpCpu, 4);
229 #endif
230
231 // Mem usage
232 _stprintf(lpMemUsg, _T("%6ld %s"), pPerfData[scrolled+idx].WorkingSetSizeBytes / 1024, lpMemUnit);
233 _tcsncpy(&lpStr[columnRightPositions[4] - 9], lpMemUsg, 9);
234
235 // Page Fault
236 _stprintf(lpPageFaults, _T("%12ld"), pPerfData[scrolled+idx].PageFaultCount);
237 _tcsncpy(&lpStr[columnRightPositions[5] - 12], lpPageFaults, 12);
238 }
239
240 // columns
241 lpStr[0] = _T(' ');
242 lpStr[1] = _T('|');
243 for (i = 0; i < 6; i++)
244 lpStr[columnRightPositions[i] + 1] = _T('|');
245 pos.X = 0; pos.Y = 5+idx;
246 WriteConsoleOutputCharacter(hStdout, lpStr, 80, pos, &numChars);
247
248 // Attributes now...
249 pos.X = columnRightPositions[0] + 1; pos.Y = 5+idx;
250 if (selection == idx)
251 {
252 wColor = BACKGROUND_GREEN |
253 FOREGROUND_RED |
254 FOREGROUND_GREEN |
255 FOREGROUND_BLUE;
256 }
257 else
258 {
259 wColor = BACKGROUND_BLUE |
260 FOREGROUND_RED |
261 FOREGROUND_GREEN |
262 FOREGROUND_BLUE;
263 }
264
265 FillConsoleOutputAttribute(
266 hStdout, // screen buffer handle
267 wColor, // color to fill with
268 columnRightPositions[1] - 4, // number of cells to fill
269 pos, // first cell to write to
270 &numChars); // actual number written
271 }
272
273 return;
274 }
275
276 // returns TRUE if exiting
277 int ProcessKeys(int numEvents)
278 {
279 DWORD numChars;
280 if ((ProcessCount-scrolled < 17) && (ProcessCount > 17))
281 scrolled = ProcessCount-17;
282
283 TCHAR key = GetKeyPressed(numEvents);
284 if (key == KEY_QUIT)
285 return TRUE;
286 else if (key == KEY_KILL)
287 {
288 // user wants to kill some process, get his acknowledgement
289 DWORD pId;
290 COORD pos;
291 TCHAR lpStr[100];
292
293 pos.X = 1; pos.Y =ScreenLines-1;
294 if (LoadString(hInst, IDS_KILL_PROCESS, lpStr, 100))
295 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
296
297 do {
298 GetNumberOfConsoleInputEvents(hStdin, &pId);
299 key = GetKeyPressed(pId);
300 } while (key != KEY_YES && key != KEY_NO);
301
302 if (key == KEY_YES)
303 {
304 HANDLE hProcess;
305 pId = pPerfData[selection+scrolled].ProcessId;
306 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pId);
307
308 if (hProcess)
309 {
310 if (!TerminateProcess(hProcess, 0))
311 {
312 if (LoadString(hInst, IDS_KILL_PROCESS_ERR1, lpStr, 80))
313 {
314 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
315 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
316 }
317 Sleep(1000);
318 }
319
320 CloseHandle(hProcess);
321 }
322 else
323 {
324 if (LoadString(hInst, IDS_KILL_PROCESS_ERR2, lpStr, 80))
325 {
326 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
327 _stprintf(lpStr, lpStr, pId);
328 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
329 }
330 Sleep(1000);
331 }
332 }
333
334 first = 0;
335 }
336 else if (key == VK_UP)
337 {
338 if (selection > 0)
339 selection--;
340 else if ((selection == 0) && (scrolled > 0))
341 scrolled--;
342 }
343 else if (key == VK_DOWN)
344 {
345 if ((selection < ProcPerScreen-1) && (selection < ProcessCount-1))
346 selection++;
347 else if ((selection == ProcPerScreen-1) && (selection+scrolled < ProcessCount-1))
348 scrolled++;
349 }
350 else if (key == VK_PRIOR)
351 {
352 if (scrolled>ProcPerScreen-1)
353 scrolled-=ProcPerScreen-1;
354 else
355 {
356 scrolled=0; //First
357 selection=0;
358 }
359 //selection=0;
360 }
361 else if (key == VK_NEXT)
362 {
363 scrolled+=ProcPerScreen-1;
364 if (scrolled>ProcessCount-ProcPerScreen)
365 {
366 scrolled=ProcessCount-ProcPerScreen; //End
367 selection=ProcPerScreen-1;
368 }
369
370 //selection=ProcPerScreen-1;
371 if (ProcessCount<=ProcPerScreen) //If there are less process than fits on the screen
372 {
373 scrolled=0;
374 selection=(ProcessCount%ProcPerScreen)-1;
375 }
376 }
377 else if (key == VK_HOME)
378 {
379 selection=0;
380 scrolled=0;
381 }
382 else if (key == VK_END)
383 {
384 selection=ProcPerScreen-1;
385 scrolled=ProcessCount-ProcPerScreen;
386 if (ProcessCount<=ProcPerScreen) //If there are less process than fits on the screen
387 {
388 scrolled=0;
389 selection=(ProcessCount%ProcPerScreen)-1;
390 }
391 }
392 return FALSE;
393 }
394
395 void PerfInit()
396 {
397 NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), 0);
398 }
399
400 void PerfDataRefresh()
401 {
402 LONG status;
403 ULONG ulSize;
404 LPBYTE pBuffer;
405 ULONG Idx, Idx2;
406 PSYSTEM_PROCESS_INFORMATION pSPI;
407 PPERFDATA pPDOld;
408 #ifdef EXTRA_INFO
409 HANDLE hProcess;
410 HANDLE hProcessToken;
411 TCHAR szTemp[MAX_PATH];
412 DWORD dwSize;
413 #endif
414 #ifdef TIMES
415 LARGE_INTEGER liCurrentKernelTime;
416 LARGE_INTEGER liCurrentIdleTime;
417 LARGE_INTEGER liCurrentTime;
418 #endif
419 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo;
420 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
421
422 #ifdef TIMES
423 // Get new system time
424 status = NtQuerySystemInformation(SystemTimeInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
425 if (status != NO_ERROR)
426 return;
427 #endif
428 // Get processor information
429 SysProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors);
430 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors, &ulSize);
431
432
433 // Get process information
434 PsaCaptureProcessesAndThreads((PSYSTEM_PROCESS_INFORMATION *)&pBuffer);
435
436 #ifdef TIMES
437 liCurrentKernelTime.QuadPart = 0;
438 liCurrentIdleTime.QuadPart = 0;
439 for (Idx=0; Idx<SystemBasicInfo.NumberOfProcessors; Idx++) {
440 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].KernelTime.QuadPart;
441 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].DpcTime.QuadPart;
442 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].InterruptTime.QuadPart;
443 liCurrentIdleTime.QuadPart += SysProcessorTimeInfo[Idx].IdleTime.QuadPart;
444 }
445
446 // If it's a first call - skip idle time calcs
447 if (liOldIdleTime.QuadPart != 0) {
448 // CurrentValue = NewValue - OldValue
449 liCurrentTime.QuadPart = liCurrentIdleTime.QuadPart - liOldIdleTime.QuadPart;
450 dbIdleTime = Li2Double(liCurrentTime);
451 liCurrentTime.QuadPart = liCurrentKernelTime.QuadPart - liOldKernelTime.QuadPart;
452 dbKernelTime = Li2Double(liCurrentTime);
453 liCurrentTime.QuadPart = SysTimeInfo.CurrentTime.QuadPart - liOldSystemTime.QuadPart;
454 dbSystemTime = Li2Double(liCurrentTime);
455
456 // CurrentCpuIdle = IdleTime / SystemTime
457 dbIdleTime = dbIdleTime / dbSystemTime;
458 dbKernelTime = dbKernelTime / dbSystemTime;
459
460 // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
461 dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5;
462 dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5;
463 }
464
465 // Store new CPU's idle and system time
466 liOldIdleTime = liCurrentIdleTime;
467 liOldSystemTime = SysTimeInfo.CurrentTime;
468 liOldKernelTime = liCurrentKernelTime;
469 #endif
470
471 // Determine the process count
472 // We loop through the data we got from PsaCaptureProcessesAndThreads
473 // and count how many structures there are (until PsaWalkNextProcess
474 // returns NULL)
475 ProcessCountOld = ProcessCount;
476 ProcessCount = 0;
477 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer);
478 while (pSPI) {
479 ProcessCount++;
480 pSPI = PsaWalkNextProcess(pSPI);
481 }
482
483 // Now alloc a new PERFDATA array and fill in the data
484 if (pPerfDataOld) {
485 free(pPerfDataOld);
486 }
487 pPerfDataOld = pPerfData;
488 pPerfData = (PPERFDATA)malloc(sizeof(PERFDATA) * ProcessCount);
489 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer);
490 for (Idx=0; Idx<ProcessCount; Idx++) {
491 // Get the old perf data for this process (if any)
492 // so that we can establish delta values
493 pPDOld = NULL;
494 for (Idx2=0; Idx2<ProcessCountOld; Idx2++) {
495 if (pPerfDataOld[Idx2].ProcessId == (ULONG)(pSPI->UniqueProcessId) &&
496 /* check also for the creation time, a new process may have an id of an old one */
497 pPerfDataOld[Idx2].CreateTime.QuadPart == pSPI->CreateTime.QuadPart) {
498 pPDOld = &pPerfDataOld[Idx2];
499 break;
500 }
501 }
502
503 // Clear out process perf data structure
504 memset(&pPerfData[Idx], 0, sizeof(PERFDATA));
505
506 if (pSPI->ImageName.Buffer) {
507 wcsncpy(pPerfData[Idx].ImageName, pSPI->ImageName.Buffer, pSPI->ImageName.Length / sizeof(WCHAR));
508 pPerfData[Idx].ImageName[pSPI->ImageName.Length / sizeof(WCHAR)] = 0;
509 }
510 else
511 {
512 #ifdef _UNICODE
513 wcscpy(pPerfData[Idx].ImageName, lpIdleProcess);
514 #else
515 MultiByteToWideChar(CP_ACP, 0, lpIdleProcess, strlen(lpIdleProcess), pPerfData[Idx].ImageName, MAX_PATH);
516 #endif
517 }
518
519 pPerfData[Idx].ProcessId = (ULONG)(pSPI->UniqueProcessId);
520 pPerfData[Idx].CreateTime = pSPI->CreateTime;
521
522 if (pPDOld) {
523 #ifdef TIMES
524 double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime);
525 double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime);
526 double CpuTime = (CurTime - OldTime) / dbSystemTime;
527 CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; // + 0.5;
528
529 pPerfData[Idx].CPUUsage = (ULONG)CpuTime;
530 #else
531 pPerfData[Idx].CPUUsage = 0;
532 #endif
533 }
534
535 pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart;
536 pPerfData[Idx].WorkingSetSizeBytes = pSPI->WorkingSetSize;
537 pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSize;
538 if (pPDOld)
539 pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->WorkingSetSize - (LONG)pPDOld->WorkingSetSizeBytes);
540 else
541 pPerfData[Idx].WorkingSetSizeDelta = 0;
542 pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount;
543 if (pPDOld)
544 pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount);
545 else
546 pPerfData[Idx].PageFaultCountDelta = 0;
547 pPerfData[Idx].VirtualMemorySizeBytes = pSPI->VirtualSize;
548 pPerfData[Idx].PagedPoolUsagePages = pSPI->QuotaPagedPoolUsage;
549 pPerfData[Idx].NonPagedPoolUsagePages = pSPI->QuotaNonPagedPoolUsage;
550 pPerfData[Idx].BasePriority = pSPI->BasePriority;
551 pPerfData[Idx].HandleCount = pSPI->HandleCount;
552 pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads;
553 //pPerfData[Idx].SessionId = pSPI->SessionId;
554
555 #ifdef EXTRA_INFO
556 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pSPI->UniqueProcessId);
557 if (hProcess) {
558 if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) {
559 ImpersonateLoggedOnUser(hProcessToken);
560 memset(szTemp, 0, sizeof(TCHAR[MAX_PATH]));
561 dwSize = MAX_PATH;
562 GetUserName(szTemp, &dwSize);
563 #ifndef UNICODE
564 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTemp, -1, pPerfData[Idx].UserName, MAX_PATH);
565 #endif
566 RevertToSelf();
567 CloseHandle(hProcessToken);
568 }
569 CloseHandle(hProcess);
570 }
571 #endif
572 #ifdef TIMES
573 pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart;
574 pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart;
575 #endif
576 pSPI = PsaWalkNextProcess(pSPI);
577 }
578 PsaFreeCapture(pBuffer);
579
580 free(SysProcessorTimeInfo);
581 }
582
583 // Code partly taken from slw32tty.c from mc/slang
584 unsigned int GetKeyPressed(int events)
585 {
586 DWORD bytesRead;
587 INPUT_RECORD record;
588 int i;
589
590
591 for (i=0; i<events; i++)
592 {
593 if (!ReadConsoleInput(hStdin, &record, 1, &bytesRead)) {
594 return 0;
595 }
596
597 if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
598 return record.Event.KeyEvent.wVirtualKeyCode;//.uChar.AsciiChar;
599 }
600
601 return 0;
602 }
603
604
605 int main(int argc, char **argv)
606 {
607 int i;
608 TCHAR lpStr[80];
609
610 for (i = 0; i < 80; i++)
611 lpEmpty[i] = lpHeader[i] = _T(' ');
612 lpEmpty[79] = _T('\0');
613
614 /* Initialize global variables */
615 hInst = 0 /* FIXME: which value? [used with LoadString(hInst, ..., ..., ...)] */;
616
617 if (LoadString(hInst, IDS_COLUMN_NUMBER, lpStr, 80))
618 {
619 columnRightPositions[0] = _tcslen(lpStr) + 3;
620 _tcsncpy(&lpHeader[2], lpStr, _tcslen(lpStr));
621 }
622 if (LoadString(hInst, IDS_COLUMN_IMAGENAME, lpStr, 80))
623 {
624 columnRightPositions[1] = columnRightPositions[0] + _tcslen(lpStr) + 3;
625 _tcsncpy(&lpHeader[columnRightPositions[0] + 2], lpStr, _tcslen(lpStr));
626 }
627 if (LoadString(hInst, IDS_COLUMN_PID, lpStr, 80))
628 {
629 columnRightPositions[2] = columnRightPositions[1] + _tcslen(lpStr) + 3;
630 _tcsncpy(&lpHeader[columnRightPositions[1] + 2], lpStr, _tcslen(lpStr));
631 }
632 if (LoadString(hInst, IDS_COLUMN_CPU, lpStr, 80))
633 {
634 columnRightPositions[3] = columnRightPositions[2] + _tcslen(lpStr) + 3;
635 _tcsncpy(&lpHeader[columnRightPositions[2] + 2], lpStr, _tcslen(lpStr));
636 }
637 if (LoadString(hInst, IDS_COLUMN_MEM, lpStr, 80))
638 {
639 columnRightPositions[4] = columnRightPositions[3] + _tcslen(lpStr) + 3;
640 _tcsncpy(&lpHeader[columnRightPositions[3] + 2], lpStr, _tcslen(lpStr));
641 }
642 if (LoadString(hInst, IDS_COLUMN_PF, lpStr, 80))
643 {
644 columnRightPositions[5] = columnRightPositions[4] + _tcslen(lpStr) + 3;
645 _tcsncpy(&lpHeader[columnRightPositions[4] + 2], lpStr, _tcslen(lpStr));
646 }
647
648 for (i = 0; i < columnRightPositions[5]; i++)
649 lpSeparator[i] = _T('-');
650 lpHeader[0] = _T('|');
651 lpSeparator[0] = _T('+');
652 for (i = 0; i < 6; i++)
653 {
654 lpHeader[columnRightPositions[i]] = _T('|');
655 lpSeparator[columnRightPositions[i]] = _T('+');
656 }
657 lpSeparator[columnRightPositions[5] + 1] = _T('\0');
658 lpHeader[columnRightPositions[5] + 1] = _T('\0');
659
660
661 if (!LoadString(hInst, IDS_APP_TITLE, lpTitle, 80))
662 lpTitle[0] = _T('\0');
663 if (!LoadString(hInst, IDS_COLUMN_MEM_UNIT, lpMemUnit, 3))
664 lpMemUnit[0] = _T('\0');
665 if (!LoadString(hInst, IDS_MENU, lpMenu, 80))
666 lpMenu[0] = _T('\0');
667 if (!LoadString(hInst, IDS_IDLE_PROCESS, lpIdleProcess, 80))
668 lpIdleProcess[0] = _T('\0');
669
670 if (LoadString(hInst, IDS_MENU_QUIT, lpStr, 2))
671 KEY_QUIT = lpStr[0];
672 if (LoadString(hInst, IDS_MENU_KILL_PROCESS, lpStr, 2))
673 KEY_KILL = lpStr[0];
674 if (LoadString(hInst, IDS_YES, lpStr, 2))
675 KEY_YES = lpStr[0];
676 if (LoadString(hInst, IDS_NO, lpStr, 2))
677 KEY_NO = lpStr[0];
678
679 GetInputOutputHandles();
680
681 if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE)
682 {
683 if (LoadString(hInst, IDS_CTM_GENERAL_ERR1, lpStr, 80))
684 _tprintf(lpStr);
685 return -1;
686 }
687
688 if (GetConsoleMode(hStdin, &inConMode) == 0)
689 {
690 if (LoadString(hInst, IDS_CTM_GENERAL_ERR2, lpStr, 80))
691 _tprintf(lpStr);
692 return -1;
693 }
694
695 if (GetConsoleMode(hStdout, &outConMode) == 0)
696 {
697 if (LoadString(hInst, IDS_CTM_GENERAL_ERR3, lpStr, 80))
698 _tprintf(lpStr);
699 return -1;
700 }
701
702 SetConsoleMode(hStdin, 0); //FIXME: Should check for error!
703 SetConsoleMode(hStdout, 0); //FIXME: Should check for error!
704
705 PerfInit();
706
707 while (1)
708 {
709 DWORD numEvents;
710
711 PerfDataRefresh();
712 DisplayScreen();
713
714 /* WaitForSingleObject for console handles is not implemented in ROS */
715 WaitForSingleObject(hStdin, 1000);
716 GetNumberOfConsoleInputEvents(hStdin, &numEvents);
717
718 if (numEvents > 0)
719 {
720 if (ProcessKeys(numEvents) == TRUE)
721 break;
722 }
723 }
724
725 RestoreConsole();
726 return 0;
727 }