Программирование игр для Windows. Советы профессионала

Установка обработчика прерывания


Регистрация (или установка) подпрограммы обработки прерываний заключается том, что мы помещаем ее начальный адрес в соответствующее поле таблицы векторов прерываний. Это можно сделать двумя способами:

 Мы можем просто изменить адрес прерывания таким образом, чтобы он Указывал на наш собственный обработчик и так все и оставить. Однако при этом, старый обработчик прерывания никогда больше вызываться не будет.

Кроме того, а что произойдет, если прерывание будет сгенерировано именно в тот момент, когда мы будем заниматься заменой адреса в таблице векторов? Р-р-раз и «зависли» — вот что случится! Именно поэтому пусть это действие за вас выполнит DOS при помощи функции _dos_setvect(). Для сохранения старого вектора прерывания следует использовать функцию _dos_getvect(). Обе функции гарантировано изменяют вектора без ущерба для операционной системы;

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

Взгляните на рисунок 12.3, на котором представлены два способа установки обработчиков прерываний.

Листинг 12.1 демонстрирует установку нашей процедуры обслуживания прерывания timer () (которая по-прежнему ничего не делает).

Листинг 12.1. Установка процедуры обслуживания прерывания.

void (_interrupt _far old_isr) (); // Указатель для сохранения

// вектора старого

// обработчика прерываний

// Сохранить вектор старого обработчика прерывания таймера

old_isr =  _dos_getvect( 0х1C);



// Установить новую процедуру обработки прерывания

_dos_setvect(0x1C, Timer);

Ну как, трудно? Да вовсе нет! Для восстановления старого обработчика нам потребуется сделать только:




_dos_setvect(0x1C, old_isr);

Вот и все. Теперь, для примера, заставим наш обработчик прерывания делать что-нибудь полезное, например, обновлять значения глобальной переменной. В Листинге 12.1 показан текст программы SPY.С, которая представляет собой бесконечный цикл, печатающий значение переменной. Единственный способ изменить значение этой переменной - присвоить ей значение из другой программы, например, из обработчика прерывания.

Листинг 12.2. Шпионим за часами (SPY.C)._________________

// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ///////////////////////////////////////////////

#include <dos.h>

#include <bios.h>

#nclude <stdio.h>

#include <math.h>

#include <conio.h>

#include <graph.h>

// ОПРЕДЕЛЕНИЯ//////////////////////////////////

#define TIME_KEEPER_INT 0x1C

// ГЛОБАЛЬНЫЕ

ПЕРЕМЕННЫЕ

///////////////////////////////

void (_interrupt _far *old_Isr)();

// хранит старый обработчик прерывания

long time=0;

// функции ////////////////////////////////////

void _interrupt _far Timer()

{

// Увеличивает глобальную переменную.

// Еще раз отметим, что мы можем это делать, так как при входе

// в процедуру обработки прерывания регистр DS

указывает на сегмент

// глобальных данных нашей программы,

time++;

} // конец Timer

// ОСНОВНАЯ ПРОГРАММА ////////////////////////////////

void main(void)

{

// установка процедуры обработки прерывания

Old_Isr = _dos_getvect(TIME_KEEPER_INT);

_dos_setvect(TIME_KEEPER_INT, Timer) ;

// ожидание нажатия клавиши пользователем

while(!kbhit())

{

// вывод переменной. Примечание: сама по себе функция main

// значение этой переменной не изменяет...

_settextposition(0,0);

printf("\nThe timer reads:%ld   ",time);

} // конец while

// восстановление старого обработчика прерывания

_dos_setvect(TIME_KEEPER_INT, Old_Isr) ;

} // конец функции main

Запустив программу, приведенную в Листинге 12.2, вы увидите, что приращение счетчика происходит очень быстро. Фактически, значение этой переменной увеличивается каждую 1/18.2 секунды — так настроены по умолчанию внутренние системные часы. (Не переживайте, очень скоро мы научимся управлять и ими).Главное, что сама программа не увеличивает значенй переменной time. Этим занимается исключительно подпрограмма обслужива ния прерывания.

Итак, мы создали процедуру обслуживания прерывания, установили ее и убедились в том, что она работает - и все это мы сделали, написав лишь несколько строк кода. Восхитительно, не правда ли? Более сложными обработчиками прерываний мы займемся чуть позже. Сейчас же давайте сменим тему и поговорим об игровом цикле.


Содержание раздела