1 2 3 4 5 6 7 8 Ім'я файлу: ЗВІТ КУРСАЧА - РЕЗИДЕНТНИЙ КАЛЬКУЛЯТОР.docx Розширення: docx Розмір: 511кб. Дата: 05.11.2021 скачати 5.5. Вимоги до апаратного і програмного забезпеченняВимоги до програмого забеспеченні: Windows XP і вище, необхідні бібліотеки, драйвера для підтримки клавіатури. Вимоги до апаратного забеспечення: ОЗУ 1ГБ (для Windows XP), 2ГБ (для Windows 7) , 3+ГБ (для Winsows 10). ВИСНОВОКИ Під час виконання курсової роботи я дізнався, що таке резидентні програми, для чого їх використовують, де вони використовуються, дізнався про процес створення таких програм та за допомогою отриманих знань, в тому числі протягом усього курсу «Системне програмування та операційні системи в комп'ютерній поліграфії» мені вдалося створити програму «Резидентний калькулятор» на основі мов С та Асемблер. Також для виконання цієї курсової роботи мені довелося ознайомитися з такою мовою як Асемблер, частково її розібрати та вивчити. Звісно треба ще дуже багато старань та зусиль для повного вивчення цієї мови, але на рівні чайника я вже розібрався. СПИСОК ВИКОРИСТАНОХ ДЖЕРЕЛMS-DOS для программиста [Електронний ресурс] – Режим доступу: http://www.frolov-lib.ru/books/bsp.old/v18/ch5.html#b5.6 C для профессиональных программистов [Електронний ресурс] – Режим доступу: http://aiut.tugab.bg/Library/Software/Doc/C/c_za_progr.pdf Stack Overflow [Електронний ресурс] – Режим доступу: https://stackoverflow.com/ Резидентные программы [Електронний ресурс] – Режим доступу: http://www.realcoding.net/articles/chast-iii-rezidentnye-programmy.html ДОДАТКИТЕКСТ ПРОГРАМИ Розділ ініціалізації програми резидентного калькулятора дуже невеликий і цілком поміщається в наступній функції: void interrupt test(bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags) unsigned bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags; main () void interrupt tsr_ap (); / * Вхід в прикладну програму * / main (){ struct address { char far * p;}; / * Адреса переривання друку екрану * / struct address far * addr = (struct address far *) 20; addr-> p = (char far *) tsr_ap; set_vid_mem (); tsr (2000);} Функція tsr_ap () є точкою входу в прикладну частину TSR-програми. Вона використовує покажчик на вміст таблиці векторів, відповідне переривання 5. Значення глобального покажчика vid_mem встановлюється за допомогою функції set_vid_mem, що приводиться нижче. set_vid_mem (){ int vmode; vmode = video_mode (); if ((vmode! = 2) && (vmode! = 3) && (vmode! = 7)) { printf ( "video must be in 80 column text mode"); exit (1);} / * Встановити відповідну адресу відеопам'яті * / if (vmode == 7) vid_mem = (char far *) 0xB0000000; else vid_mem = (char far *) 0xB8000000;} Вихід з функції main () здійснюється шляхом звернення до функції tsr (), наведеної нижче. / * Завершити виконання, але залишити резидентною * / tsr (size) unsigned size;{ union REGS r; rhah = 49; / * Завершити і залишити резидентною * / rhal = 0; / * Код повернення * / rxdx = size; int86 (0x21, & r, & r);} Параметр size, який визначається в регістрі DX, використовується для того, щоб повідомити DOS, скільки пам'яті потрібно для розміщення ТSR-програми. Розмір пам'яті визначається в 16-байтних параграфах. Після завершення виконання функції маin () програма залишається в пам'яті, і ніяка інша програма не може бути завантажена на її місце. Це означає, що прикладна частина програми в будь-який момент часу готова бути запущеною натисканням клавіші PrtSc. Точкою входу в прикладну частину TSR-програми повинна бути функція типу interrupt. Запуск прикладної частини виконується шляхом виклику функції window_main(). / * Точка входу в прикладну частину TSR-програми * / void interrupt tsr_ap (){ if (! busy) { busy =! busy; window_main (); busy =! busy;}} Глобальна змінна busy спочатку встановлюється в 0. Прикладна частина TSR-програми не є повторно входимою, отже, вона не повинна запускатися двічі за час одного використання. Змінна busy використовується як раз для того, щоб запобігти цьому. / * TSR-програма, яка використовує переривання друку екрану * / #include "dos.h" #include "stdlib.h" #define BORDER 1 #define ESC 27 #define MAX_FRAME 1 #define REV_VID 0x70 #define NORM_VID 7 #define BKSP 8 void interrupt tsr_ap (); void save_video (), restore_video (); void write_string (), write_char (); void display_header (), draw_border (); void window_gets (); void window_cleol (), window (); void calc (); char far * vid_mem; struct window_frame { int startx, endx, starty, endy; int curx, cury; / * Поточний стан курсору у вікні * / unsigned char * p; / * Покажчик буфера * / char * header; / * Повідомлення у верхній частині вікна * / int border; / * Включення / відключення бордюру * / int active; / * Активація / деактивація вікна * / } Frame [MAX_FRAME]; char wp [4000]; / * Буфер для зберігання поточного вмісту екрана / * Busy встановлена в 1, якщо програма активна, інакше - в 0 * / char busy = 0; main () { struct address { char far * p; }; / * Адреса переривання друку екрану * / struct address far * addr = (struct address far *) 20; addr-> p = (char far *) tsr_ap; set_vid_mem (); tsr (2000); } set_vid_mem () { int vmode; vmode = video_mode (); if ((vmode! = 2) && (vmode! = 3) && (vmode! = 7)) { printf ( "video must be in & 0 column text mode"); exit (1); } / * Встановити відповідну адресу відеопам'яті * / if (vmode == 7) vid_mem = (char far *) 0xB0000000; else vid_mem = (char far *) 0xB8000000; } / * Точка входу в прикладну частину TSR-програми * / void interrupt tsr_ap () { if (! busy) { busy =! busy; window_main (); busy =! busy; } } / * Завершити, але залишити резидентною * / tsr (size) unsigned size; { union REGS r; rhah = 49; / * Завершити, але залишити резидентною * / rhal = 0; / * Код повернення * / rxax = size; int86 (0x21, & r, & r); } window_main () { / * Насамперед, створити структуру вікна * / make_window (0, "Calculator", 8, 20, 12, 60, BORDER); / * Для активації описаного вікна використати window () * / calc (); } / ************************************************* ************ / / * Функції управління вікнами * / / ************************************************* ************ / / * Вивести на екран спускається меню * / void window (num) int num; / * Номер вікна * / { int vmode, choice; int x, y; / * Зробити вікно активним * / if (! frame [num] .active) {/ * використовується не постійно * / save_video (num); / * Зберегти поточний екран * / frame [num] .active = 1; / * Встановити прапор активності * / } if (frame [num] .border) draw_border (num); display_header (num); / * Вивести вікно * / } / * Створити вікно якщо вікно може бути створено, повертається 1; інакше повертається 0.* / make_window (num, header, startx, starty, endx, endy, border) int num; / * Номер вікна * / char * header; / * Текст заголовка * / int startx, starty; / * Координати X, Y лівого верхнього кута * / int endx, endy; / * Координати X, Y правого нижнього кута * / int border; / * Без бордюру якщо 0 * / { register int i; int choice, vmode; unsigned char * p; if (num> MAX_FRAME) { window_puts (0, "Too many windows \ n"); return 0; } if ((startx> 24) || (starty> 78) || (starty <0)) { window_puts (0, "range error"); return 0; } if ((endx> 24) || (endy> 79)) { window_puts (0, "window will not fit"); return 0; } / * Створити структуру вікна * / frame [num] .startx = startx; frame [num] .endx = endx; frame [num] .starty = starty; frame [num] .endy = endy; frame [num] .p = wp; frame [num] .header = header; frame [num] .border = border; frame [num] .active = 0; frame [num] .curx = 0; frame [num] .cury = 0; return 1; } / * Деактивувати вікно і видалити його з екрану * / deactivate (num) int num; { / * Встановити курсор в лівий верхній кут * / frame [num] .curx = 0; frame [num] .cury = 0; restore_video (num); } / * Вивести заголовок вікна в відповідне поле * / void display_header (num) int num; { register int i, y, len; y = frame [num] .starty; / * Обчислити точне значення центральної позиції заголовка якщо негативне - заголовок не може бути виведений* / len = strlen (frame [num] .header); len = (frame [num] .endy - y - len) / 2; if (len <0) return; / * Do not display it * / y = y + len; write_string (frame [num] .startx, y, frame [num] .header, NORM_VID); } void draw_border (num) int num; { register int i; char far * v, far * t; v = vid_mem; t = v; for (i = frame [num] .startx + 1; i= Frame [num] .endy) { return 1; } if (x> = frame [num] .endx) { return 1; } if (ch == '\ n') {/ * символ переходу на новий рядок * / x ++; y = frame [num] .startx + 1; v = vid_mem; v + = (x + 160) + y * 2; / * Обчислити адресу * / frame [num] .curx ++; frame [num] .cury = 0; / * Скинути Y * / } else { frame [num] .cury ++; * V ++ = ch; / * Вивести символ * / * V ++ = NORM_VID; / * Нормальні атрибути символу * / } window_xy (num, frame [num] .curx, frame [num] .cury); return 1; } / * Установка курсора в задану позицію вікна, повертає 0 при виході за кордон; НЕ нуль в іншому випадку.* / window_xy (num, x, y) int num, x, y; { if (x <0 || x + frame [num] .startx> = frame [num] .endx-1) return 0; if (y <0 || y + frame [num] .starty> = frame [num] .endy-1) return 0; frame [num] .curx = x; frame [num] .cury = y; return 1; } / * Вважати рядок з вікна. * / void window_gets (num, s) int num; char * s; { char ch, * temp; temp = s; for (;;) { ch = window_getche (num); switch (ch) { case '\ r': / * натиснута клавіша ENTER * / * S = '\ 0'; return; case BKSP: / * повернення * / if (s> temp) { s--; frame [num] .cury--; if (frame [num] .cury <0) frame [num] .cury = 0; window_xy (num, frame [num] .curx, frame [num] .cury); write_char (frame [num] .startx + frame [num] .curx + 1, frame [num] .starty + frame [num] .cury + 1, '', NORM_VID); } break; default: * s = ch; s ++; } } } / * Введення символу з клавіатури у вікно. Повертає повний 16-розрядний скан-код. / * window_getche (num) int num; { union inkey { char ch [2]; int i; } C; if (! frame [num] .active) return 0; / * Window not active * / window_xy (num, frame [num] .curx, frame [num] .cury); ci = bioskey (0); / * Обробити натискання клавіші * / if (c.ch [0]) { switch (c.ch [0]) { case '\ r': / * натиснута клавіша ENTER * / break; case BKSP: / * повернення * / break; default: if (frame [num] .cury + frame [num] .starty write char (frame [num] .startx + frame [num] .curx + 1, frame [num] .curx--; window_xy (num, frame [num] .curx, frame [num] .cury); } return ci; } / * Очистити до кінця рядка * / void window_cleol (num) int num; { register int i, x, y; x = frame [num] .curx; y = frame [num] .cury; window_xy (num, frame [num] .curx, frame [num] .cury); for (i = frame [num] .cury; i0) { frame [num] .curx--; window_xy (num, frame [num] .curx, frame [num] .cury); return 1; } return 0; } / * Перемістити курсор на один рядок вниз. При успішному завершенні повернути нульове значення; в іншому випадку - 0.* / window_downline (num) int num; { if (frame [num] .curx0) { frame [num] .cury--; window_xy (num, frame [num] .curx, frame [num] .cury); window_putchar (num, ''); frame [num] .cury--; window_xy (num, frame {num} .curx, frame [num] .cury); } } / ************************************************* ******* / /* Додаткові функції */ / ************************************************* ******* / / * Вивести рядок з встановленими атрибутами * / void write_string (x, y, p, attrib) int x, y; char * p; int attrib; { register int i; char far * v; v = vid_mem; v + = (x * 160) + y * 2; / * Обчислити адресу * / for (i + y; * p; i ++) { * V ++ = * p ++; / * Вивести символ * / * V ++ = attrib; / * Вивести атрибути * / } } / * Вивести символ з утановленнимі атрибутами * / void write_char (x, y, ch, attrib) int x, y; char ch; int attrib; { register int i; char far * v; v = vid_mem; v + = (x * 160) + y * 2; * V ++ = ch; / * Вивести символ * / * V = attrib; / * Вивести атрибути * / } / * Зберегти вміст області екрану * / void save_video (num) int num; { register int i, j; char far * v, far * t; char * but_ptr; but_ptr = frame [num] .p; v = vid_mem; t = v; for (i = frame [num] .starty; ibos) return 0; * P = i; p ++; return 1; } / * Видобути верхній елемент стека Повернути 0, якщо стек порожній. * / pop () { p--; if (pp == (int9 + 1) -> p) { int9-> p = addr-> p; addr-> p = (char far *) tsr_ap; printf ( "F3 for calculator"); } Else { printf ( "tsr application already initialized \ n"); exit (1); }} set_vid_mem (); tsr (2000); } Слід зазначити, що дана версія програми не допускає, щоб її запускали більше одного разу протягом одного сеансу роботи. Це пов'язано з тим, що повторний запуск програми приведе до запису адреси точки входу в TSR-програму в таблицю векторів за адресою 60-го переривання, а утримувався там адреса програми реакції на натискання клавіші буде пошкоджений. Під час роботи функції перевіряється, чи збігається вміст таблиці векторів, відповідне перериванням 60 і 61. (Переривання 61 також не використовується DOS). DOS обробляє всі невикористовувані нею переривання однієї і тієї ж програмою обробки неприпустимого переривання. Отже, перед запуском TSR-програми ці адреси будуть збігатися, а після запуску вони будуть різні. 0>0> 1 2 3 4 5 6 7 8 |