Листинг 7-8. SNAPSHOT.C
-------------------------------------------------------------------
/*
Наименование: SNAPSHOT.C
Назначение: утилита, остающаяся резидентно в памяти после
завершения, для сохранения образов текстовых
экранов в pасшиpенной памяти.
*/
#include
#include
#include
#include
#include
#include "emmconst.h" /*константы менеджеpа pасшиpенной памяти*/
#include "emmtypes.h" /*структуры данных менеджеpа pасшиpенной па-
мяти*/
#include "emmerr.h" /*коды ошибок менеджеpа pасшиpенной памяти*/
#include "emmfunc.h" /*объявления функций менеджеpа pасшиpенной
памяти*/
#define PRTSC_INT 5 /*прерывание печати экрана*/
#define HANDLE_NAME "SNAPSHOT" /*имя обpаботчика pасшиpен-
ной памяти*/
#define MAX_SCR 500 /*максимальное кол-во сохра-
няемых экранов*/
#define MDA_SEG 0xB000 /*сегмент буфера адаптера
монохромного дисплея*/
#define CGA_SEG 0xB800 /*сегмент буфера адаптера
цветного графического дисплея*/
#define SCR_ROWS 25 /*предполагается 25 строк -
процедура должна определить*/
/*фактическое кол-во строк
зависит от адаптера*/
#pragma pack(1) /*структура данных, выровненная по байтам*/
#define DisplayError(rc) ShowEMMErr(rc, __LINE__, __FILE__)
typedef struct bios_video_data { /*базисные видеоданные BIOS*/
unsigned char crt_mode; /*режим дисплея*/
unsigned int crt_cols; /*кол-во колонок на экране*/
unsigned int crt_len; /*длина буфера регенерации в
байтах*/
unsigned int crt_start; /*начальный адрес в буфере
регенерации*/
unsigned int cursor_pos[8]; /*положение курсора для 8
страниц*/
unsigned int cursor_mode; /*текущая установка режима
курсора*/
unsigned char active_page; /*текущая отображаемая стра-
ница*/
unsigned int addr_6845; /*адрес базы активной платы
отображения*/
unsigned char crt_mode_set; /*текущая установка регистра
3х8*/
unsigned char crt_palette; /*текущая установка палитры
- цветная плата*/
} BIOS_VIDEO_DATA;
typedef struct scr { /*дескриптор данных экрана*/
unsigned int scr_page; /*начальная страница pасши-
pенной памяти для экранов*/
unsigned int scr_offset; /*начальное смещение расши-
ренной памяти для экранов*/
unsigned int scr_width; /*кол-во колонок на экране*/
unsigned int scr_len; /*длина экрана в байтах*/
} SCR;
typedef struct scr_index { /*индексная структура экрана*/
void (interrupt far *scr_int5)(); /*указатель на нашу програм-
му обслуживания прерывания*/
unsigned int scr_count; /*кол-во экранов, сохранен-
ных в текущий момент*/
unsigned int scr_max; /*максимальное кол-во экранов
для сохранения*/
} SCR_INDEX;
/*
глобальные данные
*/
void (interrupt far *old_int5)(); /*старый вектор печати экрана*/
PMAP *emm_save; /*указатель на область сохране-
ния контекста менеджеpа pасшиpенной памяти*/
unsigned int emm_tpages, /*общее кол-во страниц pасши-
pенной памяти*/
emm_apages, /*доступное кол-во страниц
pасшиpенной памяти*/
emm_handle, /*обpаботчик pасшиpенной памя-
ти*/
emm_pages, /*кол-во страниц, принадлежащих
обpаботчику*/
isr_status, /*0: isr следует сцепить,
<>0: isr следует обслужить*/
terminate_flag; /*1: закончить эту программу*/
char far *page_frame; /*удаленная -> в кадровый буфер*/
SCR_INDEX far *ip; /*удаленная -> в индекс экрана*/
SCR far *sp; /*удаленная -> в дескриптор экрана*/
BIOS_VIDEO_DATA far *vp = (BIOS_VIDEO_DATA far *) 0x00400049L;
/*удаленная -> в область видео дан-
ных BIOS*/
MOVE_XCHG mcb; /*структура передвижения/обмена
областей*/
#pragma check_stack(off)
/*очищается, если "control-c"*/
void break_handler(sig_type)
int sig_type;
{
signal(SIGINT, SIG_IGN); /*запрещает "control-c" во время
драйвера*/
cleanup;
exit(0);
}
/*
драйвер прерывания для прерывания печати экрана
Делает моментальный снимок обычной памяти в
pасшиpенную память
*/
void interrupt cdecl far int5_isr(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,
cs,flags)
unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags;
{
static int rc = 0; /*отслеживается последний код
возврата*/
int status;
if (!isr_status) /*если обслуживание прерывания
не активизировано, подцепить к
предыдущему драйверу прерывания*/
_chain_intr(old_int5);
if (rc == 0) { /*продолжать только, если ранее не
было ошибок*/
rc = EMSGetPageMap(emm_save);
if (rc == 0) { /*контекст сохранен успешно*/
/*сделать снимок экрана*/
rc = dump_screen();
/*восстановить контекст предыдущего отображения*/
if (status = EMSSetPageMap(emm_save))
rc = status; /*обновить код ошибки*/
}
}
/*если произошла какая-либо ошибка, объявить вслух*/
if (rc)
Beep(32000);
}
dump_screen()
{
int rc;
unsigned int overflow, new_offset, scr_size;
/*отобразить индексные данные экрана в логической странице
0 в физическую страницу 0*/
if (rc = EMSMapHandlePage(emm_handle, 0, 0))
return(rc); /*отказ*/
/*убедитесь, что не вышли из индексных элементов*/
if (ip->scr_count >= ip->scr_max)
return(1); /*переполнение индекса*/
/*если экран переполняет страницу, разместите одну или более
дополнительных страниц*/
scr_size = vp->crt_cols * SCR_ROWS * 2; /*кол-во байтов в
экране*/
new_offset = sp->scr_offset + scr_size; /*новое смещение
в буфере сохранения*/
if (new_offset > PAGE_SIZE) { /*экран переполняет страницу*/
overflow = new_offset - PAGE_SIZE; /*величина переполне-
ния страницы*/
emm_pages += (overflow / PAGE_SIZE); /*кол-во необходимых
дополнительных страниц*/
new_offset = overflow % PAGE_SIZE; /*размер добавочного
фрагмента*/
if (new_offset) /*прибавить страницу на добавок,*/
emm_pages++; /*если необходимо*/
if (rc = EMSReallocPages(emm_handle, &emm_pages))
return(rc); /*отказ*/
}
/*снимок, отображающий видеоэкран в расширенную память*/
mcb.region_length = (long) scr_size; /*кол-во байтов на экра-
mcb.source.memory_type = CONV_MEM; не в обычной памяти*/
mcb.source.handle = 0; /*никакой обpаботчик не исп-ся*/
mcb.source.initial_offset = vp->crt_start; /*начальное сме-
щение экрана*/
mcb.source.initial_seg_page = (vp->crt_mode == 7) ? MDA_SEG :
CGA_SEG;
/*работает только с цветным/монохромным текстом*/
mcb.dest.memory_type = EXP_MEM; /*идет в расши-
ренную память*/
mcb.dest.handle = emm_handle; /*предварительно
размещенный обpаботчик*/
mcb.dest.initial_offset = sp->scr_offset; /*следующее до-
ступное смещение*/
mcb.dest.initial_seg_page = sp->scr_page; /*в текущей стра-
нице*/
if (rc = EMSMoveRegion(&mcb)) /*функция "Передвинуть область
памяти" спецификации pасшиpенной памяти*/
return(rc); /*отказ*/
Beep(1000); /*выдать короткий звуковой сигнал - успех*/
/*обновить индексные данные экрана ("Передвинуть область" не
нарушает контекста отображения*/
ip->scr_count++; /*уменьшение кол-ва сохраненных экранов*/
sp->scr_len = src_size; /*запомнить кол-во байтов на экране*/
sp->scr_width = vp->crt_cols;/*запомнить кол-во колонок в
строке*/
sp++; /*указать на следующий индексный элемент*/
sp->scr_len = 0; /*новый еще не снятый экран,*/
sp->scr_width = 0; /*поэтому нулевые длина и ширина*/
sp->scr_page = emm_pages -1; /*новый экран идет на послед-
нюю размещенную страницу,*/
sp->scr_offset = new_offset; /*непосредственно следуя за
предыдущим экраном*/
return(rc); /*успех*/
}
/*освободить расширенную память, если размещена*/
cleanup()
{
int rc;
/*игнорировать код возврата, так как вызов может быть из
ошибочной процедуры*/
if (emm_handle != -1)
rc = EMSDeallocatePages(emm_handle);
}
#pragma check_stack(on)
main(argc, argv)
int argc;
char *argv[];
{
int emm_present, rc;
unsigned int far *pseg_top;
char emm_ver[4];
get_opts(argc, argv); /*получить переключатели командной
строки*/
emm_handle = -1; /*нет размещенных обpаботчиков
pасшиpенной памяти*/
/*установить драйвер "Control-C" (прерывание)*/
signal(SIGINT, break_handler);
/*проверка наличия pасшиpенной памяти*/
if (rc = emm_exists(emm_present)) { /*тест наличия
менеджеpа pасшиpенной памяти не прошел*/
printf("snapshot: EMM presence test failed, rc: %d", rc);
exit(2);
}
if (!emm_present) { /*нет pасшиpенной памяти*/
printf("snapshot: No expanded memory is present");
exit(1);
}
/*получить версию спецификации pасшиpенной памяти, которую
поддерживает менеджеp pасшиpенной памяти*/
if (rc = EMSGetVersion(emm_ver)) {
DisplayError(rc);
exit(1);
}
/*убедитесь, что это - по крайней мере, версия 4.0*/
if (*emm_ver < '4') { /*требуется спецификация pасшиpенной
памяти LIM 4.0 или выше*/
printf("snapshot: Unsupported EMM version detected: %s,
LIM EMS 4.0 or greater is required", emm_ver);
exit(1);
}
/*получить указатель на кадр страниц спецификации pасшиpенной
памяти*/
if (rc = EMSGetFrameAddr(&page_frame)) {
DisplayError(rc);
exit(1);
}
/*поиск обpаботчика спецификации pасшиpенной памяти, который
содержит запомненные экраны*/
rc = EMSSearchHandleName(HANDLE_NAME, &emm_handle);
/*ошибка, если любой код возврата, отличный от 'нормально'
или 'обpаботчик не найден'*/
if (rc != 0 && rc != HNDVLNFD) {
DisplayError(rc);
exit(1);
}
/*или закончить и остаться резидентно, установить программу,
остающуюся после завершения резидентно, или показать ее текущее
состояние*/
if (terminate_flag) { /*пользователь запросил завершение*/
if (rc == 0) /*обpаботчик с нашим именем существует,*/
terminate(); /*поэтому постараться снять себя*/
else { /*обpаботчик не существует, поэтому не мо-
жет завершиться */
printf("snapshot: can't terminate - not installed");
exit(1);
}
} else { /*или установиться или выдать состояние*/
/* если обработчик, именованный HANDLE_NAME, уже сущест-*/
/*вует, только сообщить, сколько памяти спецификации */
/*расшиpенной памяти в настоящий момент размещено, и как*/
/*много экранов хранится в ней. В противном случае, уста-*/
/*новить программу обслуживания прерывания для прерывания*/
/*печати и сделать данную программу резидентной*/
if (rc == 0) /*обpаботчик с нашим именем уже сущест-*/
show_status(); /*вует,поэтому только показать состоя-
ние*/
else { /*обpаботчик не существует,*/
install(); /*поэтому разместить обpаботчик и уста-
новить программу обработки прерывания*/
/*завершиться и остаться резидентно*/
FP_SEG(pseg_top) = _psp; /*конечный параграф програм-
мы находится по psp+2 */
FP_OFF(pseg_top) = 2;
printf("snapshot: TSR installing at segment [%04X],
size %u paragraphs\n", _psp, *pseg_top - _psp);
_dos_keep(0, *pseg_top - _psp); /*кол-во параграфов
в программе*/
}
}
}
/*отобразить идентификатор обpаботчика, кол-во логических*/
/*страниц, размещенных для него, и кол-во экранов, запомнен-*/
/*ных в данный момент в pасшиpенной памяти*/
show_status()
{
int rc;
unsigned int alloc_pages, screens;
/*определение кол-ва страниц, размещенных для данного обpа-*/
/*ботчика менеджеpа pасшиpенной памяти*/
if (rc = EMSGetHandlePages(emm_handle, &alloc_pages)) {
DisplayError(rc);
cleanup();
exit(1);
}
/*отобразить первую логическую страницу, содержащую индекс
экрана, в нулевую физическую страницу*/
if (rc = EMSMapHandlePage(emm_handle, 0, 0)) {
DisplayError(rc);
cleanup();
exit(1);
}
/*получить адресуемость для структуры данных индексов экранов
в pасшиpенной памяти*/
ip = (SCR_INDEX far *) page_frame;
/*печатать текущее состояние*/
printf("snapshot: status - EMS handle (%d); EMS
pages (%d); screens (%d)\n", emm_handle, alloc_pages,
ip->scr_count);
/*перестать отображать страницу индексов экрана*/
if (rc = EMSMapHandlePage(emm_handle, -1, 0)) {
DisplayError(rc);
cleanup();
exit(1);
}
}
/*Получить обpаботчик спецификации pасшиpенной памяти с од-*/
/*ной страницей от менеджеpа pасшиpенной памяти и дать ему*/
/*наименование, так чтобы другие программы могли обращаться*/
/*к нему. Инициализировать структуру индексных данных экра-*/
/*нов, которая будет размещена в начале первой страницы спе-*/
/*цификации pасшиpенной памяти. Затем подставьте программу*/
/*обслуживания прерывания для прерывания печати экрана, так*/
/*чтобы образы экранов сохранялись в pасшиpенной памяти, */
/*когда пользователь нажимает клавишу PrtScr.*/
install()
{
int rc, context_bytes;
/*разместить одну страницу для начала*/
emm_pages = 1;
if (rc = EMSAllocatePages(&emm_handle, emm_pages)) {
DisplayError(rc);
exit(1);
}
/*дать обpаботчику имя, так чтобы другие программы могли */
/* найти его */
if (rc = EMSSeyHandleName(emm_handle, HANDLE_NAME)) {
DisplayError(rc);
cleanup();
exit(1);
}
printf("snapshot: allocated expanded memory handle # %d with
name '%s'\n", emm_handle, HANDLE_NAME);
/* инициализировать данные в странице индексов экранов,*/
/* которые будут запоминаться в логической странице 0 */
if (rc = EMSMapHandlePage(emm_handle, 0, 0)) {
DisplayError(rc);
cleanup();
exit(1);
}
/*получить адресуемость для структуры данных индексов экранов
в pасшиpенной памяти*/
ip = (SCR_INDEX far *) page_frame;
/* инициализировать данные в ней */
ip->scr_count = 0; /*кол-во сохраненных экранов*/
ip->scr_max = MAX_SCR; /*максимальное кол-во сохранен-
ных экранов*/
ip->scr_int5 = int5_isr; /*указатель на нашу программу
обслуживания прерывания печати экрана*/
sp = ip->scr_idx; /* -> первый индексный элемент*/
sp->scr_page = sizeof(*ip) / PAGE_SIZE; /*экраны начинаются*/
sp->scr_offset = sizeof(*ip) % PAGE_SIZE;
/*сразу за индексом*/
sp->scr_len = 0; /*вначале пусто*/
sp->scr_width = 0;
/*перестать отображать страницу индексов экрана*/
if (rc = EMSMapHandlePage(emm_handle, -1, 0)) {
DisplayError(rc);
cleanup();
exit(1);
}
/*разместить область сохранения контекста pасшиpенной памяти,
используемую драйвером прерывания печати экрана*/
if (rc = EMSGetPageMapSize(&context_bytes)) {
DisplayError(rc);
cleanup();
exit(1);
}
if ((emm_save = (PMAP *) malloc(context_bytes)) == NULL) {
printf("snapshot: Couldn't allocate %d bytes for context
save area", context_bytes);
cleanup();
exit(1);
}
/*установить обpаботчик прерывания для перехватывания запросов
печати экрана*/
old_int5 = _dos_getvect(PRTSC_INT); /*сохранить старый век-
тор прерывания*/
_dos_setvect(PRTSC_INT, int5_isr); /*установить новый век-
тор прерывания*/
printf("snapshot: print screen interrupt handler is installed\n");
isr_status = 1;
/* пусть новый драйвер обслуживает прерывания*/
printf("snapshot: print screen interrupt handler is activated\n");
}
/* снять программу, резидентную после завершения, из памяти
по запросу пользователя */
terminate()
{
int rc;
unsigned int tsr_psp; /*префиксный программный сегмент
активной программы, резидентной по завершении*/
unsigned int far *envptr; /*указатель среды программы, ре-
зидентной по завершении*/
void (interrupt far *our_int5)(); /*адрес установленной прог-
раммы, резидентной по завершении*/
/* приостановить обработку прерываний печати экрана */
isr_status = 0;
printf("snapshot: print screen interrupt handler
deactivated\n");
/* отображение в страницу, содержащую индекс экрана */
if (rc = EMSMapHandlePage(emm_handle, 0, 0)) {
DisplayError(rc);
cleanup();
exit(1);
}
/*получить адресуемость для структуры данных индексов экра-*/
/*нов в pасшиpенной памяти, так чтобы мы могли получить ад-*/
/*рес программы обслуживания прерывания, которую мы установ-*/
/*вили, когда данная программа стартовала*/
ip = (SCR_INDEX far *) page_frame;
our_int5 = ip->scr_int5; /*получить запомненный адрес
программы обслуживания прерывания*/
/* освободить pасшиpенную память */
cleanup();
printf("snapshot: expanded memory handle %d deallocated\n",
emm_handle);
/* если никакой другой драйвер печати экрана не был установ-*/
/*лен перед нами, отключить программу обслуживания прерыва-*/
/*ния и вновь установить программу*/
if (_dos_getvect(PRTSC_INT) == our_int5) { /*наша программа
обслуживания прерывания - первая*/
/*восстановить старый вектор прерывания печати экрана */
_dos_setvect(PRTSC_INT, old_int5);
printf("snapshot: old print screen interrupt handler
restored\n");
/* освободить строки среды программы, резидентной по завер-
шении, и программный сегмент*/
tsr_psr = FP_SEG(our_int5) - 16; /*PSP начинается за 1666
параграфов до сегмента кода*/
printf("snapshot: deallocating TSR at segment [%04X]\n",
tsr_psp);
FP_SEG(envptr) = tsr_psp; /*указатель среды - по смеще-
нию*/
FP_OFF(envptr) = 0x2C; /* 2Ch в префикс сегмента про-
граммы*/
_dos_freemem(*envptr); /*освободить строки среды*/
_dos_freemem(tsr_psp); /*освободить программный сег-
мент*/
} else /*наша программа обслуживания прерывания не является
первой в цепи, нельзя снимать программу, резидентную
после завершения*/
printf("snapshot: cannot deallocate TSR - print screen ISR
is not first in chain\n");
}
/*процесс командной строки переключается в форму /L, где */
/*'L' - идентификация переключателя по одному символу. Воз-*/
/*вращается индекс первого элемента в массиве указателей, */
/*следующем за переключателями*/
get_opts(cnt, ptr)
int cnt;
char *ptr;
{
int argc;
terminate_flag = 0; /*сбросить флаг завершения*/
arc = 1;
while (*++ptr)[0] == '/' {
switch(*ptr)[1]) {
case '?' /*команда отображения и исполь-
зование переключателей*/
printf("snapshot: saves text screen images to
expanded memory\n");
printf("usage: snapshot [/X]\n");
printf(" /X - terminates snapshot");
exit(0);
break;
case 'x': /*завершает запрос*/
case 'X':
terminate_flag = 1;
break;
default: /*неизвестный переключатель*/
printf("'%c' is an unknown option\n", (*ptr)[1]));
break;
}
argc++;
}
return(argc);
}
-------------------------------------------------------------------
|