1 /* Console Task Manager
3 ctm.c - main program file
5 Written by: Aleksey Bragin (aleksey@studiocerebral.com)
7 Most of the code dealing with getting system parameters is taken from
8 ReactOS Task Manager written by Brian Palmer (brianp@reactos.org)
10 Localization features added by Hervé Poussineau (hpoussin@reactos.org)
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
17 18 March 2003 - Initial version 0.01, doesn't work under RectOS
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.
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.
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. */
34 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows //headers
35 #define WIN32_NO_STATUS
45 #define NTOS_MODE_USER
46 #include <ndk/ntndk.h>
48 #include <epsapi/epsapi.h>
62 DWORD columnRightPositions
[5];
63 TCHAR lpSeparator
[80];
66 TCHAR lpIdleProcess
[80];
72 TCHAR KEY_QUIT
, KEY_KILL
;
73 TCHAR KEY_YES
, KEY_NO
;
75 int ProcPerScreen
= 17; // 17 processess are displayed on one page
77 ULONG ProcessCountOld
= 0;
78 ULONG ProcessCount
= 0;
83 LARGE_INTEGER liOldIdleTime
= {{0,0}};
84 LARGE_INTEGER liOldKernelTime
= {{0,0}};
85 LARGE_INTEGER liOldSystemTime
= {{0,0}};
87 PPERFDATA pPerfDataOld
= NULL
; // Older perf data (saved to establish delta values)
88 PPERFDATA pPerfData
= NULL
; // Most recent copy of perf data
91 int scrolled
=0; // offset from which process start showing
92 int first
= 0; // first time in DisplayScreen
93 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
95 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo
;
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
); }
104 unsigned int GetKeyPressed();
106 void GetInputOutputHandles()
109 HANDLE console
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
110 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
111 0, CONSOLE_TEXTMODE_BUFFER
, 0);
113 if (SetConsoleActiveScreenBuffer(console
) == FALSE
)
115 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);
116 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
120 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);//console;
124 hStdin
= GetStdHandle(STD_INPUT_HANDLE
);
125 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
129 void RestoreConsole()
131 SetConsoleMode(hStdin
, inConMode
);
132 SetConsoleMode(hStdout
, outConMode
);
135 SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE
));
147 GetConsoleScreenBufferInfo(hStdout
,&screenBufferInfo
);
148 size
=screenBufferInfo
.dwSize
;
150 ProcPerScreen
= ScreenLines
-7;
154 pos
.X
= 1; pos
.Y
= 1;
155 WriteConsoleOutputCharacter(hStdout
, lpTitle
, _tcslen(lpTitle
), pos
, &numChars
);
157 pos
.X
= 1; pos
.Y
= 2;
158 WriteConsoleOutputCharacter(hStdout
, lpSeparator
, _tcslen(lpSeparator
), pos
, &numChars
);
160 pos
.X
= 1; pos
.Y
= 3;
161 WriteConsoleOutputCharacter(hStdout
, lpHeader
, _tcslen(lpHeader
), pos
, &numChars
);
163 pos
.X
= 1; pos
.Y
= 4;
164 WriteConsoleOutputCharacter(hStdout
, lpSeparator
, _tcslen(lpSeparator
), pos
, &numChars
);
167 pos
.X
= 1; pos
.Y
= ScreenLines
-2;
168 WriteConsoleOutputCharacter(hStdout
, lpSeparator
, _tcslen(lpSeparator
), pos
, &numChars
);
171 pos
.X
= 1; pos
.Y
= ScreenLines
-1;
172 WriteConsoleOutputCharacter(hStdout
, lpEmpty
, _tcslen(lpEmpty
), pos
, &numChars
);
173 WriteConsoleOutputCharacter(hStdout
, lpMenu
, _tcslen(lpMenu
), pos
, &numChars
);
179 lines
= ProcessCount
;
180 if (lines
> ProcPerScreen
)
181 lines
= ProcPerScreen
;
182 for (idx
=0; idx
<ProcPerScreen
; idx
++)
189 TCHAR lpPageFaults
[15];
192 for (i
= 0; i
< 80; i
++)
196 if (idx
< lines
&& scrolled
+ idx
< ProcessCount
)
200 _stprintf(lpNumber
, _T("%3d"), idx
+scrolled
);
201 _tcsncpy(&lpStr
[2], lpNumber
, 3);
205 len
= wcslen(pPerfData
[scrolled
+idx
].ImageName
);
207 WideCharToMultiByte(CP_ACP
, 0, pPerfData
[scrolled
+idx
].ImageName
, -1,
208 imgName
, MAX_PATH
, NULL
, NULL
);
209 len
= strlen(imgName
);
211 if (len
> columnRightPositions
[1])
213 len
= columnRightPositions
[1];
216 wcsncpy(&lpStr
[columnRightPositions
[0]+3], pPerfData
[scrolled
+idx
].ImageName
, len
);
218 strncpy(&lpStr
[columnRightPositions
[0]+3], imgName
, len
);
222 _stprintf(lpPid
, _T("%6ld"), pPerfData
[scrolled
+idx
].ProcessId
);
223 _tcsncpy(&lpStr
[columnRightPositions
[2] - 6], lpPid
, 6);
227 _stprintf(lpCpu
, _T("%3d%%"), pPerfData
[scrolled
+idx
].CPUUsage
);
228 _tcsncpy(&lpStr
[columnRightPositions
[3] - 4], lpCpu
, 4);
232 _stprintf(lpMemUsg
, _T("%6ld %s"), pPerfData
[scrolled
+idx
].WorkingSetSizeBytes
/ 1024, lpMemUnit
);
233 _tcsncpy(&lpStr
[columnRightPositions
[4] - 9], lpMemUsg
, 9);
236 _stprintf(lpPageFaults
, _T("%12ld"), pPerfData
[scrolled
+idx
].PageFaultCount
);
237 _tcsncpy(&lpStr
[columnRightPositions
[5] - 12], lpPageFaults
, 12);
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
);
249 pos
.X
= columnRightPositions
[0] + 1; pos
.Y
= 5+idx
;
250 if (selection
== idx
)
252 wColor
= BACKGROUND_GREEN
|
259 wColor
= BACKGROUND_BLUE
|
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
276 // returns TRUE if exiting
277 int ProcessKeys(int numEvents
)
280 if ((ProcessCount
-scrolled
< 17) && (ProcessCount
> 17))
281 scrolled
= ProcessCount
-17;
283 TCHAR key
= GetKeyPressed(numEvents
);
286 else if (key
== KEY_KILL
)
288 // user wants to kill some process, get his acknowledgement
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
);
298 GetNumberOfConsoleInputEvents(hStdin
, &pId
);
299 key
= GetKeyPressed(pId
);
300 } while (key
!= KEY_YES
&& key
!= KEY_NO
);
305 pId
= pPerfData
[selection
+scrolled
].ProcessId
;
306 hProcess
= OpenProcess(PROCESS_TERMINATE
, FALSE
, pId
);
310 if (!TerminateProcess(hProcess
, 0))
312 if (LoadString(hInst
, IDS_KILL_PROCESS_ERR1
, lpStr
, 80))
314 WriteConsoleOutputCharacter(hStdout
, lpEmpty
, _tcslen(lpEmpty
), pos
, &numChars
);
315 WriteConsoleOutputCharacter(hStdout
, lpStr
, _tcslen(lpStr
), pos
, &numChars
);
320 CloseHandle(hProcess
);
324 if (LoadString(hInst
, IDS_KILL_PROCESS_ERR2
, lpStr
, 80))
326 WriteConsoleOutputCharacter(hStdout
, lpEmpty
, _tcslen(lpEmpty
), pos
, &numChars
);
327 _stprintf(lpStr
, lpStr
, pId
);
328 WriteConsoleOutputCharacter(hStdout
, lpStr
, _tcslen(lpStr
), pos
, &numChars
);
336 else if (key
== VK_UP
)
340 else if ((selection
== 0) && (scrolled
> 0))
343 else if (key
== VK_DOWN
)
345 if ((selection
< ProcPerScreen
-1) && (selection
< ProcessCount
-1))
347 else if ((selection
== ProcPerScreen
-1) && (selection
+scrolled
< ProcessCount
-1))
350 else if (key
== VK_PRIOR
)
352 if (scrolled
>ProcPerScreen
-1)
353 scrolled
-=ProcPerScreen
-1;
361 else if (key
== VK_NEXT
)
363 scrolled
+=ProcPerScreen
-1;
364 if (scrolled
>ProcessCount
-ProcPerScreen
)
366 scrolled
=ProcessCount
-ProcPerScreen
; //End
367 selection
=ProcPerScreen
-1;
370 //selection=ProcPerScreen-1;
371 if (ProcessCount
<=ProcPerScreen
) //If there are less process than fits on the screen
374 selection
=(ProcessCount
%ProcPerScreen
)-1;
377 else if (key
== VK_HOME
)
382 else if (key
== VK_END
)
384 selection
=ProcPerScreen
-1;
385 scrolled
=ProcessCount
-ProcPerScreen
;
386 if (ProcessCount
<=ProcPerScreen
) //If there are less process than fits on the screen
389 selection
=(ProcessCount
%ProcPerScreen
)-1;
397 NtQuerySystemInformation(SystemBasicInformation
, &SystemBasicInfo
, sizeof(SystemBasicInfo
), 0);
400 void PerfDataRefresh()
406 PSYSTEM_PROCESS_INFORMATION pSPI
;
410 HANDLE hProcessToken
;
411 TCHAR szTemp
[MAX_PATH
];
415 LARGE_INTEGER liCurrentKernelTime
;
416 LARGE_INTEGER liCurrentIdleTime
;
417 LARGE_INTEGER liCurrentTime
;
419 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo
;
420 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo
;
423 // Get new system time
424 status
= NtQuerySystemInformation(SystemTimeInformation
, &SysTimeInfo
, sizeof(SysTimeInfo
), 0);
425 if (status
!= NO_ERROR
)
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
);
433 // Get process information
434 PsaCaptureProcessesAndThreads((PSYSTEM_PROCESS_INFORMATION
*)&pBuffer
);
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
;
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
);
456 // CurrentCpuIdle = IdleTime / SystemTime
457 dbIdleTime
= dbIdleTime
/ dbSystemTime
;
458 dbKernelTime
= dbKernelTime
/ dbSystemTime
;
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;
465 // Store new CPU's idle and system time
466 liOldIdleTime
= liCurrentIdleTime
;
467 liOldSystemTime
= SysTimeInfo
.CurrentTime
;
468 liOldKernelTime
= liCurrentKernelTime
;
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
475 ProcessCountOld
= ProcessCount
;
477 pSPI
= PsaWalkFirstProcess((PSYSTEM_PROCESS_INFORMATION
)pBuffer
);
480 pSPI
= PsaWalkNextProcess(pSPI
);
483 // Now alloc a new PERFDATA array and fill in the data
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
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
];
503 // Clear out process perf data structure
504 memset(&pPerfData
[Idx
], 0, sizeof(PERFDATA
));
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;
513 wcscpy(pPerfData
[Idx
].ImageName
, lpIdleProcess
);
515 MultiByteToWideChar(CP_ACP
, 0, lpIdleProcess
, strlen(lpIdleProcess
), pPerfData
[Idx
].ImageName
, MAX_PATH
);
519 pPerfData
[Idx
].ProcessId
= (ULONG
)(pSPI
->UniqueProcessId
);
520 pPerfData
[Idx
].CreateTime
= pSPI
->CreateTime
;
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;
529 pPerfData
[Idx
].CPUUsage
= (ULONG
)CpuTime
;
531 pPerfData
[Idx
].CPUUsage
= 0;
535 pPerfData
[Idx
].CPUTime
.QuadPart
= pSPI
->UserTime
.QuadPart
+ pSPI
->KernelTime
.QuadPart
;
536 pPerfData
[Idx
].WorkingSetSizeBytes
= pSPI
->WorkingSetSize
;
537 pPerfData
[Idx
].PeakWorkingSetSizeBytes
= pSPI
->PeakWorkingSetSize
;
539 pPerfData
[Idx
].WorkingSetSizeDelta
= labs((LONG
)pSPI
->WorkingSetSize
- (LONG
)pPDOld
->WorkingSetSizeBytes
);
541 pPerfData
[Idx
].WorkingSetSizeDelta
= 0;
542 pPerfData
[Idx
].PageFaultCount
= pSPI
->PageFaultCount
;
544 pPerfData
[Idx
].PageFaultCountDelta
= labs((LONG
)pSPI
->PageFaultCount
- (LONG
)pPDOld
->PageFaultCount
);
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;
556 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, (DWORD
)pSPI
->UniqueProcessId
);
558 if (OpenProcessToken(hProcess
, TOKEN_QUERY
|TOKEN_DUPLICATE
|TOKEN_IMPERSONATE
, &hProcessToken
)) {
559 ImpersonateLoggedOnUser(hProcessToken
);
560 memset(szTemp
, 0, sizeof(TCHAR
[MAX_PATH
]));
562 GetUserName(szTemp
, &dwSize
);
564 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, szTemp
, -1, pPerfData
[Idx
].UserName
, MAX_PATH
);
567 CloseHandle(hProcessToken
);
569 CloseHandle(hProcess
);
573 pPerfData
[Idx
].UserTime
.QuadPart
= pSPI
->UserTime
.QuadPart
;
574 pPerfData
[Idx
].KernelTime
.QuadPart
= pSPI
->KernelTime
.QuadPart
;
576 pSPI
= PsaWalkNextProcess(pSPI
);
578 PsaFreeCapture(pBuffer
);
580 free(SysProcessorTimeInfo
);
583 // Code partly taken from slw32tty.c from mc/slang
584 unsigned int GetKeyPressed(int events
)
591 for (i
=0; i
<events
; i
++)
593 if (!ReadConsoleInput(hStdin
, &record
, 1, &bytesRead
)) {
597 if (record
.EventType
== KEY_EVENT
&& record
.Event
.KeyEvent
.bKeyDown
)
598 return record
.Event
.KeyEvent
.wVirtualKeyCode
;//.uChar.AsciiChar;
605 int main(int argc
, char **argv
)
610 for (i
= 0; i
< 80; i
++)
611 lpEmpty
[i
] = lpHeader
[i
] = _T(' ');
612 lpEmpty
[79] = _T('\0');
614 /* Initialize global variables */
615 hInst
= 0 /* FIXME: which value? [used with LoadString(hInst, ..., ..., ...)] */;
617 if (LoadString(hInst
, IDS_COLUMN_NUMBER
, lpStr
, 80))
619 columnRightPositions
[0] = _tcslen(lpStr
) + 3;
620 _tcsncpy(&lpHeader
[2], lpStr
, _tcslen(lpStr
));
622 if (LoadString(hInst
, IDS_COLUMN_IMAGENAME
, lpStr
, 80))
624 columnRightPositions
[1] = columnRightPositions
[0] + _tcslen(lpStr
) + 3;
625 _tcsncpy(&lpHeader
[columnRightPositions
[0] + 2], lpStr
, _tcslen(lpStr
));
627 if (LoadString(hInst
, IDS_COLUMN_PID
, lpStr
, 80))
629 columnRightPositions
[2] = columnRightPositions
[1] + _tcslen(lpStr
) + 3;
630 _tcsncpy(&lpHeader
[columnRightPositions
[1] + 2], lpStr
, _tcslen(lpStr
));
632 if (LoadString(hInst
, IDS_COLUMN_CPU
, lpStr
, 80))
634 columnRightPositions
[3] = columnRightPositions
[2] + _tcslen(lpStr
) + 3;
635 _tcsncpy(&lpHeader
[columnRightPositions
[2] + 2], lpStr
, _tcslen(lpStr
));
637 if (LoadString(hInst
, IDS_COLUMN_MEM
, lpStr
, 80))
639 columnRightPositions
[4] = columnRightPositions
[3] + _tcslen(lpStr
) + 3;
640 _tcsncpy(&lpHeader
[columnRightPositions
[3] + 2], lpStr
, _tcslen(lpStr
));
642 if (LoadString(hInst
, IDS_COLUMN_PF
, lpStr
, 80))
644 columnRightPositions
[5] = columnRightPositions
[4] + _tcslen(lpStr
) + 3;
645 _tcsncpy(&lpHeader
[columnRightPositions
[4] + 2], lpStr
, _tcslen(lpStr
));
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
++)
654 lpHeader
[columnRightPositions
[i
]] = _T('|');
655 lpSeparator
[columnRightPositions
[i
]] = _T('+');
657 lpSeparator
[columnRightPositions
[5] + 1] = _T('\0');
658 lpHeader
[columnRightPositions
[5] + 1] = _T('\0');
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');
670 if (LoadString(hInst
, IDS_MENU_QUIT
, lpStr
, 2))
672 if (LoadString(hInst
, IDS_MENU_KILL_PROCESS
, lpStr
, 2))
674 if (LoadString(hInst
, IDS_YES
, lpStr
, 2))
676 if (LoadString(hInst
, IDS_NO
, lpStr
, 2))
679 GetInputOutputHandles();
681 if (hStdin
== INVALID_HANDLE_VALUE
|| hStdout
== INVALID_HANDLE_VALUE
)
683 if (LoadString(hInst
, IDS_CTM_GENERAL_ERR1
, lpStr
, 80))
688 if (GetConsoleMode(hStdin
, &inConMode
) == 0)
690 if (LoadString(hInst
, IDS_CTM_GENERAL_ERR2
, lpStr
, 80))
695 if (GetConsoleMode(hStdout
, &outConMode
) == 0)
697 if (LoadString(hInst
, IDS_CTM_GENERAL_ERR3
, lpStr
, 80))
702 SetConsoleMode(hStdin
, 0); //FIXME: Should check for error!
703 SetConsoleMode(hStdout
, 0); //FIXME: Should check for error!
714 /* WaitForSingleObject for console handles is not implemented in ROS */
715 WaitForSingleObject(hStdin
, 1000);
716 GetNumberOfConsoleInputEvents(hStdin
, &numEvents
);
720 if (ProcessKeys(numEvents
) == TRUE
)