Часть четвертая. Разговор с самим собой.Оглавление
" Да,братец, ты и плодовит!
О чём угодно сочиняешь,-
То ты слащав, то ядовит,
И разным фаршем начиняешь
Свои стихи.
l_solntsev
В
прошлых частях мы создали пустую консольную программу и пришло время наконец оформить какой то ни было диалог.
Для начала попытаемся понять, что же такое консоль сама по себе и что ей надо для работы?
Окунёмся в дебри Windows и его API.
Умные люди из Микрософта
стырили у IBM сляпали операционную систему Windows, которая
в которой можно создавать консольные или GUI окна и обмениваться между ними сообщениями.
Что бы как то понимать какое сообщение какому окну принадлежит они придумаль уникальную метку
для каждого окна и обозвали её ХЭНДЛОМ (handle). Программисты всего мира долго
матерились чесали репу и наконец нашлись более умные люди которые обозвали хэндл дискриптором.
Тоже не понятная хрень, но программистам нравилось все новое обзывать непонятными словами.
И вот наконец то, однажды, появился человек, который ни фига не понял. Он то и обозвал хэндл
словом идентификатор. Так вот идентификаторы у разных окон (консольных или GUI или ещё там каких)
разные и именно по ним мы можем узнать от какого окна приходит сообщение или какому окну нам надо послать сообщение. Нулевой идентификатор принадлежит рабочему столу, остальные другим окнам. Так же они определили
номера и названия самих сообщений (надо же как то определить что мы хотим от окна или приложения в данный момент). Так для консоли, основные идентификаторы сообщений следующие:
STD_INPUT_HANDLE - стандартный ввод
STD_OUTPUT_HANDLE - стандартный вывод
STD_ERROR_HANDLE - стандартное сообщение об ошибках
Ну вот теперь на основании наших знаний мы можем приступить к созданию стандартной консольной библиотеки.
Для начала нам надо добавить в нашу папку пару файлов. Сразу оговорюсь по названию файлов.
Я не лисапедист и не любитель изобретать лисапеды, по этому имена файлов будут стандартно скопированы
из других языков программирования.
Итак делаем файлы
Console.Mod и
Windows.Mod что бы наша папка приобрела похожий вид
Теперь договоримся что в файл
Windows.Mod мы будем собирать и прописывать все платформо зависимые процедуры
и переменные а так же константы, на то он так и называется. Луноходы могут обозвать его например
Linux.Mod и делать абсолютно похожее. (к стати кто хочет компилировать под линукс
мы можем обсудить изменение линкёра для этого в отдельной ветке).
Теперь мы можем код запуска сборщика мусора перенести в файл
Windows.Modи создать одну константу, которая нам потом пригодится.
Код: "OBERON"
MODULE Windows;
IMPORT
SYSTEM, Kernel;
CONST
NULL* = 0;
BEGIN
IF Kernel.call = 0 THEN
INC(Kernel.call);
Kernel.Init();
ELSIF Kernel.ExitProc # NIL THEN
Kernel.Shutdown(0);
END;
END Windows.
Остальные файлы приобретут следующий вид
Console.ModКод: "OBERON"
MODULE Console;
IMPORT
Windows, SYSTEM;
BEGIN
END Console.
Program1.ModКод: "OBERON"
MODULE Program1;
IMPORT
Console;
BEGIN
END Program1.
и
CompileAndLink.batКод: "BAT"
Bin\O2ETHCLC.EXE Windows.mod
Bin\O2ETHCLC.EXE Console.mod
Bin\O2ETHCLC.EXE Program1.mod
Bin\O2ETHCLL.EXE Program1.Link
pause
Теперь после компилирования нашего кода мы получим практически то же самое пустое приложение,
необходимо только немного подправить строчку в
Program1.LinkКод: "LINK"
MODULES
Kernel, Windows, Console, Program1
то есть подключить их в порядке компилирования модулей.
Теперь давайте вернёмся к началу нашей части и вспомним, какие константы и переменные нам нужны для
отправки и приёма сообщений консоли.
STD_INPUT_HANDLE,
STD_OUTPUT_HANDLE,
STD_ERROR_HANDLEДавайте запишим их в наш файл
Windows.Mod а так же пару-тройку типов
которые так же нам пригодятся для дальнейшей работы
Код: "OBERON"
CONST
NULL* = 0;
STD_INPUT_HANDLE* = -10;
STD_OUTPUT_HANDLE* = -11;
STD_ERROR_HANDLE* = -12;
TYPE
BOOL* = LONGINT;
ADDRESS* = LONGINT;
ATOM* = INTEGER;
HANDLE* = ADDRESS;
HMODULE* = ADDRESS;
HINSTANCE* = ADDRESS;
HGLOBAL* = HANDLE;
LPSTR* = ADDRESS;
Звездочки после переменных и типов(да и вообще везде) означают доступность переменной, константы или функции остальным модулям подключающими данный.
Что бы ввод и ввывод работал, нам необходимо добавить в Windows.Mod описание нескольких API
функций операционной системы
AllocConsole,GetStdHandle,WriteFile,ReadFile, вот их описание
Код: "TEXT"
Функция AllocConsole назначает новую консоль для вызывающего процесса.
Функция GetStdHandle извлекает дескриптор для стандартного ввода данных,
стандартного вывода или стандартной ошибки устройства.
Функция WriteFile пишет данные в файл с места, обозначенного указателем позиции в файле.
Функция ReadFile читает данные из файла, начиная с позиции, обозначенной указателем файла.
Подробное описание можно найти в интернете или специализированной литературе.
Вот так добавляются импортные функции в Обероне
Код: "OBERON"
VAR
AllocConsole- : PROCEDURE [WINAPI] (): BOOL;
GetStdHandle- : PROCEDURE [WINAPI] (nStdHandle: LONGINT): HANDLE;
WriteFile- : PROCEDURE [WINAPI] (hFile: HANDLE; VAR lpBuffer: ARRAY [NOTAG] OF SYSTEM.BYTE;
nNumberOfBytesToWrite: LONGINT; VAR lpNumberOfBytesWritten: LONGINT; lpOverlapped: SYSTEM.PTR): BOOL;
ReadFile- : PROCEDURE [WINAPI] (hFile: HANDLE; VAR lpBuffer: ARRAY [NOTAG] OF SYSTEM.BYTE;
nNumberOfBytesToRead: LONGINT; VAR lpNumberOfBytesRead: LONGINT; lpOverlapped: SYSTEM.PTR): BOOL;
[
WINAPI] - означает вызов переменных для функции
через жопу в обратном порядке, что то вроде
stdcall.
[
C] в Си стиле.
[
NOTAG] - без выравнивания.
А минусик перед процедурами - только для чтения.
Ну вот, сформировав и дополнив
Windows.Mod мы можем перейти к файлу
Console.Mod где и пропишим обертку
для вызовов API функций системы.
Для начала нам надо инициализировать нашу консоль, а именно
Код: "OBERON"
VAR
hin, hout: Windows.HANDLE;
...............
BEGIN
hin := Windows.GetStdHandle(Windows.STD_INPUT_HANDLE);
hout:= Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE);
END Console.
В переменные мы записываем дискрипторы стандартного ввода и вывода
А вот так делаем вывод сообщения
Код: "OBERON"
PROCEDURE Length*(str:ARRAY OF CHAR): LONGINT;
VAR
n,i,c:LONGINT;
BEGIN
n:=LEN(str);
i:=0;
WHILE (i<n) & (str[i]>0X) DO INC(i); END;
RETURN i;
END Length;
PROCEDURE WriteString*(str:ARRAY OF CHAR);
VAR
n,i,c:LONGINT;
BEGIN
n:=Length(str);
SYSTEM.PUTREG(0, Windows.WriteFile(hout, str, n, n, NIL));
END WriteString;
Если далее развивать библиотеку для Оберона то нам понадобится функции преобразования числовых
в строковые значения, конвертации OEM и многие другие. Этим мы займемся в
следующей части а
пока я прикрепляю модули для комфортной работы в консоли.
В русской консоли!
Вложение:
Комментарий к файлу: Пример консоли
Console.zip [8.58 КБ]
Скачиваний: 773