Проста консольна програма

На момент написання статті (1997р.), в Delphi не було можливості
автоматично створювати консольні додатки (можливо на сьогоднішній день цей
недолік усунуто), тому ми створимо порожній файл і помістимо в нього
наступний код:

  program ConPrg;
{$APPTYPE CONSOLE}
begin
end.

Потім збережемо цей файл з розширенням. Dpr – в даному випадку conprg.dpr.
Далі, його можна завантажити в Delphi (File | Open) і приступити до додавання коду.

Зверніть увагу: Якщо Ви запустіть вищенаведену програму, то вона
негайно завершиться, оскільки в ній немає жодного робочого коду.

Для початку, в неї можна додати рядок readln:

  program ConPrg;
{$APPTYPE CONSOLE}
begin
readln
end.

Ви побачите пусте текстове віконце, яке закриється, якщо натиснути клавішу
Enter.

Йдемо далі

Як згадувалося раніше, Ви можете використовувати майже будь-яку функцію Win32 API
з консольного застосування. Такий додаток дуже зручно ще й тим, що про
інтерфейсі можна взагалі не думати, а для виводу інформації
використовувати тільки пару функцій Write / Writeln. Прикладів застосування консольних
додатків безліч: це і різного виду утиліти, і тестові
програми для перевірки роботи функцій API і т.д. Ми не буде занурюватися в
приклади того як використовувати певні API, а поговоримо тільки про Консольні
API (Console API).

Консольні API (Console API)


Microsoft надає певний набір функцій, які дуже навіть
корисні при створенні консольних додатків. Для початку скажу, що існує по
принаймні два дескриптора (handles), які пов'язані з консольним вікном. Один
для введення, другий для виводу. Нижче наводяться дві невеликі функції, які
показують, як отримати ці дескриптори.

//—————————————–
/ / Отримання дескриптора для консольного вводу
//—————————————–
function GetConInputHandle : THandle;
begin
Result := GetStdHandle(STD_INPUT_HANDLE)
end;
//—————————————–
/ / Отримання дескриптора для консольного виводу
//—————————————–
function GetConOutputHandle : THandle;
begin
Result := GetStdHandle(STD_OUTPUT_HANDLE)
end;

Так само, краще відразу створити свої функції для таких простих операцій як
позиціонування курсору, очищення екрана і відображення / приховування курсору (так як
у консольних API вони трошки громозкі і заплутані). Ось як вони виглядають:

//—————————————–
/ / Встановлення курсору в координати X, Y
//—————————————–
procedure GotoXY(X, Y : Word);
begin
Coord.X := X; Coord.Y := Y;
SetConsoleCursorPosition(ConHandle, Coord);
end;
//—————————————–
/ / Очищення екрану – заповнення його пробілами
//—————————————–
procedure Cls;
begin
Coord.X := 0; Coord.Y := 0;
FillConsoleOutputCharacter (ConHandle, "", MaxX * MaxY, Coord, NOAW);
GotoXY(0, 0);
end;
//————————————–
/ / Показуємо / Приховуємо курсор
//————————————–
procedure ShowCursor(Show : Bool);
begin
CCI.bVisible := Show;
SetConsoleCursorInfo(ConHandle, CCI);
end;

Як Ви встигли помітити, ми скористалися чотирма функціями консольного
API: GetStdHandle, SetConsoleCursorPosition, FillConsoleOutputCharacter,
SetConsoleCursorInfo. Іноді може виникнути завдання визначення розміру
консольного вікна по вертикалі і по горизонталі. Для цього ми створимо дві
змінні: MaxX і MaxY, типу WORD:

//————————————–
/ / Ініціалізація глобальних змінних
//————————————–
procedure Init;
begin
/ / Отримуємо дескриптор виводу (output)
ConHandle := GetConOutputHandle;
/ / Отримуємо максимальні розміри вікна
Coord := GetLargestConsoleWindowSize(ConHandle);
MaxX := Coord.X;
MaxY := Coord.Y;
end;

Ми навіть можемо зробити "цикл обробки повідомлень" (message loop) – для тих,
хто тільки починає програмувати в Delphi – цикл обробки повідомлень
необхідно робити, якщо додаток створюється в чистому API – при цьому необхідні
як мінімум три складові: WinMain, message loop і window proc.

Нижче приведений код "циклу обробки повідомлень":

SetConsoleCtrlHandler(@ConProc, False);
Cls;
//
/ / "Цикл обробки повідомлень"
//
Continue := True;
While Continue do
Begin
ReadConsoleInput(GetConInputHandle, IBuff, 1, IEvent);
Case IBuff.EventType of
KEY_EVENT : Begin
/ / Перевіряємо клавішу ESC і завершуємо програму
If ((IBuff.KeyEvent.bKeyDown = True) AND
(IBuff.KeyEvent.wVirtualKeyCode = VK_ESCAPE)) Then
Continue := False;
End;
_MOUSE_EVENT : Begin
With IBuff.MouseEvent.dwMousePosition do
StatusLine(Format(“%d, %d”, [X, Y]));
End;
end;
End {While}

Так само можна додати "обробник подій" і перехоплювати такі комбінації
клавіш як Ctrl + C і Ctrl + Break:

//—————————————————–
/ / Обробник консольних подій
//—————————————————–
function ConProc(CtrlType : DWord) : Bool; stdcall; far;
var
S : String;
begin
case CtrlType of
CTRL_C_EVENT : S := “CTRL_C_EVENT”;
CTRL_BREAK_EVENT : S := “CTRL_BREAK_EVENT”;
CTRL_CLOSE_EVENT : S := “CTRL_CLOSE_EVENT”;
CTRL_LOGOFF_EVENT : S := “CTRL_LOGOFF_EVENT”;
CTRL_SHUTDOWN_EVENT : S := “CTRL_SHUTDOWN_EVENT”;
else
S := “UNKNOWN_EVENT”;
end;
MessageBox(0, PChar(S + ” detected”), “Win32 Console”, MB_OK);
Result := True;
end;

Щоб переглянути все це у дії, я зробив невелику демонстраційну
програму, яка містить підпрограми, наведені вище, а так само деякі
інші можливості. Нижче наведено повний вихідний код цієї програми.
Насолоджуйтеся!

{
[]———————————————— ———————–[]
CON001 – Show various Console API functions. Checked with Win95

version 1.01

by Alex G. Fedorov, May-July, 1997
alexfedorov@geocities.com

09-Jul-97 some minor corrections (shown in comments)
[]———————————————— ———————–[]
}
program Con001;
{$APPTYPE CONSOLE}
uses Windows, SysUtils;

const
/ / Деякі стандартні кольори
YellowOnBlue = FOREGROUND_GREEN OR FOREGROUND_RED OR
FOREGROUND_INTENSITY OR BACKGROUND_BLUE;
WhiteOnBlue = FOREGROUND_BLUE OR FOREGROUND_GREEN OR
FOREGROUND_RED OR FOREGROUND_INTENSITY OR
BACKGROUND_BLUE;
RedOnWhite = FOREGROUND_RED OR FOREGROUND_INTENSITY OR
BACKGROUND_RED OR BACKGROUND_GREEN OR BACKGROUND_BLUE
OR BACKGROUND_INTENSITY;
WhiteOnRed = BACKGROUND_RED OR BACKGROUND_INTENSITY OR
FOREGROUND_RED OR FOREGROUND_GREEN OR FOREGROUND_BLUE
OR FOREGROUND_INTENSITY;

var
ConHandle: THandle; / / Дескриптор консольного вікна
Coord: TCoord; / / Для зберігання / встановлення позиції екрану
MaxX, MaxY: Word; / / Для зберігання максимальних розмірів вікна
CCI : TConsoleCursorInfo;
NOAW: LongInt; / / Для зберігання результатів деяких функцій

//—————————————–
/ / Отримання дескриптора для консольного вводу
//—————————————–
function GetConInputHandle : THandle;
begin
Result := GetStdHandle(STD_INPUT_HANDLE)
end;
//—————————————–
/ / Отримання дескриптора для консольного виводу
//—————————————–
function GetConOutputHandle : THandle;
begin
Result := GetStdHandle(STD_OUTPUT_HANDLE)
end;
//—————————————–
/ / Встановлення курсору в координати X, Y
//—————————————–
procedure GotoXY(X, Y : Word);
begin
Coord.X := X; Coord.Y := Y;
SetConsoleCursorPosition(ConHandle, Coord);
end;
//—————————————–
/ / Очищення екрану – заповнення його пробілами
//—————————————–
procedure Cls;
begin
Coord.X := 0; Coord.Y := 0;
FillConsoleOutputCharacter (ConHandle, "", MaxX * MaxY, Coord, NOAW);
GotoXY(0, 0);
end;
//————————————–
/ / Показуємо / Приховуємо курсор
//————————————–
procedure ShowCursor(Show : Bool);
begin
CCI.bVisible := Show;
SetConsoleCursorInfo(ConHandle, CCI);
end;
//————————————–
/ / Ініціалізація глобальних змінних
//————————————–
procedure Init;
begin
/ / Отримуємо дескриптор виводу (output)
ConHandle := GetConOutputHandle;
/ / Отримуємо максимальні розміри вікна
Coord := GetLargestConsoleWindowSize(ConHandle);
MaxX := Coord.X;
MaxY := Coord.Y;
end;
//—————————————
/ / Малюємо рядок статусу ("status line")
//—————————————
procedure StatusLine(S : String);
begin
Coord.X := 0; Coord.Y := 0;
WriteConsoleOutputCharacter (ConHandle, PChar (S), Length (S) +1, Coord, NOAW);
FillConsoleOutputAttribute (ConHandle, WhiteOnRed, Length (S), Coord, NOAW);
end;

//—————————————————–
/ / Консольний обробник подій
//—————————————————–
function ConProc(CtrlType : DWord) : Bool; stdcall; far;
var
S : String;
begin
case CtrlType of
CTRL_C_EVENT : S := “CTRL_C_EVENT”;
CTRL_BREAK_EVENT : S := “CTRL_BREAK_EVENT”;
CTRL_CLOSE_EVENT : S := “CTRL_CLOSE_EVENT”;
CTRL_LOGOFF_EVENT : S := “CTRL_LOGOFF_EVENT”;
CTRL_SHUTDOWN_EVENT : S := “CTRL_SHUTDOWN_EVENT”;
else
S := “UNKNOWN_EVENT”;
end;
MessageBox(0, PChar(S + ” detected”), “Win32 Console”, MB_OK);
Result := True;
end;
{
[]———————————————— —————[]
Основна програма – показує використання деяких підпрограм
а так само деяких функцій консольного API
[]———————————————— —————[]
}
var
R : TSmallRect;
Color : Word;
OSVer : TOSVersionInfo;
IBuff : TInputRecord;
IEvent : DWord;
Continue : Bool;

begin
/ / Ініціалізація глобальних змінних
Init;
/ / Розташування вікна на екрані
With R do
{!! 1.01 !!}
begin
Left := 10; Top := 10; Right := 40; Bottom := 40;
end
{!! 1.01 !!}
SetConsoleWindowInfo(ConHandle, False, R);
/ / Встановлюємо обробник подій
SetConsoleCtrlHandler(@ConProc, True);
/ / Перевіряємо обробник подій
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
/ / Змінюємо заголовок вікна
SetConsoleTitle(“Console Demo”);
/ / Ховаємо курсор
ShowCursor(False);
Coord.X := 0; Coord.Y := 0;
/ / Встановлюємо білий текст на синьому фоні
Color := WhiteOnBlue;
FillConsoleOutputAttribute (ConHandle, Color, MaxX * MaxY, Coord, NOAW);
/ / Console Code Page API is not supported under Win95 – only GetConsoleCP
Writeln(“Console Code Page = “, GetConsoleCP);
Writeln(“MAX X=”, MaxX,” MAX Y=”, MaxY);
Readln; / / очікуємо введення користувача
Cls; / / очищаємо екран
ShowCursor (True); / / показуємо курсор
//
// Use some Win32API stuff
//
OSVer.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
GetVersionEx(OSVer);
With OSVer do
Begin
Writeln(“dwMajorVersion = “, dwMajorVersion);
Writeln(“dwMinorVersion = “, dwMinorVersion);
Writeln(“dwBuildNumber = “, dwBuildNumber);
Writeln(“dwPlatformID = “, dwPlatformID);
End;

//
Readln; / / очікуємо введення користувача
/ / Видаляємо обробник подій
SetConsoleCtrlHandler(@ConProc, False);
Cls;
//
/ / "Цикл обробки повідомлень"
//
Continue := True;
While Continue do
Begin
ReadConsoleInput(GetConInputHandle, IBuff, 1, IEvent);
Case IBuff.EventType of
KEY_EVENT : Begin
/ / Перевіряємо клавішу ESC і завершуємо програму
If ((IBuff.KeyEvent.bKeyDown = True) AND
(IBuff.KeyEvent.wVirtualKeyCode = VK_ESCAPE)) Then
Continue := False;
End;
_MOUSE_EVENT : Begin
With IBuff.MouseEvent.dwMousePosition do
StatusLine(Format(“%d, %d”, [X, Y]));
End;
end;
End {While}
end.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*