static void erase_till_end_of_screen(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; COORD pos; DWORD dummy; if (!console) return; GetConsoleScreenBufferInfo(console, &sbi); FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, &dummy); FillConsoleOutputAttribute(console, plain_attr, sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, &dummy); pos.X = 0; for (pos.Y = sbi.dwCursorPosition.Y+1; pos.Y < sbi.dwSize.Y; pos.Y++) { FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X, pos, &dummy); FillConsoleOutputAttribute(console, plain_attr, sbi.dwSize.X, pos, &dummy); } }
bool CHaloPrintStream::Write(const std::wstring& str)// str usually has endl appended { if (str.size() == 0) return true; bool ready = *(bool*)UlongToPtr(ADDR_CONSOLEREADY); if (!ready) { std::wcout << str; return true; } // Prepare for writing the string HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); DWORD written = 0; CONSOLE_SCREEN_BUFFER_INFO info; SHORT oldX = 0; // used to set cursor back to old position // Get current console position info GetConsoleScreenBufferInfo(hConsole, &info); oldX = info.dwCursorPosition.X; // Set cursor to start of the last row (where we want to start writing) info.dwCursorPosition.X = 0; info.dwCursorPosition.Y = 299; SetConsoleCursorPosition(hConsole, info.dwCursorPosition); FillConsoleOutputCharacterA(hConsole, ' ', 95, info.dwCursorPosition, &written); FillConsoleOutputAttribute(hConsole, 7, 95, info.dwCursorPosition, &written); // Write the text WriteConsoleW(hConsole, str.c_str(), str.size(), &written, NULL); //WriteConsoleW(hConsole, L"\n", 1, &written, NULL); // Get the current text in the console LPBYTE ptr = (LPBYTE)ADDR_CONSOLEINFO; if (*ptr != 0) { // Build current command input std::string formatted = "halo( "; formatted += (char*)UlongToPtr(*(DWORD*)ptr + OFFSET_CONSOLETEXT); // current text // Rewrite the data to console GetConsoleScreenBufferInfo(hConsole, &info); FillConsoleOutputCharacterA(hConsole, ' ', 95, info.dwCursorPosition, &written); WriteConsoleOutputCharacterA(hConsole, formatted.c_str(), formatted.size(), info.dwCursorPosition, &written); // Set the cursor to its old position GetConsoleScreenBufferInfo(hConsole, &info); info.dwCursorPosition.X = oldX; SetConsoleCursorPosition(hConsole, info.dwCursorPosition); } return true; }
bool Console::handleCommand( String command ) { if (command == String("exit", 4)) { TerminateThread((HANDLE)serverThread, 0); return false; } else if (command == String("reload", 6)) { if (settings.reload("server.xml")) { printf("Settings successfully reloaded\n"); } else { printf("Failed to reload settings\n"); } } else if (command == String("clear", 5)) { HANDLE hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); DWORD hWrittenChars = 0; CONSOLE_SCREEN_BUFFER_INFO strConsoleInfo; COORD Home = {0, 0}; GetConsoleScreenBufferInfo(hConsoleHandle, &strConsoleInfo); FillConsoleOutputCharacterA(hConsoleHandle, ' ', strConsoleInfo.dwSize.X * strConsoleInfo.dwSize.Y, Home, &hWrittenChars); SetConsoleCursorPosition(hConsoleHandle, Home); } else { printf("Unknown command\n"); } return true; }
static void putchxyattrwh(int x, int y, int ch, int attr, int w, int h) { HANDLE con; COORD c; int i; if (x<ti.winleft) w -= ti.winleft - x; if (y<ti.wintop) h -= ti.wintop - y; if (x + w - 1>ti.winright) w = ti.winright - x + 1; if (y + h - 1>ti.winbottom) h = ti.winbottom - y + 1; if (w <= 0 || h <= 0) return; con = GetStdHandle(STD_OUTPUT_HANDLE); for (i = 0; i<h; ++i) { DWORD written; c.X = x - 1; c.Y = y - 1 + i; FillConsoleOutputAttribute(con, attr, w, c, &written); FillConsoleOutputCharacterA(con, ch, w, c, &written); } }
static VOID DrawScrollBarGenericList( PGENERIC_LIST GenericList) { COORD coPos; DWORD Written; coPos.X = GenericList->Right + 1; coPos.Y = GenericList->Top; if (GenericList->FirstShown != GenericList->ListHead.Flink) { FillConsoleOutputCharacterA (StdOutput, '\x18', 1, coPos, &Written); } else { FillConsoleOutputCharacterA (StdOutput, ' ', 1, coPos, &Written); } coPos.Y = GenericList->Bottom; if (GenericList->LastShown != GenericList->ListHead.Blink) { FillConsoleOutputCharacterA (StdOutput, '\x19', 1, coPos, &Written); } else { FillConsoleOutputCharacterA (StdOutput, ' ', 1, coPos, &Written); } }
void AttachToRLLog::readLatest() { if (consoleConnected) { CONSOLE_SCREEN_BUFFER_INFO console_buffer_info = {0}; if (GetConsoleScreenBufferInfo(hConsole, &console_buffer_info)) { COORD screenBufferSize = console_buffer_info.dwSize; COORD curserLoc = console_buffer_info.dwCursorPosition; // special case to clear console once curser reaches max screen buffer size if (curserLoc.Y == screenBufferSize.Y - 1) { COORD topLeft = { 0, 10 }; DWORD written; FillConsoleOutputCharacterA( hConsole, ' ', screenBufferSize.X * screenBufferSize.Y, topLeft, &written ); FillConsoleOutputAttribute( hConsole, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE, screenBufferSize.X * screenBufferSize.Y, topLeft, &written ); SetConsoleCursorPosition(hConsole, topLeft); curserLoc = topLeft; linesRead = 9; } // begin actually reading lines int readToLine = curserLoc.Y; int readFromLine = linesRead; int linesToReadNow = readToLine - readFromLine; if (linesToReadNow > 0) { CHAR_INFO buffer[screenBufferSize.X * linesToReadNow]; COORD buffer_size = { screenBufferSize.X, linesToReadNow}; COORD buffer_index = { 0, 0 }; SMALL_RECT read_region = { 0, readFromLine, screenBufferSize.X - 1, readToLine}; if (!ReadConsoleOutputA(hConsole, buffer, buffer_size, buffer_index, &read_region)) { std::cout << "Error reading console output " << GetLastError() << std::endl; } // iterate lines for (int i = 0; i < linesToReadNow; i++) { std::string line = ""; // iterate characters in line for (int j = 0; j < screenBufferSize.X - 1; j++) { line+= buffer[i * screenBufferSize.X + j].Char.AsciiChar; } //std::cout << line << std::endl; emit newLineFound(line); } linesRead = readToLine; } } else { std::wcout << L"Could not get ScreenBufferInfo, last error: " << GetLastError() << std::endl; } } }
static VOID DrawProgressBar( IN PPROGRESSBAR Bar) { COORD coPos; DWORD Written; PROGRESSBAR BarBorder = *Bar; CHAR TextBuffer[256]; /* Draw the progress bar "border" border */ if (Bar->DoubleEdge) { BarBorder.Top -= 5; BarBorder.Bottom += 2; BarBorder.Right += 5; BarBorder.Left -= 5; DrawThickBorder(&BarBorder); } /* Draw the progress bar border */ DrawBorder(Bar); /* Display the description text */ if (Bar->DescriptionText) CONSOLE_SetTextXY(Bar->TextTop, Bar->TextRight, Bar->DescriptionText); /* Always update and display the progress */ if (Bar->UpdateProgressProc && Bar->UpdateProgressProc(Bar, TRUE, TextBuffer, ARRAYSIZE(TextBuffer))) { coPos.X = Bar->Left + (Bar->Width - strlen(TextBuffer) + 1) / 2; coPos.Y = Bar->Top; WriteConsoleOutputCharacterA(StdOutput, TextBuffer, strlen(TextBuffer), coPos, &Written); } /* Draw the empty bar */ coPos.X = Bar->Left + 1; for (coPos.Y = Bar->Top + 2; coPos.Y <= Bar->Bottom - 1; coPos.Y++) { FillConsoleOutputAttribute(StdOutput, Bar->ProgressColour, Bar->Width - 2, coPos, &Written); FillConsoleOutputCharacterA(StdOutput, ' ', Bar->Width - 2, coPos, &Written); } }
static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) { char seq[64]; #ifdef _WIN32 DWORD pl, bl, w; CONSOLE_SCREEN_BUFFER_INFO b; COORD coord; #endif size_t plen = strlen(prompt); while((plen+pos) >= cols) { buf++; len--; pos--; } while (plen+len > cols) { len--; } #ifndef _WIN32 /* Cursor to left edge */ snprintf(seq,64,"\x1b[0G"); if (write(fd,seq,strlen(seq)) == -1) return; /* Write the prompt and the current buffer content */ if (write(fd,prompt,strlen(prompt)) == -1) return; if (write(fd,buf,len) == -1) return; /* Erase to right */ snprintf(seq,64,"\x1b[0K"); if (write(fd,seq,strlen(seq)) == -1) return; /* Move cursor to original position. */ snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen)); if (write(fd,seq,strlen(seq)) == -1) return; #else REDIS_NOTUSED(seq); REDIS_NOTUSED(fd); /* Get buffer console info */ if (!GetConsoleScreenBufferInfo(hOut, &b)) return; /* Erase Line */ coord.X = 0; coord.Y = b.dwCursorPosition.Y; FillConsoleOutputCharacterA(hOut, ' ', b.dwSize.X, coord, &w); /* Cursor to the left edge */ SetConsoleCursorPosition(hOut, coord); /* Write the prompt and the current buffer content */ WriteConsole(hOut, prompt, (DWORD)plen, &pl, NULL); WriteConsole(hOut, buf, (DWORD)len, &bl, NULL); /* Move cursor to original position. */ coord.X = (int)(pos+plen); coord.Y = b.dwCursorPosition.Y; SetConsoleCursorPosition(hOut, coord); #endif }
void SnakeAPI::putChar(char ch, int left, int top) { if (top == CURRENT_CURSOR) { left = whereX(); top = whereY(); } COORD coord = {left, top}; DWORD cCharsWritten; FillConsoleOutputCharacterA(hSnakeAPI, ch, 1, coord, &cCharsWritten); }
static void erase_in_line(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; DWORD dummy; /* Needed for Windows 7 (or Vista) regression */ if (!console) return; GetConsoleScreenBufferInfo(console, &sbi); FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, &dummy); }
VOID DrawFileSystemList( IN PFILE_SYSTEM_LIST List) { PLIST_ENTRY ListEntry; PFILE_SYSTEM_ITEM Item; COORD coPos; DWORD Written; ULONG Index = 0; CHAR Buffer[70]; ListEntry = List->ListHead.Flink; while (ListEntry != &List->ListHead) { Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry); coPos.X = List->Left; coPos.Y = List->Top + (SHORT)Index; FillConsoleOutputAttribute(StdOutput, FOREGROUND_WHITE | BACKGROUND_BLUE, sizeof(Buffer), coPos, &Written); FillConsoleOutputCharacterA(StdOutput, ' ', sizeof(Buffer), coPos, &Written); if (Item->FileSystemName) { if (Item->QuickFormat) snprintf(Buffer, sizeof(Buffer), MUIGetString(STRING_FORMATDISK1), Item->FileSystemName); else snprintf(Buffer, sizeof(Buffer), MUIGetString(STRING_FORMATDISK2), Item->FileSystemName); } else snprintf(Buffer, sizeof(Buffer), MUIGetString(STRING_KEEPFORMAT)); if (ListEntry == &List->Selected->ListEntry) CONSOLE_SetInvertedTextXY(List->Left, List->Top + (SHORT)Index, Buffer); else CONSOLE_SetTextXY(List->Left, List->Top + (SHORT)Index, Buffer); Index++; ListEntry = ListEntry->Flink; } }
void scroll_to_top(CONSOLE_SCREEN_BUFFER_INFO &csbi) { COORD topLeft = { 0, 0 }; HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD written; GetConsoleScreenBufferInfo(hConsoleOut, &csbi); FillConsoleOutputCharacterA(hConsoleOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, topLeft, &written); FillConsoleOutputAttribute(hConsoleOut, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y, topLeft, &written); SetConsoleCursorPosition(hConsoleOut, topLeft); }
void linenoiseClearScreen(void) { #ifdef _WIN32 COORD coord = {0, 0}; CONSOLE_SCREEN_BUFFER_INFO inf; DWORD count; DWORD size; GetConsoleScreenBufferInfo(console_out, &inf); size = inf.dwSize.X * inf.dwSize.Y; FillConsoleOutputCharacterA(console_out, ' ', size, coord, &count ); SetConsoleCursorPosition(console_out, coord); #else if (write(1,"\x1b[H\x1b[2J",7) <= 0) { /* nothing to do, just to avoid warning. */ } #endif }
void SnakeAPI::clear(bool clearAttribute, char ch) { getInfo(); DWORD cCharsWritten; DWORD size = CSBI.dwSize.X * CSBI.dwSize.Y; COORD coord = {0, 0}; FillConsoleOutputCharacterA(hSnakeAPI, ch, size, coord, &cCharsWritten); int attrib = CSBI.wAttributes; if (clearAttribute) attrib = LIGHTGRAY; FillConsoleOutputAttribute(hSnakeAPI, attrib, size, coord, &cCharsWritten); SetConsoleCursorPosition(hSnakeAPI, coord); getInfo(); }
void IOConsole::ClearConsole(void) { COORD topLeft = { 0, 0 }; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; DWORD written; GetConsoleScreenBufferInfo(m_hOutput, &screen); FillConsoleOutputCharacterA( m_hOutput, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); FillConsoleOutputAttribute( m_hOutput, FOREGROUND_RED, screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); SetConsoleCursorPosition(m_hOutput, topLeft); }
static VOID DrawBorder( IN PPROGRESSBAR Bar) { COORD coPos; DWORD Written; SHORT i; /* draw upper left corner */ coPos.X = Bar->Left; coPos.Y = Bar->Top + 1; FillConsoleOutputCharacterA(StdOutput, 0xDA, // '+', 1, coPos, &Written); /* draw upper edge */ coPos.X = Bar->Left + 1; coPos.Y = Bar->Top + 1; FillConsoleOutputCharacterA(StdOutput, 0xC4, // '-', Bar->Right - Bar->Left - 1, coPos, &Written); /* draw upper right corner */ coPos.X = Bar->Right; coPos.Y = Bar->Top + 1; FillConsoleOutputCharacterA(StdOutput, 0xBF, // '+', 1, coPos, &Written); /* draw left and right edge */ for (i = Bar->Top + 2; i < Bar->Bottom; i++) { coPos.X = Bar->Left; coPos.Y = i; FillConsoleOutputCharacterA(StdOutput, 0xB3, // '|', 1, coPos, &Written); coPos.X = Bar->Right; FillConsoleOutputCharacterA(StdOutput, 0xB3, //'|', 1, coPos, &Written); } /* draw lower left corner */ coPos.X = Bar->Left; coPos.Y = Bar->Bottom; FillConsoleOutputCharacterA(StdOutput, 0xC0, // '+', 1, coPos, &Written); /* draw lower edge */ coPos.X = Bar->Left + 1; coPos.Y = Bar->Bottom; FillConsoleOutputCharacterA(StdOutput, 0xC4, // '-', Bar->Right - Bar->Left - 1, coPos, &Written); /* draw lower right corner */ coPos.X = Bar->Right; coPos.Y = Bar->Bottom; FillConsoleOutputCharacterA(StdOutput, 0xD9, // '+', 1, coPos, &Written); }
static VOID DrawListEntries( PGENERIC_LIST GenericList) { PGENERIC_LIST_ENTRY ListEntry; PLIST_ENTRY Entry; COORD coPos; DWORD Written; USHORT Width; coPos.X = GenericList->Left + 1; coPos.Y = GenericList->Top + 1; Width = GenericList->Right - GenericList->Left - 1; Entry = GenericList->FirstShown; while (Entry != &GenericList->ListHead) { ListEntry = CONTAINING_RECORD (Entry, GENERIC_LIST_ENTRY, Entry); if (coPos.Y == GenericList->Bottom) break; GenericList->LastShown = Entry; FillConsoleOutputAttribute (StdOutput, (GenericList->CurrentEntry == ListEntry) ? FOREGROUND_BLUE | BACKGROUND_WHITE : FOREGROUND_WHITE | BACKGROUND_BLUE, Width, coPos, &Written); FillConsoleOutputCharacterA (StdOutput, ' ', Width, coPos, &Written); coPos.X++; WriteConsoleOutputCharacterA (StdOutput, ListEntry->Text, min (strlen(ListEntry->Text), (SIZE_T)Width - 2), coPos, &Written); coPos.X--; coPos.Y++; Entry = Entry->Flink; } while (coPos.Y < GenericList->Bottom) { FillConsoleOutputAttribute (StdOutput, FOREGROUND_WHITE | BACKGROUND_BLUE, Width, coPos, &Written); FillConsoleOutputCharacterA (StdOutput, ' ', Width, coPos, &Written); coPos.Y++; } }
static VOID DrawListFrame( PGENERIC_LIST GenericList) { COORD coPos; DWORD Written; SHORT i; /* Draw upper left corner */ coPos.X = GenericList->Left; coPos.Y = GenericList->Top; FillConsoleOutputCharacterA (StdOutput, 0xDA, // '+', 1, coPos, &Written); /* Draw upper edge */ coPos.X = GenericList->Left + 1; coPos.Y = GenericList->Top; FillConsoleOutputCharacterA (StdOutput, 0xC4, // '-', GenericList->Right - GenericList->Left - 1, coPos, &Written); /* Draw upper right corner */ coPos.X = GenericList->Right; coPos.Y = GenericList->Top; FillConsoleOutputCharacterA (StdOutput, 0xBF, // '+', 1, coPos, &Written); /* Draw left and right edge */ for (i = GenericList->Top + 1; i < GenericList->Bottom; i++) { coPos.X = GenericList->Left; coPos.Y = i; FillConsoleOutputCharacterA (StdOutput, 0xB3, // '|', 1, coPos, &Written); coPos.X = GenericList->Right; FillConsoleOutputCharacterA (StdOutput, 0xB3, //'|', 1, coPos, &Written); } /* Draw lower left corner */ coPos.X = GenericList->Left; coPos.Y = GenericList->Bottom; FillConsoleOutputCharacterA (StdOutput, 0xC0, // '+', 1, coPos, &Written); /* Draw lower edge */ coPos.X = GenericList->Left + 1; coPos.Y = GenericList->Bottom; FillConsoleOutputCharacterA (StdOutput, 0xC4, // '-', GenericList->Right - GenericList->Left - 1, coPos, &Written); /* Draw lower right corner */ coPos.X = GenericList->Right; coPos.Y = GenericList->Bottom; FillConsoleOutputCharacterA (StdOutput, 0xD9, // '+', 1, coPos, &Written); }
VOID ProgressSetStep( IN PPROGRESSBAR Bar, IN ULONG Step) { COORD coPos; DWORD Written; ULONG NewPos; CHAR TextBuffer[256]; if (Step > Bar->StepCount) return; Bar->CurrentStep = Step; /* Update the progress and redraw it if it has changed */ if (Bar->UpdateProgressProc && Bar->UpdateProgressProc(Bar, FALSE, TextBuffer, ARRAYSIZE(TextBuffer))) { coPos.X = Bar->Left + (Bar->Width - strlen(TextBuffer) + 1) / 2; coPos.Y = Bar->Top; WriteConsoleOutputCharacterA(StdOutput, TextBuffer, strlen(TextBuffer), coPos, &Written); } /* Calculate the bar position */ NewPos = (((Bar->Width - 2) * 2 * Bar->CurrentStep + (Bar->StepCount / 2)) / Bar->StepCount); /* Redraw the bar if it has changed */ if (Bar->Pos != NewPos) { Bar->Pos = NewPos; for (coPos.Y = Bar->Top + 2; coPos.Y <= Bar->Bottom - 1; coPos.Y++) { coPos.X = Bar->Left + 1; FillConsoleOutputCharacterA(StdOutput, 0xDB, Bar->Pos / 2, coPos, &Written); coPos.X += Bar->Pos / 2; if (NewPos & 1) { FillConsoleOutputCharacterA(StdOutput, 0xDD, 1, coPos, &Written); coPos.X++; } if (coPos.X <= Bar->Right - 1) { FillConsoleOutputCharacterA(StdOutput, ' ', Bar->Right - coPos.X, coPos, &Written); } } } }
// Internal thread for updating the console. void lConsole::Int_UpdateThread() { static std::chrono::milliseconds UpdateDelay(500); while (true) { // Delay so we don't waste time updating. std::this_thread::sleep_for(UpdateDelay); // If we have a stream handle. if (StreamHandle == nullptr || !ShouldPrintScrollback) continue; // Clear the console. #ifdef _WIN32 // Aparently system("cls") is bad practice as it spawns a shell. COORD topLeft = { 0, 0 }; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; DWORD written; GetConsoleScreenBufferInfo(console, &screen); FillConsoleOutputCharacterA( console, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); FillConsoleOutputAttribute( console, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE, screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); SetConsoleCursorPosition(console, topLeft); #else // But nix can use ANSI escapecodes. // CSI[2J to clear the console. // CSI[H to reset the cursor. fprintf(stdout, "\x1B[2J\x1B[H"); #endif // Save the old color settings. static CONSOLE_SCREEN_BUFFER_INFO OldTextColor; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &OldTextColor); // For each line in the scrollback. ThreadSafe.lock(); for (uint32_t i = 0; i < ScrollbackLineCount; ++i) { // Set the output strings color. SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), CompatibleRGBA(ScrollbackLines[i].RGBA)); // Search the string for progress bars. for (uint32_t c = 0; c < ProgressbarCount; ++c) { if (strstr(ScrollbackLines[i].String, Progressbars[c].ProgressToken)) { static char ProgressBuffer[257]; memset(ProgressBuffer, 0, 257); // Create the buffer. for (int32_t k = 0; k < (int32_t)min(INT32_MAX, strlen(ScrollbackLines[i].String)) - 1; ++k) { // Copy all the characters up until the token. if (ScrollbackLines[i].String[k + 0] == Progressbars[c].ProgressToken[0] && ScrollbackLines[i].String[k + 1] == Progressbars[c].ProgressToken[1]) { ProgressBuffer[k] = ScrollbackLines[i].String[k]; } else { // Copy the progress bar into the buffer. // TODO: Use the bar type. strcpy(&ProgressBuffer[c], GetProgress(0, Progressbars[c].CurrentValue, Progressbars[c].EndValue)); break; } } // Print the formated buffer. printf(ProgressBuffer); printf("\n"); goto LABEL_PRINT_DONE; } } // Print the string since there's no progress bar. printf(ScrollbackLines[i].String); printf("\n"); LABEL_PRINT_DONE:; } // Reset the color. SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), OldTextColor.wAttributes); ThreadSafe.unlock(); } }