На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 7 / Листинг 7-8. SNAPSHOT.C Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Листинг 7-8. SNAPSHOT.C

                    Листинг 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);
        }
        -------------------------------------------------------------------

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz