Assembler очистка консольного окна приложения windows

Обновлено: 04.07.2024

Programm.ws - это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..

Программирование — в обычном понимании, это процесс создания компьютерных программ.
В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками.
В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.

Глава 5. Работа с консолью в программах на ассемблере

Если ничто другое не помогает,
прочтите, наконец, инструкцию.
Прикладная Мерфология

В этом разделе будут рассмотрены средства для работы с консолью в среде операционной системы Windows. Как известно, Windows поддерживает работу двух типов приложений — оконных, в полной мере использующих все достоинства графического интерфейса, и консольных, работающих исключительно в текстовом режиме. Поэтому не следует путать понятие «консоли», используемое выше, с понятием «консольного приложения» Windows. В предшествующем материале под «консолью» подразумевались средства для ввода информации с клавиатуры и вывода ее на экран. Для однозначности изложения далее под термином «консоль» мы будем иметь в виду либо само консольное приложение, либо его видимую часть — окно консольного приложения.
Далее мы рассмотрим порядок ввода-вывода данных в консольное приложение для Windows, написанное на ассемблере. Организация ввода-вывода в оконном приложении Windows здесь рассматриваться не будет, так как в уроках 18 «Создание Windows-приложений на ассемблере» и 19 «Архитектура и программирование сопроцессора» учебника этот вопрос был рассмотрен очень подробно и полно. Что-либо существенное добавить к уже сказанному трудно. Данная книга рассматривается как практическое продолжение учебника, поэтому повторяться просто не имеет смысла. Что же касается организации работы с консольным приложением, то этот вопрос в учебнике был рассмотрен слабо — в контексте одной из задач урока 20 «ММХ-технология микропроцессоров Intel». Поэтому есть смысл рассмотреть его более систематично, попутно осветив проблемы ввода-вывода в консольном приложении Windows. Это тем более актуально, что при программировании на ассемблере необходимость написания консольного приложения возникает более часто, чем оконного. Причина проста — малыми затратами нам становятся доступны многие возможности API Win32.

Организация ввода-вывода в консольном приложении Windows

  • нажатии и отпускании клавиш;
  • манипуляциях мышью — движение, нажатие-отпускание кнопок;
  • изменение размера активного экранного буфера, состояние прокрутки.

Относительно этой программы можно сделать два замечания. Первое касается функции Handl erRoutine, которая в нашей программе называется Ctrl Handler. Как упоминалось, эта функция является функцией обратного вызова. Ее вызов производится при возникновении определенных событий неявно — из системы Windows. По структуре и алгоритму работы она аналогична оконной функции, которую мы рассматривали в уроке 18 «Создание Windows-приложений на ассемблере» учебника. Поэтому за всеми подробностями отсылаем читателя к этому материалу. Второе замечание касается порядка отладки приложений, содержащих определяемые пользователем функции (процедуры) обратного вызова. Первое, что нужно сделать в процессе пошагового выполнения программы в отладчике, — выяснить адрес процедуры обратного вызова. В программе выше это можно сделать, выяснив, какое значение будет помещено в стек при выполнении команд:

.
[установим функцию-обработчик сигналов управления
push TRUE
push offset cs: Ctrl Handler
call SetConsoleCtrlHandler
cmp eax. 0
jz exit [если неуспех
.

После этого, сделав активным окно отладчика CPU (выбрав в меню команду
View CPU), необходимо установить указатель мыши в окно с командами процес-; сора и щелкнуть правой кнопкой мыши. В появившемся контекстном меню вы-
бер*етс пункт Goto. В результате этих действий отладчик отобразит диалоговое ¦ окно, в которое необходимо внести адрес программы-обработчика Ctrl Handler. ; В результате этого в верхней части окна команд отобразится первая команда [' процедуры Ctrl Handler. Установите на нее курсор и нажмите клавишу F4. Все, S программа начнет выполняться по своему алгоритму. При нажатии пользователем
управляющих комбинаций клавиш, допустимых функцией Handl erRoutine, управ-I ление будет передано этой функции, и вы сможете произвести ее отладку.

Итак, в данный момент я копирую экранный буфер (screenbuffer db 64000 DUP (0)) в видеопамять (которая начинается с 0a0000h), чтобы очистить экран. Но мне было интересно, лучше ли снова просто установить видео режим так:

Что, кажется, очистить экран, а также.

Или есть еще лучший способ очистить экран?

2 ответа

Вы можете использовать STOSD с REP префикс для очистки видеопамяти для режима видео 13 (320x200x256 цветов). REP STOSD будет повторять STOSD по количеству, сохраненному в ECX . STOSD будет записывать каждый DWORD в EAX в ES: [EDI] увеличивая EDI каждый раз на 4.

REP: Повторяет строковую инструкцию количество раз, указанное в регистре подсчета.

STOSD: сохраняет двойное слово из регистра EAX в операнде назначения.

Пример кода может выглядеть примерно так:

В этом коде предполагается, что вы работаете на 32-разрядном процессоре, но не предполагается, что вы работаете в нереальном режиме .

Если вы используете 16-битный процессор (8086/80186/80286), вам придется использовать 16-битные регистры и использовать REP STOSW . Для CX будет установлено значение (320 * 200) / 2 вместо (320 * 200) / 4. 16-разрядные процессоры не допускают 32-разрядные операнды, поэтому не поддерживают STOSD .

Вы можете легко преобразовать этот код в функцию на ассемблере.

Есть функция INT 10H для очистки экрана: AH=06h, AL=00h

Вы можете установить цвет в BH .

Это INT 10H Окно прокрутки , которое очищает экран, если AL = 0

Эта функция применяется к прямоугольной области, которая устанавливается в других регистрах, например DH = номер нижней строки, DL = номер правой колонки.

Стандартный способ очистки экрана состоит в том, чтобы установить CX на 0000H, DL на 0040: [004a] -1 (обычно 79), DH на 0040: [0084] (обычно 24), BH на 07H (атрибут белого или черного видео ) и AL до 00H (чтобы очистить весь экран).


Очистка экрана состоит просто в записи пробела в каждую из
позиций экрана (код ASCII - 32). Однако, если при выводе на экран
были использованы ненормальные атрибуты, то должны быть также
изменены и байты атрибутов. Операционная система обеспечивает
простой способ очистки только части экрана.

Высокий уровень.


Бейсик для очистки экрана использует оператор CLS. При этом
25-я строка внизу экрана становится пустой только если был убран
список значений функциональных клавиш с помощью команды KEY OFF.
Байты атрибутов устанавливаются равными ASCII 7. В [4.5.1] дана
процедура прокрутки, которая может быть использована в Бейсике
для очистки окон на экране.

Средний уровень.


Операционная система предоставляет несколько способов очистки
экрана. Какой из них Вы выберете зависит от того, какие средства
требуются программе для достижения других целей. Первый метод -
это просто сброс режима дисплея, используя функцию 0 прерывания
10H [4.1.2]. Для символьного экрана каждая позиция заполняется
пробелом (ASCII 32), а все атрибуты устанавливаются нормальными
(ASCII 7). Обычно этот метод хорош только в начале программы,
когда все равно надо устанавливать режим работы дисплея. Для
цветного графического адаптера и PCjr реинициализация режима
дисплея приводит к катавасии на экране. Этот эффект отсутствует у
монохромного адаптера и EGA.

;---очистка экрана путем установки нового режима
MOV AH,0 ;номер функции установки режима дисплея
MOV AL,2 ;код режима 80*25 черно-белого
INT 10H ;очистка экрана

Второй метод состоит в использовании функций 6 и 7 прерывания
10H, которые сдвигают экран. Число строк, на которое надо сдви-
нуть экран помещается в AL и когда это число равно нулю экран
очищается. Прерывание позволяет сдвигать только часть экрана,
поэтому таким образом можно очистить отдельное окно на экране.
Надо поместить координаты левого верхнего угла окна в CX, а коор-
динаты правого нижнего угла в DX (номер строки в CH/DH, а номер
столбца в CL/DL). Поместите атрибут, с которым должен чиститься
экран в BH. Координаты отсчитываются от 0.

;---очистка окна между 3,4 и 13,15
MOV AH,6 ;используем процедуру сдвига
MOV AL,0 ;число строк сдвига делаем равным нулю
MOV BH,7 ;байт атрибутов для заполнения
MOV CH,3 ;строка для верхнего левого угла
MOV CL,4 ;столбец для левого верхнего угла
MOV DH,13 ;строка для нижнего левого угла
MOV DL,15 ;столбец для нижнего левого угла
INT 10H ;чистим окно

Третий метод заключается в использовании фукнции 9 прерывания
10H; которая выводит символ и атрибуты столько раз, сколько ука-
зано в CX. Значение 2000 чистит весь экран, если курсор был уста-
новлен в 0,0, используя метод показанный в [4.2.1]. AH должен
содержать символ пробела, AL - байт атрибутов, а BH - номер стра-
ницы дисплея.

Наконец, DOS обеспечивает очистку экрана с помощью специальных
Esc-последовательностей, которые работают с драйвером ANSI.SYS.
Основные сведения о нем приведены в приложении Д. Эти последова-
тельности - это строки, начинающиеся с символа Esc, а завершаю-
щиеся ограничителем $. Такие строки выводятся функцией 9 прерыва-
ния 21H, при этом DS:DX должны указывать на первый символ строки.
DOS интерпретирует строку не выводя ее на дисплей. Чтобы стереть
весь экран строка должна быть [2J. Чтобы стереть конец строки,
начиная от позиции курсора (включая эту позицию), строка [K.

;---очистка конца строки, начиная от позиции курсора
MOV AH,9 ;функция вывода строки
LEA DX,CLEAR_LINE ;DX должен указывать на начало строки
INT 21H ;стираем конец строки

Низкий уровень.


На низком уровне надо просто поместить символы пробела и тре-
буемый байт атрибутов в память дисплея, используя инструкцию
STOSW. Вот пример для монохромного дисплея:

MOV AX,0B000H ;указываем на память дисплея
MOV ES,AX ;
MOV DI,0 ;DI указывает на начало буфера
MOV AL,32 ;символ пробела
MOV AH,7 ;нормальные атрибуты
MOV CX,2000 ;число повторений
REP STOSW ;посылаем AX в ES:DI 2000 раз

В процессе изучения основных правил работы оконных приложений, мы познакомились с некоторыми принципами программирования графических примитивов. Теперь самое время открыть для себя еще одну разновидность приложений под Windows - консольные приложения.
Во времена разработки первых операционных систем, в них не было такого понятия как графический интерфейс пользователя, был доступен только текстовый режим видеоадаптера с интерфейсом командной строки. Однако, в ходе развития ОС был создан графический интерфейс пользователя (GUI), роль которого со временем существенно возросла. Как раз во время создания GUI стало очевидно, что необходимость в консольных приложениях сохраняется, следствием чего было создание консоли Windows . Консоль, в зависимости от ОС, может работать как в привычных по старым операционным системам текстовых режимах (они еще поддерживаются на аппаратном уровне в современных видеоадаптерах), так и в режимах эмуляции текстового режима. Основная причина по которой консоль в Windows была выделена в отдельную разработку и продолжает своё существование, заключается в следующем:

Большое количество системных утилит, входящих в состав операционной системы, используют исключительно текстовый интерфейс и рассчитаны на использование аргументов командной строки.
  • возможность (для взаимодействия) использовать стандартные потоки ввода-вывода (будут описаны ниже).
  • наличие потоков позволяет использовать консольные утилиты в сценариях (скриптах), где выходные потоки одних утилит могут перенаправляться во входные потоки других.
  • оптимизация приложения по скорости выполнения (скорости вывода информации) и потреблению системных ресурсов.
  • удобство программирования, обусловленное простотой и небольшим набором функций обслуживания консоли.
Текстовый пользовательский интерфейс (Text user interface, TUI / Character-Mode User Interface, CUI) - разновидность интерфейса, использующая для ввода-вывода/представления информации текстовый режим (или его эмуляцию) работы видеоадаптера и набор буквенно-цифровых символов и символов псевдографики.

что является базой для:

Консоль (интерфейс командной строки) - текстовый интерфейс управления консольным приложением , ввод-вывод в рамках которого может осуществляться через стандартные потоки: ввод ( stdin ), вывод ( stdout ), ошибка ( stderr ), а так же прямыми чтением/записью из буферов ввода-вывода. По умолчанию к потоку ввода "подключена" клавиатура (мышь), а к потоку вывода — экран (монитора). В частном случае может быть представлена в виде бесконечной бумажной ленты, прокручивающейся в обе стороны.

что, в свою очередь, формирует понятие:

Консольное приложение (character-mode applications) Windows - класс приложений, использующих для взаимодействия с системой/пользователем объекты консоли: текстовый интерфейс и стандартные потоки ввода-вывода. Считается что консольные приложения управляются консолями .

Консольное приложение операционной системы Windows обеспечивает взаимодействие с пользователем через так называемое окно консоли . Примером подобных консольных приложений могут являться: окно командной строки (cmd), файловые менеджеры (например, Far Commander), и ряд типовых системных консольных утилит:

консоль cmd

Различия оконного и консольного приложений

Консольные приложения являются одним из типов исполняемых образов (приложений) Windows, наряду с типовыми оконными (GUI), библиотеками (DLL), драйверами (native) и некоторыми другими. По сути это полноценные приложениями, имеющие ряд специфических отличий:

  • Значение поля Subsystem заголовка результирующего PE-файла равно 3 ( IMAGE_SUBSYSTEM_WINDOWS_CUI ). На основании значения данного поля, загрузчик образов при подготовке приложения к выполнению производит свойственную консольным приложениям последовательность загрузки.
  • При запуске консольного приложения, загрузчик образов пытается наследовать консоль от процесса-родителя (приложение, из-под которого был произведен запуск):
    • Создается новая консоль, если родительский процесс не имеет консоли.
    • Консоль наследуется, если процесс-родитель тоже является консольным приложением (окно командной строки и прочее).

    Следует ли из всего вышеперечисленного, что все функциональные методы консольного приложения "заключены" внутри набора текстовых функций и им лишь и ограничиваются? Отнюдь, основная идея заключается в том, что отличие оконного приложения от консольного чисто условное, поскольку консольное приложение сохраняет возможность вызывать GUI-функции (то есть функции, работающие уже с графическими примитивами) программного интерфейса Win32, все зависит лишь от набора подключаемых библиотек. Да, в простейшем случае текстовый интерфейс использует интерфейс командной строки, тем не менее многие приложения могут создавать более дружественный пользователю интерфейс при помощи интерактивных элементов, тем самым приближаясь по удобству к полноценному оконному (графическому).

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

    Иначе говоря, программы с текстовым интерфейсом могут имитировать оконный интерфейс. Поэтому можно сделать следующее обобщение: консольные приложения имеют возможность полноценно взаимодействовать с функциями Win32 API наравне с типовым оконным GUI-приложением, ведь в процессе написания исходного кода автор имеет возможность импортировать (подключать) любые функции любых доступных коду библиотек, каковые он сочтет нужными.

    Начиная с Windows 7, на системном уровне функционал консоли был вынесен из диспетчера csrss.exe и оформлен в качестве самостоятельных исполняемых образов:

    • conhost.exe – обработчик консольных окон режима пользователя (обеспечивает весь функционал работы с консолью);
    • condrv.sys – драйвер режима ядра, обеспечивающий взаимодействие conhost и консольных приложений;

    Объекты консольного приложения

    Выводить текст на консоль, осуществлять ввод символов, а так же совершать любые иные действия с консолью можно лишь ассоциировав с ней некие системные сущности (объекты), посредством которых можно обеспечивать обмен данными. Каждая консоль состоит из следующих основных объектов:

    • [единственный] входной буфер - область данных (события/сигналы/данные) для ввода (передачи на консоль);
    • [несколько] экранный выходной буфер - область данных (символы/атрибуты) для вывода (отображения на экране);
    • Окно консоли - область экрана, отображающая часть выходного буфера;
    • Текущая позиция курсора - маркера вывода, обозначающий текущую позицию вывода;

    Стандартные потоки (дескрипторы консоли)

    На программном уровне для ввода/вывода информации консольные приложения используют три основных стандартных устройства ввода-вывода:

    Для кода любого консольного приложения стандартные потоки доступны через дескрипторы и используют последние для того, чтобы обратиться к стандартному вводу (буферу ввода данных) и стандартному выводу (экранным буферам) собственной консоли. Хотя этими потоками консольное приложение не ограничено, никто не запрещает ему открывать любые файлы, использовать сетевые соединения и совершать иные действия, доступные в выполняющей их среде.

    Стандартный поток — объект процесса консольного приложения, предназначающийся для организации обмена данными.

    Традиционно, со стандартным вводом ассоциирована клавиатура, а со стандартным выводом/ошибкой ассоциирован монитор (экран), таким образом вывод печатных символов в STDOUT и STDERR приводит к появлению этих символов на устройстве вывода и к получению их пользователем. В дополнение, потоки могут быть переопределены (перенаправлены) и на другие логические устройства (файл, ввод/вывод другой программы и прочее). Поэтому определение консольного приложения может быть расширено:

    Любая программа, получающая данные путём чтения STDIN и передающая данные путём записи в STDOUT , является консольной.

    Тем не менее возникает резонный вопрос: обязательно ли наличие окна консоли у консольного приложения? Ведь, теоретически, консольные программы могут обходиться и без классического ввода (с клавиатуры) и вывода (в окно, на экран), поскольку объекты stdin и stdout могут быть связаны с файлами, потоками ввода/вывода других программ или иными объектами операционной системы? Тем не менее, стандартный сценарий использования консольного приложения в Windows подразумевает создание отдельного окна консоли.
    В ходе запуска консольного приложения, система генерирует вышеперечисленные дескрипторы для вновь создаваемого процесса консоли. Процесс консольного приложения обычно использует функции GetStdHandle , CreateFile , CreateConsoleScreenBuffer для того, чтобы открыть один из вышеописанных дескрипторов. Функция GetStdHandle обеспечивает механизм получения кодом приложения дескрипторов стандартного ввода, стандартного вывода и стандартной ошибки, связываемых с процессом в момент создания. В случае необходимости имеется возможность переназначить стандартные дескрипторы через функцию SetStdHandle , изменяющую дескрипторы, связанные с STDIN , STDOUT или STDERR .
    Стандартные дескрипторы родительского процесса всегда наследуются всеми создаваемыми дочерними процессами, поэтому вызовы функции GetStdHandle дочерними процессами возвращают переназначенный дескриптор. По этой причине, в зависимости от действий родительского процесса, дескриптор, возвращенный функцией GetStdHandle , может сослаться на что-либо, отличное от привычного нам консольного ввода-вывода. К примеру, родительский процесс может при помощи SetStdHandle изменить дескриптор какого-либо потока (например STDIN ) перед созданием дочернего процесса. Затем, когда созданный дочерний процесс у себя в коде вызовет функцию GetStdHandle , он получает дескриптор переназначенного канала. Этим обеспечивается механизм управления родительским процессом стандартными дескрипторами дочернего процесса.

    К дескрипторам применяются права доступа. По умолчанию дескрипторы, возвращенные функцией GetStdHandle , имеют доступ GENERIC_READ | GENERIC_WRITE .

    Буфер ввода

    Каждое консольное приложение имеет буфер вводимых данных:

    В момент, когда окно консольного приложения имеет фокус клавиатуры (является активным), консоль оформляет каждое событие ввода (типа нажатия/отпускания клавиши, перемещение указателя мыши или щелчка кнопки мыши) в качестве данных, которые помещаются в буфер вводимых данных консоли. Что такое эти самые данные? Запись данных о вводе ― структура Windows, содержащая в себе информацию о деталях события: тип, источник (клавиатура, мышь, размеры окна, фокус, меню) и прочих. Структура имеет внутренний тип INPUT_RECORD и представляет собой следующее:

    Читайте также: