/*++ Copyright (c) 1993 Microsoft Corporation Module Name: poolmon.c Abstract: This module contains the NT/Win32 Pool Monitor Author: Lou Perazzoli (loup) 13-Sep-1993 Revision History: --*/ #include "perfmtrp.h" #include #include #include #include // // the amount of memory to increase the size // of the buffer for NtQuerySystemInformation at each step // #define BUFFER_SIZE_STEP 65536 #define CPU_USAGE 0 #define QUOTAS 1 #define TAG 0 #define ALLOC 1 #define FREE 2 #define DIFF 3 #define BYTES 4 #define EACH 5 #define LIGHT 6 #define NONPAGED 0 #define PAGED 1 #define BOTH 2 UCHAR *PoolType[] = { "Nonp ", "Paged" }; PUCHAR LargeBuffer1 = NULL; PUCHAR LargeBuffer2 = NULL; size_t LargeBuffer1Size = 0; size_t LargeBuffer2Size = 0; typedef struct _POOLMON_OUT { union { UCHAR Tag[4]; ULONG TagUlong; }; UCHAR NullByte; BOOLEAN Changed; ULONG Type; SIZE_T Allocs; SIZE_T AllocsDiff; SIZE_T Frees; SIZE_T FreesDiff; SIZE_T Allocs_Frees; SIZE_T Used; SIZE_T UsedDiff; SIZE_T Each; } POOLMON_OUT, *PPOOLMON_OUT; POOLMON_OUT OutBuffer[2000]; ULONG DisplayType = BOTH; ULONG SortBy = TAG; ULONG Paren; ULONG DelayTimeMsec = 5000; BOOLEAN Interactive; ULONG NumberOfInputRecords; INPUT_RECORD InputRecord; HANDLE InputHandle; HANDLE OriginalOutputHandle; HANDLE OutputHandle; DWORD OriginalInputMode; WORD NormalAttribute; WORD HighlightAttribute; ULONG NumberOfCols; ULONG NumberOfRows; ULONG NumberOfDetailLines; SIZE_T FirstDetailLine; CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo; ULONG NoHighlight; BOOLEAN DisplayTotals = FALSE; POOLMON_OUT Totals[2]; typedef struct _FILTER { union { UCHAR Tag[4]; ULONG TagUlong; }; BOOLEAN Exclude; } FILTER, *PFILTER; #define MAX_FILTER 64 FILTER Filter[MAX_FILTER]; ULONG FilterCount = 0; VOID ShowHelpPopup( VOID ); int __cdecl ulcomp(const void *e1,const void *e2); int __cdecl ulcomp(const void *e1,const void *e2) { LONG_PTR u1; switch (SortBy) { case TAG: u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0]; if (u1 != 0) { return u1 > 0 ? 1 : -1; } u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1]; if (u1 != 0) { return u1 > 0 ? 1 : -1; } u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2]; if (u1 != 0) { return u1 > 0 ? 1 : -1; } u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3]; if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; case ALLOC: if (Paren & 1) { u1 = ((PPOOLMON_OUT)e2)->AllocsDiff - ((PPOOLMON_OUT)e1)->AllocsDiff; } else { u1 = ((PPOOLMON_OUT)e2)->Allocs - ((PPOOLMON_OUT)e1)->Allocs; } if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; case FREE: if (Paren & 1) { u1 = ((PPOOLMON_OUT)e2)->FreesDiff - ((PPOOLMON_OUT)e1)->FreesDiff; } else { u1 = ((PPOOLMON_OUT)e2)->Frees - ((PPOOLMON_OUT)e1)->Frees; } if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; case BYTES: if (Paren & 1) { u1 = ((PPOOLMON_OUT)e2)->UsedDiff - ((PPOOLMON_OUT)e1)->UsedDiff; } else { u1 = ((PPOOLMON_OUT)e2)->Used - ((PPOOLMON_OUT)e1)->Used; } if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; case DIFF: u1 = ((PPOOLMON_OUT)e2)->Allocs_Frees - ((PPOOLMON_OUT)e1)->Allocs_Frees; if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; case EACH: u1 = ((PPOOLMON_OUT)e2)->Each - ((PPOOLMON_OUT)e1)->Each; if (u1 == 0) { return 0; } else { return u1 > 0 ? 1 : -1; } break; default: return(0); break; } } BOOLEAN CheckSingleFilter ( PCHAR Tag, PCHAR Filter ) { ULONG i; CHAR tc; CHAR fc; for ( i = 0; i < 4; i++ ) { tc = *Tag++; fc = *Filter++; if ( fc == '*' ) return TRUE; if ( fc == '?' ) continue; if ( tc != fc ) return FALSE; } return TRUE; } BOOLEAN CheckFilters ( PSYSTEM_POOLTAG TagInfo ) { BOOLEAN pass; ULONG i; PCHAR tag; // // If there are no filters, all tags pass. // if ( FilterCount == 0 ) { return TRUE; } // // There are filters. If the first filter excludes tags, then any // tag not explicitly mentioned passes. If the first filter includes // tags, then any tag not explicitly mentioned fails. // if ( Filter[0].Exclude ) { pass = TRUE; } else { pass = FALSE; } tag = TagInfo->Tag; for ( i = 0; i < FilterCount; i++ ) { if ( CheckSingleFilter( tag, (PCHAR)&Filter[i].Tag ) ) { pass = !Filter[i].Exclude; } } return pass; } VOID AddFilter ( BOOLEAN Exclude, PCHAR FilterString ) { PFILTER f; PCHAR p; ULONG i; if ( FilterCount == MAX_FILTER ) { printf( "Too many filters specified. Limit is %d\n", MAX_FILTER ); return; } f = &Filter[FilterCount]; p = f->Tag; for ( i = 0; i < 4; i++ ) { if ( *FilterString == 0 ) break; *p++ = *FilterString++; } for ( ; i < 4; i++ ) { *p++ = ' '; } f->Exclude = Exclude; FilterCount++; return; } VOID ParseArgs ( int argc, char *argv[] ) { char *p; BOOLEAN exclude; argc--; argv++; while ( argc-- > 0 ) { p = *argv++; if ( *p == '-' || *p == '/' ) { p++; exclude = TRUE; switch ( tolower(*p) ) { case 'i': exclude = FALSE; case 'x': p++; if ( strlen(p) == 0 ) { printf( "missing filter string\n" ); ExitProcess( 1 ); } else if ( strlen(p) <= sizeof(ULONG) ) { AddFilter( exclude, p ); } else { printf( "filter string too long: %s\n", p ); ExitProcess( 1 ); } break; case 'e': DisplayTotals = TRUE; break; case 't': SortBy = TAG; break; case 'a': SortBy = ALLOC; break; case 'u': case 'b': SortBy = BYTES; break; case 'f': SortBy = FREE; break; case 'd': SortBy = DIFF; break; case 'm': SortBy = EACH; case 'l': NoHighlight = 1 - NoHighlight; break; case 'p': DisplayType += 1; if (DisplayType > BOTH) { DisplayType = NONPAGED; } break; case '(': case ')': Paren += 1; break; default: printf( "unknown switch: %s\n", p ); ExitProcess( 2 ); } } else { printf( "unknown switch: %s\n", p ); ExitProcess( 2 ); } } return; } BOOL WriteConsoleLine( HANDLE OutputHandle, WORD LineNumber, LPSTR Text, BOOL Highlight ) { COORD WriteCoord; DWORD NumberWritten; DWORD TextLength; WriteCoord.X = 0; WriteCoord.Y = LineNumber; if (!FillConsoleOutputCharacter( OutputHandle, ' ', NumberOfCols, WriteCoord, &NumberWritten ) ) { return FALSE; } if (!FillConsoleOutputAttribute( OutputHandle, (WORD)((Highlight && !NoHighlight) ? HighlightAttribute : NormalAttribute), NumberOfCols, WriteCoord, &NumberWritten ) ) { return FALSE; } if (Text == NULL || (TextLength = strlen( Text )) == 0) { return TRUE; } else { return WriteConsoleOutputCharacter( OutputHandle, Text, TextLength, WriteCoord, &NumberWritten ); } } NTSTATUS QueryPoolTagInformationIterative( PUCHAR *CurrentBuffer, size_t *CurrentBufferSize ) { size_t NewBufferSize; NTSTATUS ReturnedStatus = STATUS_SUCCESS; if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) { return STATUS_INVALID_PARAMETER; } // // there is no buffer allocated yet // if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) { NewBufferSize = sizeof( UCHAR ) * BUFFER_SIZE_STEP; *CurrentBuffer = (PUCHAR) malloc( NewBufferSize ); if( *CurrentBuffer != NULL ) { *CurrentBufferSize = NewBufferSize; } else { // // insufficient memory // ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES; } } // // iterate by buffer's size // while( *CurrentBuffer != NULL ) { ReturnedStatus = NtQuerySystemInformation ( SystemPoolTagInformation, *CurrentBuffer, (ULONG)*CurrentBufferSize, NULL ); if( ! NT_SUCCESS(ReturnedStatus) ) { // // free the current buffer // free( *CurrentBuffer ); *CurrentBuffer = NULL; if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) { // // try with a greater buffer size // NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP; *CurrentBuffer = (PUCHAR) malloc( NewBufferSize ); if( *CurrentBuffer != NULL ) { // // allocated new buffer // *CurrentBufferSize = NewBufferSize; } else { // // insufficient memory // ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES; *CurrentBufferSize = 0; } } else { *CurrentBufferSize = 0; } } else { // // NtQuerySystemInformation returned success // break; } } return ReturnedStatus; } int __cdecl main( int argc, char *argv[] ) { NTSTATUS Status; ULONG LastCount = 0; SYSTEM_BASIC_INFORMATION BasicInfo; SYSTEM_PERFORMANCE_INFORMATION PerfInfo; PSYSTEM_POOLTAG_INFORMATION PoolInfo; PSYSTEM_POOLTAG_INFORMATION PoolInfoOld; PUCHAR *PreviousBuffer; PUCHAR *CurrentBuffer; PUCHAR *TempBuffer; size_t *PreviousBufferSize; size_t *CurrentBufferSize; size_t *TempBufferSize; BOOLEAN DoHelp; BOOLEAN DoQuit; SIZE_T NumberOfPoolTags; SIZE_T i; UCHAR LastKey; PPOOLMON_OUT Out; LONG ScrollDelta; WORD DisplayLine, LastDetailRow; CHAR OutputBuffer[ 512 ]; DoHelp = FALSE; DoQuit = FALSE; Interactive = TRUE; ParseArgs( argc, argv ); InputHandle = GetStdHandle( STD_INPUT_HANDLE ); OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE ); if (Interactive) { if (InputHandle == NULL || OriginalOutputHandle == NULL || !GetConsoleMode( InputHandle, &OriginalInputMode ) ) { Interactive = FALSE; } else { OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); if (OutputHandle == NULL || !GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) || !SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) || !SetConsoleActiveScreenBuffer( OutputHandle ) || !SetConsoleMode( InputHandle, 0 ) ) { if (OutputHandle != NULL) { CloseHandle( OutputHandle ); OutputHandle = NULL; } Interactive = FALSE; } else { NormalAttribute = 0x1F; HighlightAttribute = 0x71; NumberOfCols = OriginalConsoleInfo.dwSize.X; NumberOfRows = OriginalConsoleInfo.dwSize.Y; NumberOfDetailLines = NumberOfRows; } } } NtQuerySystemInformation( SystemBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL ); if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) { SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); } PreviousBuffer = &LargeBuffer2; // NULL at this point PreviousBufferSize = &LargeBuffer2Size; // 0 at this point CurrentBuffer = &LargeBuffer1; // NULL at this point CurrentBufferSize = &LargeBuffer1Size; // 0 at this point while(TRUE) { Status = NtQuerySystemInformation( SystemPerformanceInformation, &PerfInfo, sizeof(PerfInfo), NULL ); if ( !NT_SUCCESS(Status) ) { printf("Query perf Failed (returned: %lx)\n", Status); break; } Status = QueryPoolTagInformationIterative( CurrentBuffer, CurrentBufferSize ); if ( !NT_SUCCESS(Status) ) { printf("Query pooltags failed (returned: %lx)\n" "Did you remember to enable pool tagging with gflags.exe and reboot?\n", Status); break; } // // Calculate pool tags and display information. // // PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)( *CurrentBuffer ); i = PoolInfo->Count; PoolInfoOld = (PSYSTEM_POOLTAG_INFORMATION)( *PreviousBuffer ); DisplayLine = 0; sprintf( OutputBuffer, " Memory:%8ldK Avail:%8ldK PageFlts:%6ld InRam Krnl:%5ldK P:%5ldK", BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024), PerfInfo.AvailablePages*(BasicInfo.PageSize/1024), PerfInfo.PageFaultCount - LastCount, (PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024), (PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024) ); WriteConsoleLine( OutputHandle, DisplayLine++, OutputBuffer, FALSE ); LastCount = PerfInfo.PageFaultCount; sprintf( OutputBuffer, " Commit:%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK", PerfInfo.CommittedPages*(BasicInfo.PageSize/1024), PerfInfo.CommitLimit*(BasicInfo.PageSize/1024), PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024), PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024), PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024) ); WriteConsoleLine( OutputHandle, DisplayLine++, OutputBuffer, FALSE ); WriteConsoleLine( OutputHandle, DisplayLine++, " Tag Type Allocs Frees Diff Bytes Per Alloc", FALSE ); WriteConsoleLine( OutputHandle, DisplayLine++, NULL, FALSE ); Out = &OutBuffer[0]; if (DisplayTotals) { RtlZeroMemory( Totals, sizeof(POOLMON_OUT)*2 ); } for (i = 0; i < (int)PoolInfo->Count; i++) { if ( !CheckFilters(&PoolInfo->TagInfo[i]) ) { continue; } if ((PoolInfo->TagInfo[i].NonPagedAllocs != 0) && (DisplayType != PAGED)) { Out->Allocs = PoolInfo->TagInfo[i].NonPagedAllocs; Out->Frees = PoolInfo->TagInfo[i].NonPagedFrees; Out->Used = PoolInfo->TagInfo[i].NonPagedUsed; Out->Allocs_Frees = PoolInfo->TagInfo[i].NonPagedAllocs - PoolInfo->TagInfo[i].NonPagedFrees; Out->TagUlong = PoolInfo->TagInfo[i].TagUlong; Out->Type = NONPAGED; Out->Changed = FALSE; Out->NullByte = '\0'; if (PoolInfoOld != NULL && PoolInfoOld->Count > i && PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong ) { Out->AllocsDiff = PoolInfo->TagInfo[i].NonPagedAllocs - PoolInfoOld->TagInfo[i].NonPagedAllocs; Out->FreesDiff = PoolInfo->TagInfo[i].NonPagedFrees - PoolInfoOld->TagInfo[i].NonPagedFrees; Out->UsedDiff = PoolInfo->TagInfo[i].NonPagedUsed - PoolInfoOld->TagInfo[i].NonPagedUsed; if (Out->AllocsDiff != 0 || Out->FreesDiff != 0 || Out->UsedDiff != 0 ) { Out->Changed = TRUE; } } else { Out->AllocsDiff = 0; Out->UsedDiff = 0; Out->FreesDiff = 0; } Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1); if (DisplayTotals) { Totals[NONPAGED].Allocs += Out->Allocs; Totals[NONPAGED].AllocsDiff += Out->AllocsDiff; Totals[NONPAGED].Frees += Out->Frees; Totals[NONPAGED].FreesDiff += Out->FreesDiff; Totals[NONPAGED].Allocs_Frees += Out->Allocs_Frees; Totals[NONPAGED].Used += Out->Used; Totals[NONPAGED].UsedDiff += Out->UsedDiff; } Out += 1; } if ((PoolInfo->TagInfo[i].PagedAllocs != 0) && (DisplayType != NONPAGED)) { Out->Allocs = PoolInfo->TagInfo[i].PagedAllocs; Out->Frees = PoolInfo->TagInfo[i].PagedFrees; Out->Used = PoolInfo->TagInfo[i].PagedUsed; Out->Allocs_Frees = PoolInfo->TagInfo[i].PagedAllocs - PoolInfo->TagInfo[i].PagedFrees; Out->TagUlong = PoolInfo->TagInfo[i].TagUlong; Out->Type = PAGED; Out->Changed = FALSE; Out->NullByte = '\0'; if (PoolInfoOld != NULL && PoolInfoOld->Count > i && PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong ) { Out->AllocsDiff = PoolInfo->TagInfo[i].PagedAllocs - PoolInfoOld->TagInfo[i].PagedAllocs; Out->FreesDiff = PoolInfo->TagInfo[i].PagedFrees - PoolInfoOld->TagInfo[i].PagedFrees; Out->UsedDiff = PoolInfo->TagInfo[i].PagedUsed - PoolInfoOld->TagInfo[i].PagedUsed; if (Out->AllocsDiff != 0 || Out->FreesDiff != 0 || Out->UsedDiff != 0 ) { Out->Changed = TRUE; } } else { Out->AllocsDiff = 0; Out->UsedDiff = 0; Out->FreesDiff = 0; } Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1); if (DisplayTotals) { Totals[PAGED].Allocs += Out->Allocs; Totals[PAGED].AllocsDiff += Out->AllocsDiff; Totals[PAGED].Frees += Out->Frees; Totals[PAGED].FreesDiff += Out->FreesDiff; Totals[PAGED].Allocs_Frees += Out->Allocs_Frees; Totals[PAGED].Used += Out->Used; Totals[PAGED].UsedDiff += Out->UsedDiff; } Out += 1; } } //end for // // Sort the running working set buffer // NumberOfPoolTags = Out - &OutBuffer[0]; qsort((void *)&OutBuffer, (size_t)NumberOfPoolTags, (size_t)sizeof(POOLMON_OUT), ulcomp); LastDetailRow = (WORD)(NumberOfRows - (DisplayTotals ? (DisplayType == BOTH ? 3 : 2) : 0)); for (i = FirstDetailLine; i < NumberOfPoolTags; i++) { if (DisplayLine >= LastDetailRow) { break; } sprintf( OutputBuffer, " %4s %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld", OutBuffer[i].Tag, PoolType[OutBuffer[i].Type], OutBuffer[i].Allocs, OutBuffer[i].AllocsDiff, OutBuffer[i].Frees, OutBuffer[i].FreesDiff, OutBuffer[i].Allocs_Frees, OutBuffer[i].Used, OutBuffer[i].UsedDiff, OutBuffer[i].Each ); WriteConsoleLine( OutputHandle, DisplayLine++, OutputBuffer, OutBuffer[i].Changed ); OutBuffer[i].Changed = FALSE; } if (DisplayTotals) { WriteConsoleLine( OutputHandle, DisplayLine++, NULL, FALSE ); for (i = 0; i < 2; i++) { if ( (int)DisplayType == i || DisplayType == BOTH ) { sprintf( OutputBuffer, "Total %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld", PoolType[i], Totals[i].Allocs, Totals[i].AllocsDiff, Totals[i].Frees, Totals[i].FreesDiff, Totals[i].Allocs_Frees, Totals[i].Used, Totals[i].UsedDiff, Totals[i].Each ); WriteConsoleLine( OutputHandle, DisplayLine++, OutputBuffer, FALSE ); } } } TempBuffer = PreviousBuffer; TempBufferSize = PreviousBufferSize; PreviousBuffer = CurrentBuffer; PreviousBufferSize = CurrentBufferSize; CurrentBuffer = TempBuffer; CurrentBufferSize = TempBufferSize; while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) { // // Check for input record // if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) && InputRecord.EventType == KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown ) { LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar; if (LastKey < ' ') { ScrollDelta = 0; if (LastKey == 'C'-'A'+1) { DoQuit = TRUE; } else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) { case VK_ESCAPE: DoQuit = TRUE; break; case VK_PRIOR: ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines); break; case VK_NEXT: ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines; break; case VK_UP: ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount; break; case VK_DOWN: ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount; break; case VK_HOME: FirstDetailLine = 0; break; case VK_END: FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines; break; } if (ScrollDelta != 0) { if (ScrollDelta < 0) { if (FirstDetailLine <= (ULONG)-ScrollDelta) { FirstDetailLine = 0; } else { FirstDetailLine += ScrollDelta; } } else { FirstDetailLine += ScrollDelta; if (FirstDetailLine >= (NumberOfPoolTags - NumberOfDetailLines)) { FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines; } } } } else { switch (toupper( LastKey )) { case 'Q': // // Go to the bottom of the current screen when // we quit. // DoQuit = TRUE; break; case 'T': SortBy = TAG; FirstDetailLine = 0; break; case 'A': SortBy = ALLOC; FirstDetailLine = 0; break; case 'U': case 'B': SortBy = BYTES; FirstDetailLine = 0; break; case 'F': SortBy = FREE; FirstDetailLine = 0; break; case 'D': SortBy = DIFF; FirstDetailLine = 0; break; case 'M': SortBy = EACH; FirstDetailLine = 0; break; case 'L': NoHighlight = 1 - NoHighlight; break; case 'P': DisplayType += 1; if (DisplayType > BOTH) { DisplayType = NONPAGED; } FirstDetailLine = 0; break; case 'X': case '(': case ')': Paren += 1; break; case 'E': DisplayTotals = !DisplayTotals; FirstDetailLine = 0; break; case 'H': case '?': DoHelp = TRUE; break; } } break; } } if (DoQuit) { break; } if (DoHelp) { DoHelp = FALSE; ShowHelpPopup(); } } if (Interactive) { SetConsoleActiveScreenBuffer( OriginalOutputHandle ); SetConsoleMode( InputHandle, OriginalInputMode ); CloseHandle( OutputHandle ); } ExitProcess( 0 ); return 0; } VOID ShowHelpPopup( VOID ) { HANDLE PopupHandle; WORD n; PopupHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); if (PopupHandle == NULL) { return; } SetConsoleActiveScreenBuffer( PopupHandle ); n = 0; WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " Poolmon Help", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " columns:", FALSE ); WriteConsoleLine( PopupHandle, n++, " Tag is the 4 byte tag given to the pool allocation", FALSE ); WriteConsoleLine( PopupHandle, n++, " Type is paged or nonp(aged)", FALSE ); WriteConsoleLine( PopupHandle, n++, " Allocs is count of all alloctions", FALSE ); WriteConsoleLine( PopupHandle, n++, " ( ) is difference in Allocs column from last update", FALSE ); WriteConsoleLine( PopupHandle, n++, " Frees is count of all frees", FALSE ); WriteConsoleLine( PopupHandle, n++, " ( ) difference in Frees column from last update", FALSE ); WriteConsoleLine( PopupHandle, n++, " Diff is (Allocs - Frees)", FALSE ); WriteConsoleLine( PopupHandle, n++, " Bytes is the total bytes consumed in pool", FALSE ); WriteConsoleLine( PopupHandle, n++, " ( ) difference in Bytes column from last update", FALSE ); WriteConsoleLine( PopupHandle, n++, " Per Alloc is (Bytes / Diff)", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " switches: ", FALSE ); WriteConsoleLine( PopupHandle, n++, " ? or h - gives this help", FALSE ); WriteConsoleLine( PopupHandle, n++, " q - quits", FALSE ); WriteConsoleLine( PopupHandle, n++, " p - toggles default pool display between both, paged, and nonpaged", FALSE ); WriteConsoleLine( PopupHandle, n++, " e - toggles totals lines on and off", FALSE ); WriteConsoleLine( PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " sorting switches:", FALSE ); WriteConsoleLine( PopupHandle, n++, " t - tag a - allocations", FALSE ); WriteConsoleLine( PopupHandle, n++, " f - frees d - difference", FALSE ); WriteConsoleLine( PopupHandle, n++, " b - bytes m - per alloc", FALSE ); WriteConsoleLine( PopupHandle, n++, " (u is the same as b)", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " ) - toggles sort between primary tag and value in ( )", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, " command line switches", FALSE ); WriteConsoleLine( PopupHandle, n++, " -i - list only matching tags", FALSE ); WriteConsoleLine( PopupHandle, n++, " -x - list everything except matching tags", FALSE ); WriteConsoleLine( PopupHandle, n++, " can include * and ?", FALSE ); WriteConsoleLine( PopupHandle, n++, " -peltafdbum) - as listed above", FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); WriteConsoleLine( PopupHandle, n++, NULL, FALSE ); while (TRUE) { if (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0 && ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) && InputRecord.EventType == KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown && InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE ) { break; } } SetConsoleActiveScreenBuffer( OutputHandle ); CloseHandle( PopupHandle ); return; }