Жанр: Учеба
Техника программирования на турбо-С
...цесса.
Листинг 10.1: tmenu.c
/* ------------ tmenu.c ------------ */
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#include "keys.h"
#include "twindow.h"
extern int VSG;
WINDOW *open_menu(char *mnm, MENU *mn, int hsel);
int gethmenu(MENU *mn, WINDOW *hmenu, int hsel);
int getvmn(MENU *mn, WINDOW *hmenu, int *hsel, int vsel);
int haccent(MENU *mn, WINDOW *hmenu, int hsel, int vsel);
void dimension(char *sl[], int *ht, int *wd);
void light(MENU *mn, WINDOW *hmenu, int hsel, int d);
/* ------------ Отображение и обработка меню--------- */
void menu_select(char *name, MENU *mn)
{
WINDOW *open_menu();
WINDOW *hmenu;
int sx, sy;
int hsel = 1, vsel;
curr_cursor(&sx, &sy);
cursor(0, 26);
hmenu = open_menu(name, mn, hsel);
while (hsel = gethmenu(mn, hmenu, hsel)) {
vsel = 1;
while (vsel = getvmn(mn, hmenu, &hsel, vsel)) {
delete_window(hmenu);
set_help("", 0, 0);
(*(mn+hsel-1)-"func [vsel-1])(hsel, vsel);
hmenu = open_menu(name, mn, hsel);
}
}
delete_window(hmenu);
cursor(sx, sy);
}
/* ----Инициализация горизонтального меню-------*/
static WINDOW *open_menu(char *mnm, MENU *mn, int hsel)
{
int i = 0;
WINDOW *hmenu;
set_help("menu ", 30, 10);
hmenu = establish_window(0, 0, 3, 80);
set_title(hmenu, mnm);
set_colors(hmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(hmenu, ACCENT, WHITE, BLACK, DIM);
display_window(hmenu);
while ((mn+i)-"mname)
wprintf(hmenu, " %-10.10s ", (mn+i++)-"mname);
light(mn, hmenu, hsel, 1);
cursor(0, 26);
return hmenu;
}
/* ----Выборка из горизонтальногоь меню------*/
static int gethmenu(MENU *mn, WINDOW *hmenu, int hsel)
{
int sel;
light(mn, hmenu, hsel, 1);
while (TRUE) {
switch (sel = get_char()) {
case FWD:
case BS: hsel = haccent(mn, hmenu, hsel, sel);
break;
case ESC: return 0;
case '\r': return hsel;
default: putchar(BELL);
break;
}
}
}
/* -----Всплывающее вертикальное меню--------*/
static int getvmn(MENU *mn,WINDOW *hmenu,int *hsel,int vsel)
{
WINDOW *vmenu;
int ht = 10, wd = 20;
char **mp;
while (1) {
dimension((mn+*hsel-1)-"mselcs, &ht, &wd);
vmenu = establish_window(2+(*hsel-1)*12, 2, ht, wd);
set_colors(vmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(vmenu, ACCENT, WHITE, BLACK, DIM);
set_border(vmenu, 4);
display_window(vmenu);
mp = (mn+*hsel-1)-"mselcs;
while (*mp)
wprintf(vmenu, "\n%s", *mp++);
vsel = get_selection(vmenu, vsel, "");
delete_window(vmenu);
if (vsel == FWD || vsel == BS) {
*hsel = haccent(mn, hmenu, *hsel, vsel);
vsel = 1;
}
else
return vsel;
}
}
/* -----Управление отображением выбранных элементов
горизонтального меню -----*/
static int haccent(MENU *mn,WINDOW *hmenu,int hsel,int sel)
{
switch (sel) {
case FWD:
light(mn, hmenu, hsel ,0);
if ((mn+hsel)-"mname)
hsel++;
else
hsel = 1;
light(mn, hmenu, hsel ,1);
break;
case BS:
light(mn, hmenu, hsel ,0);
if (hsel == 1)
while ((mn+hsel)-"mname)
hsel++;
else
--hsel;
light(mn, hmenu, hsel ,1);
break;
default:
break;
}
return hsel;
}
/* -----Вычисление высоты и ширины меню-------*/
static void dimension(char *sl[], int *ht, int *wd)
{
unsigned strlen(char *);
*ht = *wd = 0;
while (sl [*ht]) {
*wd = max(*wd, strlen(sl [*ht]));
(*ht)++;
}
*ht += 2;
*wd += 2;
}
/* --------Отображение в соответствии с параметром
accent элемента горизонтального меню ---*/
static void light(MENU *mn, WINDOW *hmenu, int hsel, int d)
{
if (d)
revers_video(hmenu);
wcursor(hmenu, (hsel-1)*12+2, 0);
wprintf(hmenu, (mn+hsel-1)-"mname);
normal_video(hmenu);
cursor(0, 26);
}
Описание программы: tmenu.c
-----------------------------------------------------------------
Функция menu_select вызывается для обработки меню,
описанного в массиве структур MENU. Эта функция запоминает
текущее положение системы меню и позицию курсора относительно
координат экрана. Затем вызывается функция open_menu, которая
осуществляет инициализацию и отображение на экране (в его верхней
части) горизонтального меню-строки. Цикл while осуществляет
обработку горизонтального меню-строки до тех пор, пока
пользователь не нажмет клавишу "КЛЮЧ" ("ESC"). На каждой итерации
цикла вызывается функция getmenu. Если функция getmenu возвращает
значение 0, значит, пользователь нажал клавишу "КЛЮЧ" ("ESC").
Если функция getmenu возвращает ненулевое значение, значит,
пользователь произвел выборку одного из элементов горизонтального
меню. Возвращаемое функцией значение специфицирует выбранный
пользователем элемент меню. Следующий цикл while обрабатывает
"всплывающее" вертикальное меню, соответствующее выбранному ранее
элементу горизонтального меню-строки. На каждой операции этого
цикла происходит обращение к функции getvmn, которая осуществляет
обработку "всплывающего" меню. При нажатии пользователем клавиши
"КЛЮЧ" ("ESC") функция getvmn возвращает значение 0, в противном
случае getvmn возвращает значение, специфицирующее выбранный
пользователем элемент вертикального меню. После этого окно,
выделенное для горизонтального и вертикальных меню, уничтожается,
вызывается функция, реализующая действия, соответствующие
выбранному пользователем элементу вертикального меню. По
завершении работы этой функции open_menu вызывает восстановление
изображения на экране горизонтального меню-строки.
Функция open_menu открывает окно в верхней части экрана на
всю его ширину. Это окно предназначено для горизонтального
меню-строки. Меню выбора функций вашей программы отображается в
этом окне в соответствии с таблицей MENU. Первый из выбранных
пользователем элементов этого меню отображается в акцентированном
цвете функцией light.
Функция getmenu анализирует прерывания от клавиатуры при
выборе элементов меню или при передвижении курсора по меню. Если
пользователь нажал клавишу перемещения курсора вправо или влево,
то вызывается функция haccent для перемещения курсора по
меню-строке. Если пользователь нажал клавишу "КЛЮЧ" ("ESC"), то
функция getmenu возвращает 0. При нажатии клавиши "ВВОД" ("ESC")
функция возвращает значение, соответствующее выбранному элементу
меню, и передает управление в точку ее вызова.
Функция getvmn предназначена для обработки вертикального
меню, "всплывшего" под соответствующим элементом горизонтального
меню. Вертикальное меню представляет собой окно, а его состав
определяется в соответствии с таблицей MENU. Функция
get_selection (см. Главу 6) вызывается для считывания
пользовательского выбора. После того, как в вызывающую программу
передано значение выбранного пользователем элемента меню, окно,
выделяемое для "всплывающего" меню, уничтожается. При нажатии
пользователем клавиш перемещения курсора вправо или влево
вызывается функция haccent для перемещения вперед или назад
курсора по элементам горизонтального меню-строки, а обработка
вновь появляющихся (в процессе перемещения курсора по
горизонтальному меню) вертикальных меню осуществляется опять
функцией getvmn; в противном случае значение, возвращаемое
функцией get_selection приводит к возврату управления в точку
вызова функции getvmn.
Пример оконного меню
-----------------------------------------------------------------
Листинги 10.2, 10.3 и 10.4 содержат пример программы,
иллюстрирующей использование и обработку меню. Этот пример строит
меню, позволяющее выполнять в рамках одной интегрированной
системы все оконные функции, рассмотренные в качестве
примеров, иллюстрирующих содержание глав с шестой по девятую.
Листинг 10.2, программа menu.c, является простейшей
управляющей программой, которая вызывает программу, реализующую
пример (exec.c) и представленную листингом 10.3. Листинг 10.4
программы menu.prj является make-файлом Турбо Си, по которому
строится выполняемая программа, реализующая пример.
Листинг 10.2:menu.c
/* ------------------menu.c-------------------*/
#include "twindow.h"
void exec(void);
char notefile [] = "note.pad";
main()
{
load_help("tcprogs.hlp");
exec();
}
Листинг 10.3:exec.c
/* ----------------exec.c------------------- */
#include "stdio.h"
#include "twindow.h"
/* ----------Локальные прототипы----------- */
void testmove(void);
void promote(void);
void ccolor(void);
void fasttest(void);
void notepad(void);
void ordent(void);
void poems(void);
void maxims(void);
/* -----------Таблицы меню------------------ */
char *dselcs[] = {
" move ",
" promote ",
" colors ",
" fast ",
NULL
};
char *pselcs[] = {
" notepad ",
" orders ",
" poetry ",
" sayings ",
NULL
};
static void (*dfuncs[])()={testmove,promote,ccolor,fasttest};
static void (*pfuncs[])()={notepad,ordent,poems,maxims};
static MENU tmn [] = {
{" demos ", dselcs, dfuncs},
{" programs ", pselcs, pfuncs},
{NULL,NULL,NULL}
};
void exec()
{
menu_select(" TC Executive ", tmn);
}
Листинг 10.4:menu.prj
menu.c
exec.c (twindow.h, keys.h)
testmove (twindow.h, keys.h)
promote (twindow.h, keys.h)
ccolor (twindow.h, keys.h)
fasttest (twindow.h)
notepad (twindow.h)
ordent (twindow.h)
maxims (twindow.h, keys.h)
poems (twindow.h, keys.h)
editor (twindow.h, keys.h)
entry (twindow.h, keys.h)
thelp (twindow.h, keys.h)
tmenu (twindow.h)
twindow (twindow.h, keys.h)
ibmpc.obj
Для запуска программы-примера введите следующую команду:
C"MENU
Вид экрана дисплея, изображенный на рисунке 10.2, будет
соответствовать ситуации, когда на экране отображается скользящее
меню-строка. В этом примере доступны для выбора только два
элемента меню, однако скользящее меню-строка может включать в
себя до шести элементов, доступных для выбора пользователем.
Обратимся теперь к массиву структур MENU, поименованному как
tmn (см. листинг 10.3 программы exec.c). Массив содержит лишь два
элемента, соответствующих элементам горизонтального меню,
отображаемых пользователю. Структура MENUI определена в twindow.h
(см. Главу 6) и включает три элемента: указатель на имя
выбранного элемента меню, указатель на массив имен элементов
"всплывающего" меню, соответствующего элементу горизонтального
меню, и указатель на массив указателей функции, реализующей ту
или иную операцию.
---------------------------------------------------------------¬
¦----------------------- TC Executive ------------------------¬¦
¦¦ demos programs ¦¦
¦L-------------------------------------------------------------¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
L---------------------------------------------------------------
Рис. 10.2 Горизонтальное скользящее меню.
Для перемещения по меню с целью выборки нужного элемента из
горизонтального меню используются клавиши перемещения курсора
вправо и влево. Если текущим является элемент меню demos, нажмите
клавишу "Ввод". Теперь вы можете увидеть на экране картинку,
аналогичную изображенной на рисунке 10.3, на котором также
изображено и вертикальное меню, соответствующее элементу
горизонтального меню demos. Теперь вернемся к листингу 10.3 и
обратим внимание на содержимое первого элемента массива tmn,
который соответствует элементу горизонтального меню demos. Здесь
dselcs - адрес, указывающий размещение массива указателей типа
char на имена элементов demosвертикального "всплывающего" меню,
dfuncs - адрес размещения массива указателей функций. Каждый из
указателей этого массива адресует одну из функций, которые
рассматривались в качестве примеров в предыдущих главах. Для
перемещения по вертикальному меню применяются клавиши перемещения
курсора вверх и вниз. Если вы остановились на каком-то выборе,
нажмите клавишу "Ввод". После этого будет выполнена одна из
функций в зависимости от того, какой элемент меню вы выбрали.
После передачи управления из этой функции в точку ее вызова (как
было показано в этой главе, для функций, требующих какого-либо
выбора от пользователя, это клавиша "ESC", на экране
восстанавливается изображение горизонтального и вертикального
меню в том состоянии, которое предшествовало вызову функции, и
разрешена дальнейшая работа с ними. Для уничтожения текущего
вертикального меню нажмите клавишу "ESC". Для выхода из программы
и уничтожения горизонтального меню требуется повторное нажатие
клавиши "ESC".
---------------------------------------------------------------¬
¦----------------------- TC Executive ------------------------¬¦
¦¦ demos programs ¦¦
¦LT---------T--------------------------------------------------¦
¦ ¦ move ¦ ¦
¦ ¦ promote ¦ ¦
¦ ¦ colors ¦ ¦
¦ ¦ fast ¦ ¦
¦ L---------- ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
L---------------------------------------------------------------
Рис. 10.3 "Всплывающее" вертикальное меню
Резюме
-----------------------------------------------------------------
Итак, описание библиотеки функций оконной технологии
завершено. Они позволяют поддерживать программное обеспечение на
таком профессиональном уровне развития, для которого традиционно
использовались возможности, предоставляемые фирмами-поставщиками
библиотек оконной поддержки, изучение которых требовало много
времени, да и цена их была побольше, чем стоимость этой книги.
Версия описанного в этой книге пакета программ может быть
использована для дальнейшего комплексного развития программных
систем, после чего эти системы не требуют какой-то дополнительной
перенастройки в связи с мобильностью программ, составляющих
описываемый пакет.
В следующей главе будут рассмотрены резидентные утилиты.
Функции поддержки окон, описанные в этой книге, могут быть
включены в обычные однозадачные программы, выполняемые в среде
DOS, или могут быть преобразованы в программы, которые постоянно
находятся в памяти, и инициализация их выполнения закрепляется за
определенными клавишами. Технические приемы написания таких
программ (они еще носят название резидентных программ или
резидентных утилит), а также примеры их использования при
разработке систем рассматриваются в следующих главах.
Г Л А В А 11
Резидентные программы
-----------------------------------------------------------------
Повсюду в этой книге "PC" (ПК) относится к семейству IBM PC
и совместимым с ними компьютерам; однако персональные компьютеры
не всегда были такими, как PC. Первые ПК создавались на знаниях и
интересе любителей. ПК развивались вместе с развитием
микрокомпьютерной технологии от домашних игрушек до серьезных
систем. Программное обеспечение и операционные системы
развивались вместе с компьютерами. Ранние операционные системы
(ОС) представляли собой немногим более, чем командные процессоры
Бейсика или Паскаля, которые обеспечивали поддержку языков и
простое управление файлами. Эти системы обычно ориентировались на
конкретный компьютер и были несовместимы с другими. Когда
компьютеры начали ориентироваться на массовое применение,
операционные системы начали стабилизироваться. Среди них были
Apple-DOS, NorthStar DOS, TRSDOS, и CP/M. Все они имели похожие
характеристики:
- однопрограммный однопользовательский режим работы
- поддержка файлового каталога
- поддержка интерпретаторов и компиляторов языков
программирования
- несовместимость программ и данных между системами
С великой проницательностью Гарри Килдалл создал CP/M как
открытую ОС. Изначально предназначавшаяся для поддержки создания
программ для Intel MDS, эта ОС не ориентирована на какую-либо
модель или марку компьютеров. CP/M состоит из базовой системы
ввода-вывода (BIOS), базовой дисковой операционной системы
(BDOS), и командного процессора (CCP). BIOS ориентирована на
работу с аппаратурой компьютера и предназначена для управления
консолью, принтером и дисковой системой. Путем написания
соответствующей BIOS производители компьютеров могли использовать
приемлемую и развитую операционную систему с тысячами доступных
программ. Благодаря своей адаптируемости CP/M стала промышленным
стандартом ОС для ПК на микропроцессорах 8080 или Z80.
Микропроцессоры 8080 и Z80 могли адресовать только 64К
памяти, поэтому CP/M строилась как однопользовательская
однопрограммная ОС.Была построена и многопользовательская версия,
названная MP/M, но она не стала промышленным фаворитом, каким
была CP/M, в основном из-за медленнной работы (8080 не очень
быстрый процессор), и потому, что ПК не особенно подходят для
многопользовательской работы.
ДОС, управляющая работой PC, является адаптацией ОС,
созданной для использования на 8086, и заметно похожей на CP/M.
Microsoft купила ее у создателя - фирмы Seattle Computer
Products, а IBM купила лицензию у Microsoft. ДОС до сих пор во
многом похожа на CP/M. ДОС состоит из трех модулей, схожих по
функциям с BDOS, CCP и BIOS в CP/M; и пользовательский интерфейс
почти идентичен используемому в CP/M. У ДОС есть дополнительные
возможности, такие, как каналы, фильтры, переназначение
ввода-вывода, пометка файлов временем и датой, и иерархическая
структура файлового каталога. ДОС по-прежнему
однопользовательская однозадачная ОС, в чем совпадает с CP/M.
Первые компьютеры IBM PC были очень похожи на своих
предшественников с микропроцессорами 8080 и Z80; у них было 64К
памяти, флоппи-диски и процессор немного побыстрее, чем Z80.
Однозадачная ДОС была подходящей и адекватной этим компьютерам,
но PC имели три архитектурные особенности, предназначенные для
расширения. Микропроцессор 8088 адресует до 1М памяти; он имеет
векторную систему прерываний; клавиатура и дисплей IBM PC
являются составной частью компьютера, в отличие от
видеотерминалов, присоединенных через последовательный порт. Эти
характеристики легли в основу ограниченного вида
мультизадачности, который развивался на PC и сейчас известен как
программы, остающиеся в памяти (TSR).
ДОС включает две функции, позволяющие программе объявить
себя резидентной. Эти функции похожи, но имеют небольшие
различия. Функция 0х31 прерывания ДОС 0х21 заканчивает выполнение
программы, но оставляет ее резидентной. ДОС не будет покушаться
на память, принадлежащую программе. Прерывание ДОС 0х27 делает то
же самое, но ограничивает размер программы величиной 64К.
Эти две функции предназначались в ДОС не для написания
резидентных утилит, а для того, чтобы создатели системы могли
написать программы обработки прерываний (ISR), поддерживающие
дополнительные устройства ввода-вывода, такие, как мышь,
графический планшет, или джойстик. Эти устройства не являются
стандартной частью PC и, соответственно, не имеют стандартного
программного интерфейса с ДОС. ISR могут поддерживають и другой
вид программ, не обязательно связанных с дополнительными
устройствами, но расширяющих пользовательский интерфейс с
компьютером. Это TSR-программы; два наиболее популярных вида
таких программ - это расширители клавиатуры и
программы-секретари. Расширители клавиатуры, такие, как Prokey и
Superkey, позволяют пользователю присвоить значения символов
функциональным клавишам, "Alt"-key комбинациям, или любым другим
клавишам. Программы-секретари, такие, как Sidekick и Homebase,
предлагают записную книжку, калькулятор, календарь, автовызывное
телефонное устройство и другие возможности рабочего стола,
вызываемые нажатием клавиши.
Среди других TSR-программ : программы-корректоры, системы
обработки структуризованных текстов, печать со спулингом,
расширения командного процессора ДОС, отладчики, часы с
будильником. Эти программы и многочисленные представители других
резидентных программ имеются в продаже, в источниках бесплатного
программного обеспечения, или в исходных текстах, публикуемых в
журналах.
Эта глава представляет и объясняет класс программ для PC,
известных под разными именами, среди которых всплывающие
(pop-up), TSR, резидентные утилиты, и программы-секретари. Такие
программы уникальны, так как после исполнения они остаются
резидентными в памяти и часто ее не покидают до выключения
компьютера. Будучи резидентными, они выполняются (или
"всплывают") при вызове.
Типичная TSR-программа вызывается внешним событием, обычно
называемым "горячим ключом". Горячий ключ - это ключевая строка,
формируемая при нажатии пользователем комбинации клавиш,
зарезервированной для вызова утилиты. Естественно, эта комбинация
не должна обычно использоваться для других целей.
Активизация TSR-программы прерывает выполнение текущей
программы на время работы TSR-программы. После окончания
TSR-программы прерванная программа продолжает работу. Прерванный
процесс может быть нерезидентной программой, другой
TSR-программой, или самой ДОС.
Загрузка нескольких TSR-программ в память превращает ДОС -
однозадачную по сути операционную систему - в ограниченную, в чем
-то калечную мультизадачную ОС.
Прерывания
-----------------------------------------------------------------
Чтобы понять сущность TSR-программ, вы должны понять систему
прерываний, потому что эти программы используют структуру
прерываний ДОС и PC. Это обсуждение ни в коей мере не является
исчерпывающим описанием прерываний, и этим вы поощряетесь к
исследованию предмета с использованием материалов, посвященных
архитектуре 8086/80286 и PC. Здесь объясняется, что такое
прерывания и как они используются, но без детальных спецификаций.
Этого вам хватит, чтобы понять TSR-программы.
Прерывание - это кратковременное приостановка текущей
прочедуры программы, позволяющая выполнить другую процедуру.
После завершения прерывания прерванная программа продолжает
выполняться так, как будто бы ничего не происходило. Эти две
процедуры могут быть несвязанными - и прерывание не окажет
никакого воздействия на прерванную процедуру. Они могут быть
взаимозависимы - прерванная программа может быть модифицирована
процедурой обработки прерывания. Прерывание может быть вызвано
внешним по отношению к выполняемой программе событием или в
результате действий самой программы. Прерывание может быть
вызвано аппаратно или командой из программы.
Векторы прерывания
-----------------------------------------------------------------
В компьютере PC имеется 256 различных прерываний, с номерами
от 0 до 0хff. Некоторые из них определены для использования
процессором. Например, прерывание 0 возникает при делении на 0.
Другие определены для вызова функций BIOS, третьи - для
использования ДОС. Напомним, что 8088/8086/80286 - это
микропроцессор, PC - компьютер, построенный на его базе, а ДОС -
это операционная система. Для каждого из этих трех архитектурных
слоев определен свой набор прерываний. Оставшиеся прерывания
доступны для использования прикладными программами и программами
обслуживания устройств.
Каждое прерывание представлено в памяти четырехбайтным
значением адреса. Эти значения располагаются в памяти со
смещениями от 0 до 0х3ff. При прерывании содержимое регистра
признаков и четырехбайтный адрес выполняемой команды сохраняется
в стеке.После этого прерывания запрещаются, и начинает
выполняться программа с адреса, соответствующего происшедшему
прерыванию. Эта программа должна сохранить используемые ей
регистры, выполнить свою задачу, восстановить значения регистров,
и выполнить команду возврата из прерывания, которая
восстанавливает адрес прерванной программы и регистр признаков,
так что прерванная программа продолжит свое выполнение с того
места, где была прервана.
Аппаратные прерывания
-----------------------------------------------------------------
Аппаратные прерывания вызываются событиями, физически
связанными в аппаратуре с соответствующими векторами прерываний.
Например, клавиатура в PC связана с прерыванием 9. Нажатие
клавиши вызывает прерывание выполняемой программы, как было
описано выше, и переход по адресу, находящемуся в векторе
прерывания, соответствующему прерыванию 9. В памяти этот вектор
находится по адресу 0х24 (9*4 байт ).
Программные прерывания
----------------------------------------------------------
...Поділитися у соцмережах