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 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 TCHAR key; 281 if ((ProcessCount-scrolled < 17) && (ProcessCount > 17)) 282 scrolled = ProcessCount-17; 283 284 key = GetKeyPressed(numEvents); 285 if (key == KEY_QUIT) 286 return TRUE; 287 else if (key == KEY_KILL) 288 { 289 // user wants to kill some process, get his acknowledgement 290 DWORD pId; 291 COORD pos; 292 TCHAR lpStr[100]; 293 294 pos.X = 1; pos.Y =ScreenLines-1; 295 if (LoadString(hInst, IDS_KILL_PROCESS, lpStr, 100)) 296 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars); 297 298 do { 299 GetNumberOfConsoleInputEvents(hStdin, &pId); 300 key = GetKeyPressed(pId); 301 } while (key != KEY_YES && key != KEY_NO); 302 303 if (key == KEY_YES) 304 { 305 HANDLE hProcess; 306 pId = pPerfData[selection+scrolled].ProcessId; 307 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pId); 308 309 if (hProcess) 310 { 311 if (!TerminateProcess(hProcess, 0)) 312 { 313 if (LoadString(hInst, IDS_KILL_PROCESS_ERR1, lpStr, 80)) 314 { 315 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars); 316 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars); 317 } 318 Sleep(1000); 319 } 320 321 CloseHandle(hProcess); 322 } 323 else 324 { 325 if (LoadString(hInst, IDS_KILL_PROCESS_ERR2, lpStr, 80)) 326 { 327 WriteConsoleOutputCharacter(hStdout, lpEmpty, _tcslen(lpEmpty), pos, &numChars); 328 _stprintf(lpStr, lpStr, pId); 329 WriteConsoleOutputCharacter(hStdout, lpStr, _tcslen(lpStr), pos, &numChars); 330 } 331 Sleep(1000); 332 } 333 } 334 335 first = 0; 336 } 337 else if (key == VK_UP) 338 { 339 if (selection > 0) 340 selection--; 341 else if ((selection == 0) && (scrolled > 0)) 342 scrolled--; 343 } 344 else if (key == VK_DOWN) 345 { 346 if ((selection < ProcPerScreen-1) && (selection < ProcessCount-1)) 347 selection++; 348 else if ((selection == ProcPerScreen-1) && (selection+scrolled < ProcessCount-1)) 349 scrolled++; 350 } 351 else if (key == VK_PRIOR) 352 { 353 if (scrolled>ProcPerScreen-1) 354 scrolled-=ProcPerScreen-1; 355 else 356 { 357 scrolled=0; //First 358 selection=0; 359 } 360 //selection=0; 361 } 362 else if (key == VK_NEXT) 363 { 364 scrolled+=ProcPerScreen-1; 365 if (scrolled>ProcessCount-ProcPerScreen) 366 { 367 scrolled=ProcessCount-ProcPerScreen; //End 368 selection=ProcPerScreen-1; 369 } 370 371 //selection=ProcPerScreen-1; 372 if (ProcessCount<=ProcPerScreen) //If there are less process than fits on the screen 373 { 374 scrolled=0; 375 selection=(ProcessCount%ProcPerScreen)-1; 376 } 377 } 378 else if (key == VK_HOME) 379 { 380 selection=0; 381 scrolled=0; 382 } 383 else if (key == VK_END) 384 { 385 selection=ProcPerScreen-1; 386 scrolled=ProcessCount-ProcPerScreen; 387 if (ProcessCount<=ProcPerScreen) //If there are less process than fits on the screen 388 { 389 scrolled=0; 390 selection=(ProcessCount%ProcPerScreen)-1; 391 } 392 } 393 return FALSE; 394 } 395 396 void PerfInit() 397 { 398 NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), 0); 399 } 400 401 void PerfDataRefresh() 402 { 403 LONG status; 404 ULONG ulSize; 405 LPBYTE pBuffer; 406 ULONG Idx, Idx2; 407 PSYSTEM_PROCESS_INFORMATION pSPI; 408 PPERFDATA pPDOld; 409 #ifdef EXTRA_INFO 410 HANDLE hProcess; 411 HANDLE hProcessToken; 412 TCHAR szTemp[MAX_PATH]; 413 DWORD dwSize; 414 #endif 415 #ifdef TIMES 416 LARGE_INTEGER liCurrentKernelTime; 417 LARGE_INTEGER liCurrentIdleTime; 418 LARGE_INTEGER liCurrentTime; 419 #endif 420 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo; 421 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo; 422 423 #ifdef TIMES 424 // Get new system time 425 status = NtQuerySystemInformation(SystemTimeInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0); 426 if (status != NO_ERROR) 427 return; 428 #endif 429 // Get processor information 430 SysProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors); 431 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors, &ulSize); 432 433 434 // Get process information 435 PsaCaptureProcessesAndThreads((PSYSTEM_PROCESS_INFORMATION *)&pBuffer); 436 437 #ifdef TIMES 438 liCurrentKernelTime.QuadPart = 0; 439 liCurrentIdleTime.QuadPart = 0; 440 for (Idx=0; Idx<SystemBasicInfo.NumberOfProcessors; Idx++) { 441 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].KernelTime.QuadPart; 442 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].DpcTime.QuadPart; 443 liCurrentKernelTime.QuadPart += SysProcessorTimeInfo[Idx].InterruptTime.QuadPart; 444 liCurrentIdleTime.QuadPart += SysProcessorTimeInfo[Idx].IdleTime.QuadPart; 445 } 446 447 // If it's a first call - skip idle time calcs 448 if (liOldIdleTime.QuadPart != 0) { 449 // CurrentValue = NewValue - OldValue 450 liCurrentTime.QuadPart = liCurrentIdleTime.QuadPart - liOldIdleTime.QuadPart; 451 dbIdleTime = Li2Double(liCurrentTime); 452 liCurrentTime.QuadPart = liCurrentKernelTime.QuadPart - liOldKernelTime.QuadPart; 453 dbKernelTime = Li2Double(liCurrentTime); 454 liCurrentTime.QuadPart = SysTimeInfo.CurrentTime.QuadPart - liOldSystemTime.QuadPart; 455 dbSystemTime = Li2Double(liCurrentTime); 456 457 // CurrentCpuIdle = IdleTime / SystemTime 458 dbIdleTime = dbIdleTime / dbSystemTime; 459 dbKernelTime = dbKernelTime / dbSystemTime; 460 461 // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors 462 dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5; 463 dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors;// + 0.5; 464 } 465 466 // Store new CPU's idle and system time 467 liOldIdleTime = liCurrentIdleTime; 468 liOldSystemTime = SysTimeInfo.CurrentTime; 469 liOldKernelTime = liCurrentKernelTime; 470 #endif 471 472 // Determine the process count 473 // We loop through the data we got from PsaCaptureProcessesAndThreads 474 // and count how many structures there are (until PsaWalkNextProcess 475 // returns NULL) 476 ProcessCountOld = ProcessCount; 477 ProcessCount = 0; 478 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer); 479 while (pSPI) { 480 ProcessCount++; 481 pSPI = PsaWalkNextProcess(pSPI); 482 } 483 484 // Now alloc a new PERFDATA array and fill in the data 485 if (pPerfDataOld) { 486 free(pPerfDataOld); 487 } 488 pPerfDataOld = pPerfData; 489 pPerfData = (PPERFDATA)malloc(sizeof(PERFDATA) * ProcessCount); 490 pSPI = PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION)pBuffer); 491 for (Idx=0; Idx<ProcessCount; Idx++) { 492 // Get the old perf data for this process (if any) 493 // so that we can establish delta values 494 pPDOld = NULL; 495 for (Idx2=0; Idx2<ProcessCountOld; Idx2++) { 496 if (pPerfDataOld[Idx2].ProcessId == (ULONG)(pSPI->UniqueProcessId) && 497 /* check also for the creation time, a new process may have an id of an old one */ 498 pPerfDataOld[Idx2].CreateTime.QuadPart == pSPI->CreateTime.QuadPart) { 499 pPDOld = &pPerfDataOld[Idx2]; 500 break; 501 } 502 } 503 504 // Clear out process perf data structure 505 memset(&pPerfData[Idx], 0, sizeof(PERFDATA)); 506 507 if (pSPI->ImageName.Buffer) { 508 wcsncpy(pPerfData[Idx].ImageName, pSPI->ImageName.Buffer, pSPI->ImageName.Length / sizeof(WCHAR)); 509 pPerfData[Idx].ImageName[pSPI->ImageName.Length / sizeof(WCHAR)] = 0; 510 } 511 else 512 { 513 #ifdef _UNICODE 514 wcscpy(pPerfData[Idx].ImageName, lpIdleProcess); 515 #else 516 MultiByteToWideChar(CP_ACP, 0, lpIdleProcess, strlen(lpIdleProcess), pPerfData[Idx].ImageName, MAX_PATH); 517 #endif 518 } 519 520 pPerfData[Idx].ProcessId = (ULONG)(pSPI->UniqueProcessId); 521 pPerfData[Idx].CreateTime = pSPI->CreateTime; 522 523 if (pPDOld) { 524 #ifdef TIMES 525 double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime); 526 double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime); 527 double CpuTime = (CurTime - OldTime) / dbSystemTime; 528 CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; // + 0.5; 529 530 pPerfData[Idx].CPUUsage = (ULONG)CpuTime; 531 #else 532 pPerfData[Idx].CPUUsage = 0; 533 #endif 534 } 535 536 pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart; 537 pPerfData[Idx].WorkingSetSizeBytes = pSPI->WorkingSetSize; 538 pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSize; 539 if (pPDOld) 540 pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->WorkingSetSize - (LONG)pPDOld->WorkingSetSizeBytes); 541 else 542 pPerfData[Idx].WorkingSetSizeDelta = 0; 543 pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount; 544 if (pPDOld) 545 pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount); 546 else 547 pPerfData[Idx].PageFaultCountDelta = 0; 548 pPerfData[Idx].VirtualMemorySizeBytes = pSPI->VirtualSize; 549 pPerfData[Idx].PagedPoolUsagePages = pSPI->QuotaPagedPoolUsage; 550 pPerfData[Idx].NonPagedPoolUsagePages = pSPI->QuotaNonPagedPoolUsage; 551 pPerfData[Idx].BasePriority = pSPI->BasePriority; 552 pPerfData[Idx].HandleCount = pSPI->HandleCount; 553 pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads; 554 //pPerfData[Idx].SessionId = pSPI->SessionId; 555 556 #ifdef EXTRA_INFO 557 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pSPI->UniqueProcessId); 558 if (hProcess) { 559 if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) { 560 ImpersonateLoggedOnUser(hProcessToken); 561 memset(szTemp, 0, sizeof(TCHAR[MAX_PATH])); 562 dwSize = MAX_PATH; 563 GetUserName(szTemp, &dwSize); 564 #ifndef UNICODE 565 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTemp, -1, pPerfData[Idx].UserName, MAX_PATH); 566 #endif 567 RevertToSelf(); 568 CloseHandle(hProcessToken); 569 } 570 CloseHandle(hProcess); 571 } 572 #endif 573 #ifdef TIMES 574 pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart; 575 pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart; 576 #endif 577 pSPI = PsaWalkNextProcess(pSPI); 578 } 579 PsaFreeCapture(pBuffer); 580 581 free(SysProcessorTimeInfo); 582 } 583 584 // Code partly taken from slw32tty.c from mc/slang 585 unsigned int GetKeyPressed(int events) 586 { 587 DWORD bytesRead; 588 INPUT_RECORD record; 589 int i; 590 591 592 for (i=0; i<events; i++) 593 { 594 if (!ReadConsoleInput(hStdin, &record, 1, &bytesRead)) { 595 return 0; 596 } 597 598 if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) 599 return record.Event.KeyEvent.wVirtualKeyCode;//.uChar.AsciiChar; 600 } 601 602 return 0; 603 } 604 605 606 int _tmain(int argc, char **argv) 607 { 608 int i; 609 TCHAR lpStr[80]; 610 611 for (i = 0; i < 80; i++) 612 lpEmpty[i] = lpHeader[i] = _T(' '); 613 lpEmpty[79] = _T('\0'); 614 615 /* Initialize global variables */ 616 hInst = 0 /* FIXME: which value? [used with LoadString(hInst, ..., ..., ...)] */; 617 618 if (LoadString(hInst, IDS_COLUMN_NUMBER, lpStr, 80)) 619 { 620 columnRightPositions[0] = _tcslen(lpStr) + 3; 621 _tcsncpy(&lpHeader[2], lpStr, _tcslen(lpStr)); 622 } 623 if (LoadString(hInst, IDS_COLUMN_IMAGENAME, lpStr, 80)) 624 { 625 columnRightPositions[1] = columnRightPositions[0] + _tcslen(lpStr) + 3; 626 _tcsncpy(&lpHeader[columnRightPositions[0] + 2], lpStr, _tcslen(lpStr)); 627 } 628 if (LoadString(hInst, IDS_COLUMN_PID, lpStr, 80)) 629 { 630 columnRightPositions[2] = columnRightPositions[1] + _tcslen(lpStr) + 3; 631 _tcsncpy(&lpHeader[columnRightPositions[1] + 2], lpStr, _tcslen(lpStr)); 632 } 633 if (LoadString(hInst, IDS_COLUMN_CPU, lpStr, 80)) 634 { 635 columnRightPositions[3] = columnRightPositions[2] + _tcslen(lpStr) + 3; 636 _tcsncpy(&lpHeader[columnRightPositions[2] + 2], lpStr, _tcslen(lpStr)); 637 } 638 if (LoadString(hInst, IDS_COLUMN_MEM, lpStr, 80)) 639 { 640 columnRightPositions[4] = columnRightPositions[3] + _tcslen(lpStr) + 3; 641 _tcsncpy(&lpHeader[columnRightPositions[3] + 2], lpStr, _tcslen(lpStr)); 642 } 643 if (LoadString(hInst, IDS_COLUMN_PF, lpStr, 80)) 644 { 645 columnRightPositions[5] = columnRightPositions[4] + _tcslen(lpStr) + 3; 646 _tcsncpy(&lpHeader[columnRightPositions[4] + 2], lpStr, _tcslen(lpStr)); 647 } 648 649 for (i = 0; i < columnRightPositions[5]; i++) 650 lpSeparator[i] = _T('-'); 651 lpHeader[0] = _T('|'); 652 lpSeparator[0] = _T('+'); 653 for (i = 0; i < 6; i++) 654 { 655 lpHeader[columnRightPositions[i]] = _T('|'); 656 lpSeparator[columnRightPositions[i]] = _T('+'); 657 } 658 lpSeparator[columnRightPositions[5] + 1] = _T('\0'); 659 lpHeader[columnRightPositions[5] + 1] = _T('\0'); 660 661 662 if (!LoadString(hInst, IDS_APP_TITLE, lpTitle, 80)) 663 lpTitle[0] = _T('\0'); 664 if (!LoadString(hInst, IDS_COLUMN_MEM_UNIT, lpMemUnit, 3)) 665 lpMemUnit[0] = _T('\0'); 666 if (!LoadString(hInst, IDS_MENU, lpMenu, 80)) 667 lpMenu[0] = _T('\0'); 668 if (!LoadString(hInst, IDS_IDLE_PROCESS, lpIdleProcess, 80)) 669 lpIdleProcess[0] = _T('\0'); 670 671 if (LoadString(hInst, IDS_MENU_QUIT, lpStr, 2)) 672 KEY_QUIT = lpStr[0]; 673 if (LoadString(hInst, IDS_MENU_KILL_PROCESS, lpStr, 2)) 674 KEY_KILL = lpStr[0]; 675 if (LoadString(hInst, IDS_YES, lpStr, 2)) 676 KEY_YES = lpStr[0]; 677 if (LoadString(hInst, IDS_NO, lpStr, 2)) 678 KEY_NO = lpStr[0]; 679 680 GetInputOutputHandles(); 681 682 if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) 683 { 684 if (LoadString(hInst, IDS_CTM_GENERAL_ERR1, lpStr, 80)) 685 _tprintf(lpStr); 686 return -1; 687 } 688 689 if (GetConsoleMode(hStdin, &inConMode) == 0) 690 { 691 if (LoadString(hInst, IDS_CTM_GENERAL_ERR2, lpStr, 80)) 692 _tprintf(lpStr); 693 return -1; 694 } 695 696 if (GetConsoleMode(hStdout, &outConMode) == 0) 697 { 698 if (LoadString(hInst, IDS_CTM_GENERAL_ERR3, lpStr, 80)) 699 _tprintf(lpStr); 700 return -1; 701 } 702 703 SetConsoleMode(hStdin, 0); //FIXME: Should check for error! 704 SetConsoleMode(hStdout, 0); //FIXME: Should check for error! 705 706 PerfInit(); 707 708 while (1) 709 { 710 DWORD numEvents; 711 712 PerfDataRefresh(); 713 DisplayScreen(); 714 715 /* WaitForSingleObject for console handles is not implemented in ROS */ 716 WaitForSingleObject(hStdin, 1000); 717 GetNumberOfConsoleInputEvents(hStdin, &numEvents); 718 719 if (numEvents > 0) 720 { 721 if (ProcessKeys(numEvents) == TRUE) 722 break; 723 } 724 } 725 726 RestoreConsole(); 727 return 0; 728 } 729