disable defining ntstatus codes in windows.h/winnt.h when using ndk
[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 MAX_PROC 17
54 #define TIMES
55
56 HANDLE hStdin;
57 HANDLE hStdout;
58 HINSTANCE hInst;
59
60 DWORD inConMode;
61 DWORD outConMode;
62
63 DWORD columnRightPositions[5];
64 TCHAR lpSeparator[80];
65 TCHAR lpHeader[80];
66 TCHAR lpMemUnit[3];
67 TCHAR lpIdleProcess[80];
68 TCHAR lpTitle[80];
69 TCHAR lpHeader[80];
70 TCHAR lpMenu[80];
71 TCHAR lpEmpty[80];
72
73 TCHAR KEY_QUIT, KEY_KILL;
74 TCHAR KEY_YES, KEY_NO;
75
76 const int ProcPerScreen = 17; // 17 processess are displayed on one page
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 #define NEW_CONSOLE
96
97 // Functions that are needed by epsapi
98 void *PsaiMalloc(SIZE_T size) { return malloc(size); }
99 void *PsaiRealloc(void *ptr, SIZE_T size) { return realloc(ptr, size); }
100 void PsaiFree(void *ptr) { free(ptr); }
101
102 // Prototypes
103 unsigned int GetKeyPressed();
104
105 void GetInputOutputHandles()
106 {
107 #ifdef NEW_CONSOLE
108 HANDLE console = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
109 FILE_SHARE_READ | FILE_SHARE_WRITE,
110 0, CONSOLE_TEXTMODE_BUFFER, 0);
111
112 if (SetConsoleActiveScreenBuffer(console) == FALSE)
113 {
114 hStdin = GetStdHandle(STD_INPUT_HANDLE);
115 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
116 }
117 else
118 {
119 hStdin = GetStdHandle(STD_INPUT_HANDLE);//console;
120 hStdout = console;
121 }
122 #else
123 hStdin = GetStdHandle(STD_INPUT_HANDLE);
124 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
125 #endif
126 }
127
128 void RestoreConsole()
129 {
130 SetConsoleMode(hStdin, inConMode);
131 SetConsoleMode(hStdout, outConMode);
132
133 #ifdef NEW_CONSOLE
134 SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
135 #endif
136 }
137
138 void DisplayScreen()
139 {
140 COORD pos;
141 TCHAR lpStr[80];
142 DWORD numChars;
143 int lines;
144 int idx;
145
146 if (first == 0)
147 {
148 // Header
149 pos.X = 2; pos.Y = 2;
150 WriteConsoleOutputCharacter(hStdout, lpTitle, _tcslen(lpTitle), pos, &numChars);
151
152 pos.X = 2; pos.Y = 3;
153 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
154
155 pos.X = 2; pos.Y = 4;
156 WriteConsoleOutputCharacter(hStdout, lpHeader, _tcslen(lpHeader), pos, &numChars);
157
158 pos.X = 2; pos.Y = 5;
159 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
160
161 // Footer
162 pos.X = 2; pos.Y = ProcPerScreen+6;
163 WriteConsoleOutputCharacter(hStdout, lpSeparator, _tcslen(lpSeparator), pos, &numChars);
164
165 // Menu
166 pos.X = 2; pos.Y = ProcPerScreen+7;
167 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
168 WriteConsoleOutputCharacter(hStdout, lpMenu, _tcslen(lpMenu), pos, &numChars);
169
170 first = 1;
171 }
172
173 // Processess
174 lines = ProcessCount;
175 if (lines > MAX_PROC)
176 lines = MAX_PROC;
177 for (idx=0; idx<MAX_PROC; idx++)
178 {
179 int len, i;
180 TCHAR lpPid[8];
181 TCHAR lpCpu[6];
182 TCHAR lpMemUsg[12];
183 TCHAR lpPageFaults[15];
184 WORD wColor;
185
186 for (i = 0; i < 80; i++)
187 lpStr[i] = _T(' ');
188
189 // data
190 if (idx < lines && scrolled + idx < ProcessCount)
191 {
192 // image name
193 #ifdef _UNICODE
194 len = wcslen(pPerfData[scrolled+idx].ImageName);
195 #else
196 WideCharToMultiByte(CP_ACP, 0, pPerfData[scrolled+idx].ImageName, -1,
197 imgName, MAX_PATH, NULL, NULL);
198 len = strlen(imgName);
199 #endif
200 if (len > columnRightPositions[0])
201 {
202 len = columnRightPositions[0];
203 }
204 #ifdef _UNICODE
205 wcsncpy(&lpStr[2], pPerfData[scrolled+idx].ImageName, len);
206 #else
207 strncpy(&lpStr[2], imgName, len);
208 #endif
209
210 // PID
211 _stprintf(lpPid, _T("%6ld"), pPerfData[scrolled+idx].ProcessId);
212 _tcsncpy(&lpStr[columnRightPositions[1] - 6], lpPid, 6);
213
214 #ifdef TIMES
215 // CPU
216 _stprintf(lpCpu, _T("%3d%%"), pPerfData[scrolled+idx].CPUUsage);
217 _tcsncpy(&lpStr[columnRightPositions[2] - 4], lpCpu, 4);
218 #endif
219
220 // Mem usage
221 _stprintf(lpMemUsg, _T("%6ld %s"), pPerfData[scrolled+idx].WorkingSetSizeBytes / 1024, lpMemUnit);
222 _tcsncpy(&lpStr[columnRightPositions[3] - 9], lpMemUsg, 9);
223
224 // Page Fault
225 _stprintf(lpPageFaults, _T("%12ld"), pPerfData[scrolled+idx].PageFaultCount);
226 _tcsncpy(&lpStr[columnRightPositions[4] - 12], lpPageFaults, 12);
227 }
228
229 // columns
230 lpStr[0] = _T(' ');
231 lpStr[1] = _T('|');
232 for (i = 0; i < 5; i++)
233 lpStr[columnRightPositions[i] + 1] = _T('|');
234 pos.X = 1; pos.Y = 6+idx;
235 WriteConsoleOutputCharacter(hStdout, lpStr, 74, pos, &numChars);
236
237 // Attributes now...
238 pos.X = 3; pos.Y = 6+idx;
239 if (selection == idx)
240 {
241 wColor = BACKGROUND_GREEN |
242 FOREGROUND_RED |
243 FOREGROUND_GREEN |
244 FOREGROUND_BLUE;
245 }
246 else
247 {
248 wColor = BACKGROUND_BLUE |
249 FOREGROUND_RED |
250 FOREGROUND_GREEN |
251 FOREGROUND_BLUE;
252 }
253
254 FillConsoleOutputAttribute(
255 hStdout, // screen buffer handle
256 wColor, // color to fill with
257 columnRightPositions[0] - 1, // number of cells to fill
258 pos, // first cell to write to
259 &numChars); // actual number written
260 }
261
262 return;
263 }
264
265 // returns TRUE if exiting
266 int ProcessKeys(int numEvents)
267 {
268 DWORD numChars;
269 if ((ProcessCount-scrolled < 17) && (ProcessCount > 17))
270 scrolled = ProcessCount-17;
271
272 TCHAR key = GetKeyPressed(numEvents);
273 if (key == KEY_QUIT)
274 return TRUE;
275 else if (key == KEY_KILL)
276 {
277 // user wants to kill some process, get his acknowledgement
278 DWORD pId;
279 COORD pos;
280 TCHAR lpStr[100];
281
282 pos.X = 2; pos.Y = 24;
283 if (LoadString(hInst, IDS_KILL_PROCESS, lpStr, 100))
284 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
285
286 do {
287 GetNumberOfConsoleInputEvents(hStdin, &pId);
288 key = GetKeyPressed(pId);
289 } while (key != KEY_YES && key != KEY_NO);
290
291 if (key == KEY_YES)
292 {
293 HANDLE hProcess;
294 pId = pPerfData[selection+scrolled].ProcessId;
295 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pId);
296
297 if (hProcess)
298 {
299 if (!TerminateProcess(hProcess, 0))
300 {
301 if (LoadString(hInst, IDS_KILL_PROCESS_ERR1, lpStr, 80))
302 {
303 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
304 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
305 }
306 Sleep(1000);
307 }
308
309 CloseHandle(hProcess);
310 }
311 else
312 {
313 if (LoadString(hInst, IDS_KILL_PROCESS_ERR2, lpStr, 80))
314 {
315 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars);
316 _stprintf(lpStr, lpStr, pId);
317 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars);
318 }
319 Sleep(1000);
320 }
321 }
322
323 first = 0;
324 }
325 else if (key == VK_UP)
326 {
327 if (selection > 0)
328 selection--;
329 else if ((selection == 0) && (scrolled > 0))
330 scrolled--;
331 }
332 else if (key == VK_DOWN)
333 {
334 if ((selection < MAX_PROC-1) && (selection < ProcessCount-1))
335 selection++;
336 else if ((selection == MAX_PROC-1) && (selection+scrolled < ProcessCount-1))
337 scrolled++;
338 }
339
340 return FALSE;
341 }
342
343 void PerfInit()
344 {
345 NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), 0);
346 }
347
348 void PerfDataRefresh()
349 {
350 LONG status;
351 ULONG ulSize;
352 LPBYTE pBuffer;
353 ULONG Idx, Idx2;
354 PSYSTEM_PROCESS_INFORMATION pSPI;
355 PPERFDATA pPDOld;
356 #ifdef EXTRA_INFO
357 HANDLE hProcess;
358 HANDLE hProcessToken;
359 TCHAR szTemp[MAX_PATH];
360 DWORD dwSize;
361 #endif
362 #ifdef TIMES
363 LARGE_INTEGER liCurrentKernelTime;
364 LARGE_INTEGER liCurrentIdleTime;
365 LARGE_INTEGER liCurrentTime;
366 #endif
367 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo;
368 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
369
370 #ifdef TIMES
371 // Get new system time
372 status = NtQuerySystemInformation(SystemTimeInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
373 if (status != NO_ERROR)
374 return;
375 #endif
376 // Get processor information
377 SysProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors);
378 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors, &ulSize);
379
380
381 // Get process information
382 PsaCaptureProcessesAndThreads((PSYSTEM_PROCESS_INFORMATION *)&pBuffer);
383
384 #ifdef TIMES
385 liCurrentKernelTime.QuadPart = 0;
386 liCurrentIdleTime.QuadPart = 0;
387 for (Idx=0; Idx<SystemBasicInfo.NumberOfProcessors; Idx++) {
388 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].KernelTime.QuadPart;
389 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].DpcTime.QuadPart;
390 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].InterruptTime.QuadPart;
391 liCurrentIdleTime.QuadPart += SysProcessorTimeInfo[Idx].IdleTime.QuadPart;
392 }
393
394 // If it's a first call - skip idle time calcs
395 if (liOldIdleTime.QuadPart != 0) {
396 // CurrentValue = NewValue - OldValue
397 liCurrentTime.QuadPart = liCurrentIdleTime.QuadPart - liOldIdleTime.QuadPart;
398 dbIdleTime = Li2Double(liCurrentTime);
399 liCurrentTime.QuadPart = liCurrentKernelTime.QuadPart - liOldKernelTime.QuadPart;
400 dbKernelTime = Li2Double(liCurrentTime);
401 liCurrentTime.QuadPart = SysTimeInfo.CurrentTime.QuadPart - liOldSystemTime.QuadPart;
402 dbSystemTime = Li2Double(liCurrentTime);
403
404 // CurrentCpuIdle = IdleTime / SystemTime
405 dbIdleTime = dbIdleTime / dbSystemTime;
406 dbKernelTime = dbKernelTime / dbSystemTime;
407
408 // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
409 dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5;
410 dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5;
411 }
412
413 // Store new CPU's idle and system time
414 liOldIdleTime = liCurrentIdleTime;
415 liOldSystemTime = SysTimeInfo.CurrentTime;
416 liOldKernelTime = liCurrentKernelTime;
417 #endif
418
419 // Determine the process count
420 // We loop through the data we got from PsaCaptureProcessesAndThreads
421 // and count how many structures there are (until PsaWalkNextProcess
422 // returns NULL)
423 ProcessCountOld = ProcessCount;
424 ProcessCount = 0;
425 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer);
426 while (pSPI) {
427 ProcessCount++;
428 pSPI = PsaWalkNextProcess(pSPI);
429 }
430
431 // Now alloc a new PERFDATA array and fill in the data
432 if (pPerfDataOld) {
433 free(pPerfDataOld);
434 }
435 pPerfDataOld = pPerfData;
436 pPerfData = (PPERFDATA)malloc(sizeof(PERFDATA) * ProcessCount);
437 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer);
438 for (Idx=0; Idx<ProcessCount; Idx++) {
439 // Get the old perf data for this process (if any)
440 // so that we can establish delta values
441 pPDOld = NULL;
442 for (Idx2=0; Idx2<ProcessCountOld; Idx2++) {
443 if (pPerfDataOld[Idx2].ProcessId == (ULONG)(pSPI->UniqueProcessId) &&
444 /* check also for the creation time, a new process may have an id of an old one */
445 pPerfDataOld[Idx2].CreateTime.QuadPart == pSPI->CreateTime.QuadPart) {
446 pPDOld = &pPerfDataOld[Idx2];
447 break;
448 }
449 }
450
451 // Clear out process perf data structure
452 memset(&pPerfData[Idx], 0, sizeof(PERFDATA));
453
454 if (pSPI->ImageName.Buffer) {
455 wcsncpy(pPerfData[Idx].ImageName, pSPI->ImageName.Buffer, pSPI->ImageName.Length / sizeof(WCHAR));
456 pPerfData[Idx].ImageName[pSPI->ImageName.Length / sizeof(WCHAR)] = 0;
457 }
458 else
459 {
460 #ifdef _UNICODE
461 wcscpy(pPerfData[Idx].ImageName, lpIdleProcess);
462 #else
463 MultiByteToWideChar(CP_ACP, 0, lpIdleProcess, strlen(lpIdleProcess), pPerfData[Idx].ImageName, MAX_PATH);
464 #endif
465 }
466
467 pPerfData[Idx].ProcessId = (ULONG)(pSPI->UniqueProcessId);
468 pPerfData[Idx].CreateTime = pSPI->CreateTime;
469
470 if (pPDOld) {
471 #ifdef TIMES
472 double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime);
473 double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime);
474 double CpuTime = (CurTime - OldTime) / dbSystemTime;
475 CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; // + 0.5;
476
477 pPerfData[Idx].CPUUsage = (ULONG)CpuTime;
478 #else
479 pPerfData[Idx].CPUUsage = 0;
480 #endif
481 }
482
483 pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart;
484 pPerfData[Idx].WorkingSetSizeBytes = pSPI->WorkingSetSize;
485 pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSize;
486 if (pPDOld)
487 pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->WorkingSetSize - (LONG)pPDOld->WorkingSetSizeBytes);
488 else
489 pPerfData[Idx].WorkingSetSizeDelta = 0;
490 pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount;
491 if (pPDOld)
492 pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount);
493 else
494 pPerfData[Idx].PageFaultCountDelta = 0;
495 pPerfData[Idx].VirtualMemorySizeBytes = pSPI->VirtualSize;
496 pPerfData[Idx].PagedPoolUsagePages = pSPI->QuotaPagedPoolUsage;
497 pPerfData[Idx].NonPagedPoolUsagePages = pSPI->QuotaNonPagedPoolUsage;
498 pPerfData[Idx].BasePriority = pSPI->BasePriority;
499 pPerfData[Idx].HandleCount = pSPI->HandleCount;
500 pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads;
501 //pPerfData[Idx].SessionId = pSPI->SessionId;
502
503 #ifdef EXTRA_INFO
504 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pSPI->UniqueProcessId);
505 if (hProcess) {
506 if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) {
507 ImpersonateLoggedOnUser(hProcessToken);
508 memset(szTemp, 0, sizeof(TCHAR[MAX_PATH]));
509 dwSize = MAX_PATH;
510 GetUserName(szTemp, &dwSize);
511 #ifndef UNICODE
512 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTemp, -1, pPerfData[Idx].UserName, MAX_PATH);
513 #endif
514 RevertToSelf();
515 CloseHandle(hProcessToken);
516 }
517 CloseHandle(hProcess);
518 }
519 #endif
520 #ifdef TIMES
521 pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart;
522 pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart;
523 #endif
524 pSPI = PsaWalkNextProcess(pSPI);
525 }
526 PsaFreeCapture(pBuffer);
527
528 free(SysProcessorTimeInfo);
529 }
530
531 // Code partly taken from slw32tty.c from mc/slang
532 unsigned int GetKeyPressed(int events)
533 {
534 DWORD bytesRead;
535 INPUT_RECORD record;
536 int i;
537
538
539 for (i=0; i<events; i++)
540 {
541 if (!ReadConsoleInput(hStdin, &record, 1, &bytesRead)) {
542 return 0;
543 }
544
545 if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
546 return record.Event.KeyEvent.wVirtualKeyCode;//.uChar.AsciiChar;
547 }
548
549 return 0;
550 }
551
552
553 int main(int argc, char **argv)
554 {
555 int i;
556 TCHAR lpStr[80];
557
558 for (i = 0; i < 80; i++)
559 lpEmpty[i] = lpHeader[i] = _T(' ');
560 lpEmpty[79] = _T('\0');
561
562 /* Initialize global variables */
563 hInst = 0 /* FIXME: which value? [used with LoadString(hInst, ..., ..., ...)] */;
564 if (LoadString(hInst, IDS_COLUMN_IMAGENAME, lpStr, 80))
565 {
566 columnRightPositions[0] = _tcslen(lpStr);
567 _tcsncpy(&lpHeader[2], lpStr, _tcslen(lpStr));
568 }
569 if (LoadString(hInst, IDS_COLUMN_PID, lpStr, 80))
570 {
571 columnRightPositions[1] = columnRightPositions[0] + _tcslen(lpStr) + 3;
572 _tcsncpy(&lpHeader[columnRightPositions[0] + 2], lpStr, _tcslen(lpStr));
573 }
574 if (LoadString(hInst, IDS_COLUMN_CPU, lpStr, 80))
575 {
576 columnRightPositions[2] = columnRightPositions[1] + _tcslen(lpStr) + 3;
577 _tcsncpy(&lpHeader[columnRightPositions[1] + 2], lpStr, _tcslen(lpStr));
578 }
579 if (LoadString(hInst, IDS_COLUMN_MEM, lpStr, 80))
580 {
581 columnRightPositions[3] = columnRightPositions[2] + _tcslen(lpStr) + 3;
582 _tcsncpy(&lpHeader[columnRightPositions[2] + 2], lpStr, _tcslen(lpStr));
583 }
584 if (LoadString(hInst, IDS_COLUMN_PF, lpStr, 80))
585 {
586 columnRightPositions[4] = columnRightPositions[3] + _tcslen(lpStr) + 3;
587 _tcsncpy(&lpHeader[columnRightPositions[3] + 2], lpStr, _tcslen(lpStr));
588 }
589
590 for (i = 0; i < columnRightPositions[4]; i++)
591 lpSeparator[i] = _T('-');
592 lpHeader[0] = _T('|');
593 lpSeparator[0] = _T('+');
594 for (i = 0; i < 5; i++)
595 {
596 lpHeader[columnRightPositions[i]] = _T('|');
597 lpSeparator[columnRightPositions[i]] = _T('+');
598 }
599 lpSeparator[columnRightPositions[4] + 1] = _T('\0');
600 lpHeader[columnRightPositions[4] + 1] = _T('\0');
601
602
603 if (!LoadString(hInst, IDS_APP_TITLE, lpTitle, 80))
604 lpTitle[0] = _T('\0');
605 if (!LoadString(hInst, IDS_COLUMN_MEM_UNIT, lpMemUnit, 3))
606 lpMemUnit[0] = _T('\0');
607 if (!LoadString(hInst, IDS_MENU, lpMenu, 80))
608 lpMenu[0] = _T('\0');
609 if (!LoadString(hInst, IDS_IDLE_PROCESS, lpIdleProcess, 80))
610 lpIdleProcess[0] = _T('\0');
611
612 if (LoadString(hInst, IDS_MENU_QUIT, lpStr, 2))
613 KEY_QUIT = lpStr[0];
614 if (LoadString(hInst, IDS_MENU_KILL_PROCESS, lpStr, 2))
615 KEY_KILL = lpStr[0];
616 if (LoadString(hInst, IDS_YES, lpStr, 2))
617 KEY_YES = lpStr[0];
618 if (LoadString(hInst, IDS_NO, lpStr, 2))
619 KEY_NO = lpStr[0];
620
621 GetInputOutputHandles();
622
623 if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE)
624 {
625 if (LoadString(hInst, IDS_CTM_GENERAL_ERR1, lpStr, 80))
626 _tprintf(lpStr);
627 return -1;
628 }
629
630 if (GetConsoleMode(hStdin, &inConMode) == 0)
631 {
632 if (LoadString(hInst, IDS_CTM_GENERAL_ERR2, lpStr, 80))
633 _tprintf(lpStr);
634 return -1;
635 }
636
637 if (GetConsoleMode(hStdout, &outConMode) == 0)
638 {
639 if (LoadString(hInst, IDS_CTM_GENERAL_ERR3, lpStr, 80))
640 _tprintf(lpStr);
641 return -1;
642 }
643
644 SetConsoleMode(hStdin, 0); //FIXME: Should check for error!
645 SetConsoleMode(hStdout, 0); //FIXME: Should check for error!
646
647 PerfInit();
648
649 while (1)
650 {
651 DWORD numEvents;
652
653 PerfDataRefresh();
654 DisplayScreen();
655
656 /* WaitForSingleObject for console handles is not implemented in ROS */
657 WaitForSingleObject(hStdin, 1000);
658 GetNumberOfConsoleInputEvents(hStdin, &numEvents);
659
660 if (numEvents > 0)
661 {
662 if (ProcessKeys(numEvents) == TRUE)
663 break;
664 }
665 }
666
667 RestoreConsole();
668 return 0;
669 }