]>Русские буквы в консоли FreeBASIC

Русские буквы и кириллица в консоли FreeBASIC

Аватар пользователя mabu

В самом начале работы с компилятором новички сталкиваются с проблемой: FreeBASIC не умеет выводить и вводить с консоли русские буквы. Если с выводом кириллицы можно обойтись стандартными средствами, то с вводом без WinAPI не обойтись. Разберём все средства подробно.

  1. Внутреннее устройство строк
  2. Правильный вывод юникодных строк
    1. Вывод через функцию Print
    2. Вывод строк через функцию WriteConsole
  3. Ввод юникодных строк
    1. Функция ReadConsole

Внутреннее устройство строк

FreeBASIC поддерживает три типа строк: ZString, WString и «обычные» String. Каждый тип имеет свои особенности.

ZString представляет собой массив символов, заканчивающийся нулевым байтом. Размер символа SizeOf(ZString) составляет один байт. Для WinAPI — это ANSI строка.

WString аналогична ZString, но размер символа SizeOf(WString) здесь представляет два байта. Строка также оканчивается нулевым символом, в данном случае двумя нулевыми байтами. Для WinAPI — это UNICODE строка.

String представляет собой структуру из трёх полей: строка типа ZString, длина строки в символах и количество выделенных байт памяти. Как видно из внутреннего устройства, эта строка не может содержать в себе юникодные символы.

Несмотря на то, что тип String наиболее удобен в использовании, с его помощью нельзя вводить и выводить юникодные строки. Для этих целей необходимо использовать строки типа WString, хотя работать с ними не настолько легко.

Правильный вывод юникодных строк

Вывод через функцию Print

Для вывода русских букв на консоль достаточно двух условий.

  1. Для строк необходимо использовать тип WString.
  2. Исходный код необходимо сохранять в кодировке UTF-8 или UTF-16. Если используется редактор FBEdit — то UTF-16. В этом случае все строковые литералы будут сохраняться как строки типа WString.

Теперь можно использовать встроенную функцию Print, и русские буквы будут корректно отображаться, без кракозябр:

Код FreeBASIC
' Можно так
Print "Привет, мир!"

' А лучше так
Const HelloWorld = "Привет, мир!"
Print HelloWorld

Вывод строк через функцию WriteConsole

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

Объявив константу «unicode», мы даём указание компилятору использовать WinAPI‐функции с буквой W на конце:

Код FreeBASIC
#define unicode
#include once "windows.bi"

Определение константы UNICODE необходимо ставить до подключения заголовочного файла windows.bi.

Эти три условия являются обязательными для дальнейшей работы.

В качестве альтернативы рассмотрим вывод строк без встроенных функций, используя чистые WinAPI. Для этого есть высокоуровневая функция WriteConsole. Функция записывает в текущую позицию курсора консоли строку, позиция курсора продвигается вперёд, по мере написания символов. Вот её определение из заголовочных файлов:

Код FreeBASIC
Declare Function WriteConsole Alias "WriteConsoleW"( _
&t;ByVal hConsoleOutput As HANDLE, _
&t;ByVal lpBuffer As Const Any Ptr, _
&t;ByVal nNumberOfCharsToWrite As DWORD, _
&t;ByVal lpNumberOfCharsWritten As LPDWORD, _
&t;ByVal lpReserved As LPVOID _
) As WINBOOL

Параметры

hConsoleOutput
Описатель стандартного потока вывода консоли.
lpBuffer
Указатель на выводимую строку. Длина строки должна быть меньше, чем 32000 символов.
nNumberOfCharsToWrite
Длина выводимой строки в символах.
IpNumberOfCharsWritten
Указатель на переменную, куда будет записано количество действительно выведенных символов.
lpReserved
Зарезервировано, должно быть 0.

Возвращаемое значение

Если функция завершается успешно, величина возвращаемого значения — не ноль. Если функция завершается с ошибкой, величина возвращаемого значения — ноль.

Описание

Функция WriteConsole записывает символы в экранный буфер консоли в текущей позиции курсора. Позиция курсора продвигается вперед, по мере отображения символов. После своей работы функция не переносит курсор на начало новой строки, необходимо самостоятельно добавлять к строке символы CrLf или выводить их отдельным вызовом функции. Также функция завершается ошибкой, если вывод программы перенаправлен, например, в файл или трубу. Для перенаправленного вывода нужно использовать функцию WriteFile, которая имеет аналогичные параметры.

Пример

Код FreeBASIC
#define unicode
#include "windows.bi"

' Строка с русскими буквами и символами CrLf для вывода на консоль
Const Hello = !"Привет, мир!\r\n"

' Получить дескриптор вывода, необходим
Dim OutHandle As HANDLE = GetStdHandle(STD_OUTPUT_HANDLE)

' В эту переменную будет записано количество символов, которое было выведено, оно может быть меньше или равно длине выводимой строки
Dim intSymbolsCount As DWORD = Any

If WriteConsole(OutHandle, @Hello, Len(Hello), @intSymbolsCount, 0) <> 0 Then
    ' Ошибок нет
End If

Ввод юникодных строк

Встроенная функция Input не работает с юникодом. Для выхода их этого положения придётся использовать следующую комбинацию:

Функция ReadConsole

Читает символьный ввод данных из консоли.

Код FreeBASIC
Declare Function ReadConsole Alias "ReadConsoleW"( _
&t;ByVal hConsoleInput As HANDLE, _
&t;ByVal lpBuffer As LPVOID, _
&t;ByVal nNumberOfCharsToRead As DWORD, _
&t;ByVal lpNumberOfCharsRead As LPDWORD, _
&t;ByVal lpReserved As LPVOID) _
As WINBOOL

Параметры

hConsolelnput
Описатель стандартного потока ввода консоли.
IpBuffer
Указатель на буфер, в который будет записана вводимая строка символов.
nNumberOfCharsToRead
Количество символов для чтения с консоли. Должно быть не больше размера буфера.
ipNumberOfCharsRead
Указатель на переменную, куда будет записано количество действительно введённых символов.
lpReserved
Зарезервировано, должно быть 0.

Возвращаемое значение

Если функция завершается успешно, величина возвращаемого значения — не ноль. Если функция завершается с ошибкой, величина возвращаемого значения — ноль.

Описание

Функция ReadConsole читает ввод информации с клавиатуры из консоли. В этот момент пользователь может вводить символы с клавиатуры. Когда пользователь нажимает на Enter, то тем самым завершает ввод. Функция заполняет буфер полученной строкой вместе с символами CrLf. Если размер буфера меньше, чем длина введённой пользователем строки, то функция поместит в буфер всё, что влезло, а остальную часть строки вернёт при следующем вызове функции.

Таким образом, если функция заполнила буфер, но в нём нет символов CrLf, то необходимо ещё раз прочитать данные из консоли, до тех пор, пока на конце не встретятся символы CrLf, или функция не вернёт ошибку.

Убрать символы CrLf из строки можно так:

Код FreeBASIC
Buffer[intSymbolsCount - 2] = 0

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

Пример

Код FreeBASIC
#define unicode
#include "windows.bi"

Const BufferLength As DWORD = 4096 - 1
' Буфер для строки длиной 4096 символов, этого должно хватить для обычных операций ввода (+1 символ на нулевой)
Dim Buffer As WString * (BufferLength + 1) = Any

' Идентификатор вывода
Dim InHandle As HANDLE = GetStdHandle(STD_INPUT_HANDLE)

' В эту переменную будет записано фактическое количество введённых символов
Dim intSymbolsCount As DWORD = Any

' Печатаем приглашение для ввода
Print "Введи строку"

If ReadConsole(InHandle, @Buffer, BufferLength, @intSymbolsCount, 0) <> 0 Then
    ' Ошибок нет
End If

Поделись ссылочкой в социальных сетях