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