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 101 void *PsaiMalloc(SIZE_T size) { return malloc(size); } 102 void *PsaiRealloc(void *ptr, SIZE_T size) { return realloc(ptr, size); } 103 void PsaiFree(void *ptr) { free(ptr); } 104 105 // Prototypes 106 unsigned int GetKeyPressed(); 107 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 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 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 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 405 void PerfInit() 406 { 407 NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), 0); 408 } 409 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 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 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