Использование высокоуровневых функций ввода и вывода

Нижеследующий пример использует высокоуровневые консольные функции I/O для консольного ввода - вывода. Для получения дополнительной информации о высокоуровневых консольных функциях I/O, см. статью Высокоуровневый консольный ввод - вывод I/O).

В примере предполагается, что заданные по умолчанию режимы ввода - вывода (I/O) являются по существу вначале для первого вызова функций ReadFile и WriteFile. Затем для второго вызова ReadFile и WriteFile режим ввода данных изменяется, выключается режим построчного ввода данных и отраженный режим ввода данных. Функция SetConsoleTextAttribute используется для, установки цвета, которым впоследствии письменный текст будет показан на экране. Перед выходом, программа восстанавливает исходный консольный режим ввода данных и атрибуты цвета.

Функция NewLine примера используется тогда, когда отключается режим построчного ввода данных. Она обрабатывает возвраты каретки, перемещая позицию курсора в первую ячейку следующей строки. Если курсор находится уже в последней строке экранного буфера консоли, содержание экранного буфера консоли прокручивается вверх на одну строку.

Обратите внимание! на то, что MyErrorExit - групповой символ - заместитель для определяемой программой функции, которая показывает на экране и обрабатывает аварийные ситуации.

 
#include <windows.h>

void NewLine(void);
void ScrollScreenBuffer(HANDLE, INT);

HANDLE hStdout, hStdin;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

void main(void)
{
    LPSTR lpszPrompt1 = "Type a line and press Enter, or q to quit: ";
    LPSTR lpszPrompt2 = "Type any key, or q to quit: ";
    CHAR chBuffer[256];
    DWORD cRead, cWritten, fdwMode, fdwOldMode;
    WORD wOldColorAttrs;

    // Получим дескрипторы для STDIN и STDOUT.

    hStdin = GetStdHandle(STD_INPUT_HANDLE);
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, "GetStdHandle", "Console Error", MB_OK);
        return;
    }

    // Сохраним текущий цвет текста.

    if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
    {
        MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK);
        return;
    }

    wOldColorAttrs = csbiInfo.wAttributes;

    // Установим атрибуты текста которые пишут красный текст по черному фону.

    if (! SetConsoleTextAttribute(hStdout, FOREGROUND_RED|FOREGROUND_INTENSITY))
    {
        MessageBox(NULL, "SetConsoleTextAttribute", "Console Error", MB_OK);
        return;
    }

  // Запишем в STDOUT и прочитаем из STDIN, используя режим по умолчанию.
  // При вводе данных эхо-режим осуществляется автоматически, а функция ReadFile
  // не возвращает значения до тех пор, пока не напечатается каретка возврата.
  //
  // Режим ввода по умолчанию - построчный, обрабатываемый и эхо-режим.
  // Режим вывода по умолчанию - обрабатываемый и с автопереносом в конце строки EOL.

    while (1)
    {
        if (! WriteFile(
            hStdout,                    // дескриптор вывода
            lpszPrompt1,                // строка приглашения к вводу
            lstrlen(lpszPrompt1),       // длина строки
            &cWritten,                  // записано байтов
            NULL) )                     // не перекрывающееся
        {
            MessageBox(NULL, "WriteFile", "Console Error", MB_OK);
            return;
        }

        if (! ReadFile(
            hStdin,         // дескриптор ввода
            chBuffer,       // буфер для передачи
            255,            // размер буфера
            &cRead,         // действительно прочитанные байты
            NULL) )         // не перекрывающееся
        break;
        if (chBuffer[0] == 'q')
        break;
    }

    // Выключим построчный режим ввода и эхо-режим.

    if (! GetConsoleMode(hStdin, &fdwOldMode))
    {
        MessageBox(NULL, "GetConsoleMode", "Console Error", MB_OK);
        return;
    }

    fdwMode = fdwOldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);

    if (! SetConsoleMode(hStdin, fdwMode))
    {
        MessageBox(NULL, "SetConsoleMode", "Console Error", MB_OK);
        return;
    }

    // Без эхо-режима и построчного ввода, ReadFile возвращает значение,
    // когда доступен какой либо ввод данных. Возврат каретки должен
    // обрабатываться, а WriteFile используется в эхо-режиме для ввода данных.

    NewLine();

    while (1)
    {
        if (! WriteFile(
            hStdout,                      // дескриптор вывода
            lpszPrompt2,                  // строка приглашения к вводу
            lstrlen(lpszPrompt2),         // длина строки
            &cWritten,                    // записано байтов
            NULL) )                       // не перекрывающееся
        {
            MessageBox(NULL, "WriteFile", "Console Error", MB_OK);
            return;
        }

        if (! ReadFile(hStdin, chBuffer, 1, &cRead, NULL))
            break;
        if (chBuffer[0] == '\r')
            NewLine();
        else if (! WriteFile(hStdout, chBuffer, cRead,
            &cWritten, NULL))
            break;
        else
            NewLine();
        if (chBuffer[0] == 'q')
            break;
    }

    // Восстанавливаем исходный режим консоли.

    SetConsoleMode(hStdin, fdwOldMode);

    // Восстанавливаем исходный режим текста.

    SetConsoleTextAttribute(hStdout, wOldColorAttrs);
}

// Функция NewLine обрабатывает возврат каретки тогда, когда режим обработки
// вводимых данных отключается. Она получает текущую позицию курсора
// и сбрасывает ее до позиции первой ячейки следующей строки.

void NewLine(void)
{
    if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
    {
        MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK);
        return;
    }

    csbiInfo.dwCursorPosition.X = 0;

    // Если это последняя строка в буфере экрана, прокручивает буфер вверх.

    if ((csbiInfo.dwSize.Y-1) == csbiInfo.dwCursorPosition.Y)
    {
        ScrollScreenBuffer(hStdout, 1);
    }
// Иначе, продвигает вперед курсор к следующей строке

    else csbiInfo.dwCursorPosition.Y += 1;

    if (! SetConsoleCursorPosition(hStdout,
        csbiInfo.dwCursorPosition))
    {
        MessageBox(NULL, "SetConsoleCursorPosition", "Console Error", MB_OK);
        return;
    }
}

void ScrollScreenBuffer(HANDLE h, INT x)
{
    SMALL_RECT srctScrollRect, srctClipRect;
    CHAR_INFO chiFill;
    COORD coordDest;

    srctScrollRect.Left = 0;
    srctScrollRect.Top = 1;
    srctScrollRect.Right = csbiInfo.dwSize.X - x;
    srctScrollRect.Bottom = csbiInfo.dwSize.Y - x;
// Назначение для прямоугольника прокрутки - одна строка вверх
    coordDest.X = 0;
    coordDest.Y = 0;
// Прямоугольник отсечения по границам тот же самый, что и прокручивающийся прямоугольник.
// Строка назначения оставлена неизменной

    srctClipRect = srctScrollRect;
// Установим символ - заполнитель и атрибуты

    chiFill.Attributes = FOREGROUND_RED|FOREGROUND_INTENSITY;
    chiFill.Char.AsciiChar = ' ';

    // Прокрутим вверх на одну строку.

    ScrollConsoleScreenBuffer(
        h,               // дескриптор экранного буфера
        &srctScrollRect, // прямоугольник прокрутки
        &srctClipRect,   // прямоугольник отсечения
        coordDest,       // верхняя левая ячейка назначения
        &chiFill);       // символ-заполнитель и цвет
}

 

Назад в оглавление темы
На главную страницу темы

Hosted by uCoz