Особенности резидентных программ
TSR-программы имеют некоторые особенности, отличающие их от "нормальных" программ.
Им не разрешается использовать DOS-прерывания, когда вздумается. Это связано с тем, что DOS проектировалась как однозадачная операционная система, поэтому модули DOS не обладают свойством реентерабельности (повторной входимости). Что это означает на практике?
Допустим, Ваша программа записывает длинный файл на диск. Во время записи вы (возможно, случайно) нажали клавишу, активизирующую TSR-программу записи содержимого экрана в файл.
Теперь доступа к диску требуют две программы - прикладная, записывающая длинный файл, и Ваша TSR-программа. Запись файла из прикладной программы приостановится, далее произойдет запись копии экрана в файл, после чего возобновится запись файла из прикладной программы. Все было бы хорошо, если бы прикладная программа и TSR-программа не использовали одни и те же внутренние области данных DOS для работы с диском. При запуске TSR-программа безвозвратно испортит текущее состояние служебных областей данных, которые прикладная программа использовала при записи на диск.
И таких примеров можно привести много. BIOS также далеко не весь реентерабельный. TSR-программа может смело использовать разве лишь прерывание 16h для работы с клавиатурой, которое реентерабельно. Для вывода на экран лучше всего использовать непосредственную запись символов в видеопамять дисплейного адаптера.
Не стоит пользоваться многими функциями библиотеки Quick C, так как они могут вызывать прерывания DOS. Например, функция malloc() вызывает прерывание DOS для определения размера свободной памяти в системе.
Могут возникнуть трудности с использованием арифметических действий с числами в формате плавающей запятой, так как функция _dos_keep() при завершении программы восстанавливает прерывания, использовавшиеся для эмуляции арифметики с плавающей запятой и для работы с арифметическим сопроцессором.
Некоторые из перечисленных проблем (те, что связаны с использованием прерываний DOS) можно решить с помощью недокументированного прерывания INT 28h.
Это прерывание вызывается DOS при ожидании ввода с клавиатуры. В этот момент вы можете использовать любое прерывание DOS, кроме функций от 00h до 0Сh прерывания INT 21h. Утилита спулинга печати PRINT.COM использует это прерывание.
Можно рекомендовать следующий способ использования прерывания 28h. Обработчик прерывания 9 отслеживает нажатие клавиши, которая должна активизировать TSR-программу. Обнаружив эту клавишу (или комбинацию клавиш), обработчик прерывания 9 устанавливает флаг запроса на активизацию TSR-программы и завершает свою работу обычным способом.
Ваша TSR-программа должна создать свой обработчик прерывания 28h и сцепить его со стандартным. Каждый раз, когда DOS ожидает ввода с клавиатуры (в этот момент DOS не использует сама свои прерывания), вызывается прерывание 28h. Ваш обработчик проверяет флаг активизации, устанавливаемый обработчиком прерывания 9, и если флаг установлен, TSR-программа активизируется и может пользоваться услугами DOS, в частности, файловой системой.
Разумеется, после выполнения всех необходимых действий TSR-программа должна сбросить флаг активизации.
Можно также вместе с прерыванием 28 использовать аппаратное прерывание таймера с номером 8. В этом случае надо проверять не только флаг активизации, но и так называемый флаг критической секции DOS. Это байт, адрес которого возвращает недокументированная функция 34h прерывания DOS 21h в регистрах ES:BX. Если этот байт равен 0, то DOS не использует свои прерывания и наступил подходящий момент для активизации TSR-программы.
TSR-программа может вступить в конфликт с другими TSR-программами или прикладным обеспечением, если будет использовать занятые ими номера прерываний. Известен случай, когда драйвер клавиатуры и экрана (SDRIVER) вызывал зависания программных продуктов фирмы Microsoft из-за того, что эти продукты выдавали 16h прерывание с содержимым регистра AX равным 5500h, 5501h и т.д. Обработчик 16h-го прерывания программы SDRIVER при этом зацикливался из-за ошибки в программе (или точнее, из-за плохой реакции на такого рода номера функций прерывания 16h).
Очень важно не допустить случайного повторного запуска TSR-программы, так как повторное переназначение векторов прерываний почти наверняка приведет систему к краху.
Для проверки наличия TSR-программы в памяти обычно используют прерывание мультиплексора 2Fh, специально предназначенное для организации элементов мультизадачности в DOS. Это прерывание используется спулером печати PRINT.COM (об этом мы будем говорить при описании работы с принтером).
TSR-программа может переназначить это прерывание на себя и сделать так, чтобы оно "откликалось" на какой-либо код функции, зарезервированный для прикладных программ. Можно использовать коды C0h...FFh. При запуске TSR-программа вызывает прерывание 2Fh с выбранным кодом и проверяет ответ (передаваемый, например, в регистре AX). Если прерывание отвечает тем кодом, который задан в TSR-программе, это означает, что копия программы уже есть в памяти и повторная установка недопустима.
Взаимодействие с резидентными программами
Для того чтобы некоторый программный фрагмент вызывался командой int n, надо просто поместить в выбранный вектор с номером n адрес этого фрагмента, который должен завершаться командой iret. Тогда команда int n в отлаживаемой программе будет передавать управление обработчику этого прерывания, а команда iret, завершающая обработчик, будет возвращать управление в отлаживаемую программу. Естественно, выбранный вектор не должен использоваться системой и загруженными или запускаемыми прикладными программами.
Если с помощью какой-либо инструментальной программы (например, Manifest фирмы Quarterdeck) просмотреть таблицу векторов, то можно заметить, что значительная их часть не используется. Сюда относятся, например, векторы 60h...66h, которые специально отведены для использования в прикладных программах, а также векторы 32h, 34h...3Fh, 42h, 78h...7Fh и ряд других, зарезервированных для дальнейшего использования системой. Любым из этих векторов в принципе можно воспользоваться "в личных целях". При этом, однако, следует иметь в виду, что коммерческие программы, устанавливаемые на компьютере, часто используют свободные векторы.
Поэтому, создавая свою резидентную программу, активизируемую через вектор прерывания, надо предварительно убедиться, что выбранный вектор действительно свободен.