При написании консольного приложения можно проанализировать некоторые события, которые происходят, когда консольное окно выведено на экран монитора. К таким событиям относятся:
· Нажатие комбинации клавиш Ctrl+C
· Нажатие комбинации клавиш Ctrl+Break
· Закрытие консольного окна процесса
· Завершение работы пользователя в системе (завершение сеанса пользователя)
· Завершение работы системы (выключение компьютера)
При возникновении таких событий можно выполнить необходимые разработчику программы действия. По умолчанию обрабатывается только одно событие – закрытие консольного окна, – для которого вызывается функция ExitProcess.
Однако программист может написать одну или несколько функций в своей программе, которые будут выполняться при наступлении этих событий. Если в языках высокого уровня различны такие понятия как процедура и функция, то в ассемблере они эквивалентны. (функции-обработчики заносятся в список; первой срабатывает та функция, которая занесена последней).
Такие функции должны возвращать результат в регистре EAX:
1) если в регистре EAX будет возвращено значение 1, то это будет означать, что функция выполнила обработку произошедшего события, и управление будет передано основному алгоритму.
2) если в регистре EAX будет возвращено значение 0, то это будет означать, что обработка события не выполнена, и управление будет передано функции-обработчику, которая была включена в список функций-обработчиков раньше данной.
Для того, чтобы указать на какую функцию перейти при возникновении события, применяется API-функция SetConsoleCtrlHandler.
Формат ее вызова следующий:
invoke SetConsoleCtrlHandler, HandlerRoutine, Add
где:
HandlerRoutine - указатель на функцию, которая будет обрабатывать события консольного приложения
Add – признак добавления функции-обработчика в список или удаления функции-обработчика из списка (1 – добавить, 0 - удалить).
Указатель на функцию, которая будет обрабатывать события консольного приложения, необходимо сохранить в регистре еах. Это связано с тем, что описание функции происходит после команды invoke ExitProcess,0 и до end start:
invoke ExitProcess,0
описание функции
end start
Например,
mov eax, offset CtrlHandler
invoke SetConsoleCtrlHandler, eax, 1
Если в языках высокого уровня различны такие понятия как процедура и функция, то в ассемблере они эквивалентны. Для описания функции в Ассемблере в простейшем случае применяется следующая конструкция:
имя_функции proc список_параметров
…
команды функции
…
Ret
имя_ функции endp
имя_процедуры – это метка, определяющая начало процедуры. Определить адрес этой метки относительно начала сегмента кода (то есть указатель на данную процедуру) можно с помощью оператора OFFSET (поскольку используется плоская модель и все сегменты начинаются с одного адреса).
список_параметров – представляется в виде перечисления через запятую следующих конструкций:
имя_параметра:тип_параметра
Процедура-обработчик (написанная нами) должна иметь один 32-битный параметр, через который будет передаваться в функцию информация о том, какое событие произошло. Описать этот параметр можно следующим образом:
dwCtrlType:DWORD
Этот параметр может принимать следующие значения:
0 = CTRL_C_EVENT – произошло нажатие клавиш Ctrl+C;
1 = CTRL_BREAK_EVENT – произошло нажатие клавиш Ctrl+Break;
2 = CTRL_CLOSE_EVENT – пользователь закрывает консольное окно;
5 = CTRL_LOGOFF_EVENT – пользователь завершает работу в системе (завершение сеанса пользователя);
6 = CTRL_SHUTDOWN_EVENT – пользователь завершает работу системы (завершает работу компьютера).
Задание для самостоятельной работы:
Написать программу консольного приложения, предназначенного для организации ввода нескольких строк. В программе предусмотреть обработку следующих событий: нажатие Ctrl+C, нажатие Ctrl+Break, закрытие окна консольного приложения, завершение сеанса пользователя в системе Windows. В качестве реакции на указанные события вывести в консольном окне сообщение, соответствующее каждому из них.
Организация низкоуровневого консольного ввода-вывода
API-функции, с помощью которых организуется низкоуровневый консольный ввод-вывод, по сравнению с высокоуровневыми функциями, обладают более широкими и гибкими возможностями. Низкоуровневые функции обеспечивают прямой доступ к входному и экранным буферам консоли, предоставляя приложению доступ к событиям мыши и клавиатуры, а также к информации об изменении размеров окна консоли.
Обсудим возможности низкоуровневого ввода-вывода на примере работы с входным буфером (входной очередью) и экранным буфером (выходным буфером).