- •Часть I. Язык Borland Pascal...................................12
- •Глава 1. Что такое программа Borland Pascal?...................12
- •Глава 2. Лексемы...............................................22
- •Глава 3. Константы.............................................32
- •Глава 4. Типы..................................................34
- •Глава 5. Переменные и типизированные константы.................72
- •Глава 6. Выражения.............................................93
- •Глава 7. Операторы............................................117
- •Глава 8. Блоки, локальность и область действия................133
- •Глава 9. Процедуры и функции..................................139
- •Глава 10. Программы и модули..................................170
- •Глава 11. Динамически компонуемые библиотеки..................180
- •Глава 12. Библиотеки исполняющей системы......................194
- •Глава 13. Стандартные процедуры и функции.....................199
- •Глава 14. Ввод и вывод........................................215
- •Глава 15. Использование сопроцессора 80x87....................248
- •Глава 16. Модуль Dоs..........................................259
- •Глава 17. Программирование в защищенном режиме dos............270
- •Глава 18. Строки с завершающим нулем..........................297
- •Глава 19. Использование графического интерфейса Borland.......308
- •Глава 20. Использование оверлеев..............................329
- •Часть III. В среде Borland Pascal.............................348
- •Глава 21. Использование памяти................................348
- •Глава 22. Вопросы управления..................................388
- •Глава 23. Автоматическая оптимизация..........................405
- •Часть IV. Использование Borland Pascal с языком ассемблера....411
- •Глава 24. Встроенный ассемблер................................411
- •Глава 25. Компоновка с программами на языке ассемблера........437
- •Часть II "Библиотеки исполняющей системы" содержит информа-
- •Часть I. Язык Borland Pascal
- •Глава 1. Что такое программа Borland Pascal?
- •Глава 2. Лексемы
- •Глава 3. Константы
- •Глава 4. Типы
- •Глава 5. Переменные и типизированные константы
- •Глава 6. Выражения
- •Глава 7. Операторы
- •Глава 8. Блоки, локальность и область действия
- •Глава 9. Процедуры и функции
- •Глава 10. Программы и модули
- •Глава 11. Динамически компонуемые библиотеки
- •Часть II. Глава 12. Библиотеки исполняющей системы
- •Глава 13. Стандартные процедуры и функции
- •Глава 14. Ввод и вывод
- •Глава 15. Использование сопроцессора 80x87
- •Глава 16. Модуль Dоs
- •Глава 17. Программирование в защищенном режиме dos
- •Глава 18. Строки с завершающим нулем
- •Глава 19. Использование графического интерфейса Borland
- •Глава 20. Использование оверлеев
- •Часть III. В среде Borland Pascal
- •Глава 21. Использование памяти
- •Глава 22. Вопросы управления
- •Глава 23. Автоматическая оптимизация
- •Часть IV. Использование Borland Pascal с языком ассемблера
- •Глава 24. Встроенный ассемблер
- •Глава 25. Компоновка с программами на языке ассемблера
Глава 17. Программирование в защищенном режиме dos
─────────────────────────────────────────────────────────────────
Микропроцессор 80286 дает новый способ адресации к памяти:
защищенный режим виртуальной адресации или просто защищенный ре-
жим. Этот новый режим адресации дает три основных преимущества:
* Адресация к памяти объемом до 16 мегабайт.
* Логическое адресное пространство, превышающее пространство
физических адресов.
* Способ изоляции программ друг от друга, так что одна прог-
рамма не может нарушать другой выполняющейся одновременно
с ней программы.
С помощью Borland Pascal вы легко можете писать работающие в
защищенном режиме прикладные программы DOS без необходимости при-
менения дополнительного "расширителя" DOS. Вы обнаружите, что
многие программы реального режима прекрасно работают в защищенном
режиме. Данная глава поможет вам модифицировать те программы, ко-
торые этого не делают, и прояснит некоторые основные моменты за-
щищенного режима и его отличия от реального режима.
Что такое защищенный режим?
─────────────────────────────────────────────────────────────────
Процессор 80286 и более поздние процессоры поддерживают два
режима операций: защищенный режим и реальный режим. Реальный ре-
жим совместим с работой процессора 8086 и позволяет прикладной
программе адресоваться к памяти объемом до одного мегабайта. За-
щищенный режим расширяет диапазон адресации до 16 мегабайт. Ос-
новное отличие между реальным и защищенным режимом заключается в
способе преобразования процессором логических адресов в физичес-
кие. Логические адреса - это адреса, используемые в прикладной
программе. Как в реальном, также и в защищенном режиме логический
адрес - это 32-разрядное значение, состоящее из 16-битового се-
лектора (адреса сегмента) и 16-битового смещения. Физические ад-
реса - это адреса, которые процессор использует для обмена данны-
ми с компонентами системной памяти. В реальном режиме физический
адрес представляет собой 20-битовое значение, а в защищенном ре-
жиме - 24-битовое.
B.Pascal 7 & Objects/LR - 271 -
Когда процессор обращается к памяти (для выборки инструкции
или записи переменной), он генерирует из логического адреса физи-
ческий адрес. В реальном режиме генерация физического адреса сос-
тоит из сдвига селектора (адреса сегмента) на 4 бита влево (это
означает умножение на 16) и прибавления смещения. Полученный в
результате 20-разрядный адрес используется затем для доступа к
памяти.
16Мб┌────────────────┐
│ │
┌────────┐ │ │
│Смещение├─┐ │ │
└────────┘ │ │ │
│ ├────────────────┤┐
└──┼─────>▒▒▒▒▒▒▒▒▒▒│├ сегмент 64К
┌─>├────────────────┤┘
│ │ │
│ │ Пространство │
┌────────┐ ┌──────┐ │ │ адресов │
│Селектор├─┤ x 16 ├─────┘ │ │
└────────┘ └──────┘ │ │
0└────────────────┘
Рис. 17.1 Генерация физического адреса в реальном режиме.
B.Pascal 7 & Objects/LR - 272 -
Чтобы получить физический адрес в защищенном режиме, селек-
торная часть логического адреса используется в качестве индекса
таблицы дескрипторов. Запись в таблице дескрипторов содержит
24-битовый базовый адрес, к которому затем для образования физи-
ческого адреса прибавляется смещение логического адреса.
16Мб┌────────────────┐
│ │
┌────────┐ │ │
│Смещение├─┐ │ │
└────────┘ │ │ │
│ ├────────────────┤┐
Таблица дескрипторов └──┼─────>▒▒▒▒▒▒▒▒▒▒│├ сегмент 64К
┌──────┐ ┌─>├────────────────┤┘
├──────┤ │ │ │
├──────┤ │ │ Пространство │
├──────┤ │ │ адресов │
┌─>├──────┤───┘ │ │
│ ├──────┤ │ │
│ ├──────┤ 0└────────────────┘
│ ├──────┤
│ ├──────┤
│ ├──────┤
│ ├──────┤
│ ├──────┤
│ ├──────┤
│ ├──────┤
│ ├──────┤
┌────────┐ │ ├──────┤
│Селектор├─┘ └──────┘
└────────┘
Рис. 17.2 Генерация физического адреса в защищенном режиме.
Каждая запись в таблице дескрипторов называется дескриптором
и определяет сегмент в памяти. Запись таблицы дескрипторов зани-
мает 8 байт, а записанная в дескрипторе информация включает в се-
бя базовый адрес, предельное значение и флаги полномочий доступа
к сегменту.
Записи предельного значения сегмента и полномочий доступа в
дескрипторе определяют размер и тип сегмента. Сегменты могут
иметь размер от 1 до 65536 байт и могут быть сегментами кода или
сегментами данных. Сегменты кода могут содержать выполняемые ма-
шинные инструкции и доступные только по чтению данные. Сегменты
данных могут содержать данные, доступные по чтению и записи. За-
писывать данные в сегменты кода или выполнять инструкции в сег-
ментах данных невозможно. Любая попытка сделать это или попытка
доступа к данным вне границ сегмента вызывает общий сбой по на-
рушению защиты (сокращенно сбой GP). Поэтому режим и называется
защищенным.
B.Pascal 7 & Objects/LR - 273 -
По данному адресу в реальном режиме прикладная программа мо-
жет определить физический адрес. В защищенном режиме это обычно
не так, поскольку селекторная часть логического адреса является
индексом в таблице дескрипторов, и сам селектор не имеет прямого
отношения к вычислению физического адреса. Это дает то преиму-
щество, что управление виртуальной памятью можно реализовать, не
влияя на прикладную программу. Например, путем простого обновле-
ния поля базового адреса дескриптора сегмента, операционная сис-
тема может перемещать сегмент в физической памяти без влияния на
использующую сегмент прикладную программу. Прикладная программа
ссылается только на селектор сегмента, и на селектор не влияют
изменения в дескрипторе.
Прикладная программа редко имеет дело с дескрипторами. При
необходимости дескрипторы создаются и уничтожаются операционной
системой и администратором памяти, а прикладная программа знает о
соответствующих селекторах. Селекторы аналогичны описателям фай-
лов - с точки зрения прикладной программы это то, что обслужива-
ется операционной системой, но в операционной системе они работа-
ют как индексы содержащих дополнительную информацию таблиц.
B.Pascal 7 & Objects/LR - 274 -
Расширения Borland защищенного режима DOS
─────────────────────────────────────────────────────────────────
Расширения защищенного режима Borland Pascal реализованы че-
рез два компонента: DPMI-сервер (файл DPMI16BI.OVL) и администра-
тор этапа выполнения (файл RTM.EXE).
DPMI-сервер
─────────────────────────────────────────────────────────────────
Интерфейс защищенного режима DOS (DPMI) - это отраслевой
стандарт, позволяющий программам DOS аппаратно-независимым путем
получить доступ к развитым средствам персональных компьютеров,
реализованных на процессорах 80286, 80386 и 80486. Определены
функции DPMI для обслуживания таблиц дескрипторов, переключения
режима, распределения расширенной памяти, выделения памяти DOS,
управления подсистемой прерываний и взаимодействия с программами
реального режима.
Расширения защищенного режима Borland Pascal основаны на
спецификации DPMI 0.9. Хотя спецификация DPMI не поддерживает вы-
зовы DOS из прикладных программ защищенного режима, DPMI-сервер
Borland и серверы многих других фирм, включая улучшенный режим
Windows 3.x, поддерживают прерывание INT 21H и другие стандартные
прерывания DOS и BIOS, используемые обычно в приложениях DOS за-
щищенного режима.
Администратор этапа выполнения
─────────────────────────────────────────────────────────────────
Администратор этапа выполнения (RTM.EXE) является надстрой-
кой DPMI-сервера и обеспечивать для прикладных программ защищен-
ного режима несколько служебных функций. Администратор этапа вы-
полнения содержит загрузчик защищенного режима и администратор
памяти защищенного режима и позволяет под DPMI сосуществовать
нескольким клиентам защищенного режима.
Приложения защищенного режима Borland используют те же фор-
маты выполняемых файлов, что и Windows 3.x и OS/2 1.x. Программ-
ный загрузчик администратора этапа выполнения может загружать как
выполняемые файлы (.EXE), так и динамически компонуемые библиоте-
ки (.DLL).
Администратор памяти защищенного режима позволяет прикладным
программам защищенного режима распределять блоки динамической па-
мяти. Администратор памяти поддерживает фиксированные, перемещае-
мые и выгружаемые блоки, а также обслуживает код и сегменты дан-
ных прикладной программы. Используя уникальные для защищенного
режима средства, администратор памяти функционирует также в ка-
честве администратора оверлеев, автоматически загружая и выгружая
сегменты кода (по этой причине прикладной программе защищенного
режима не требуется модуль Overlay).
B.Pascal 7 & Objects/LR - 275 -
Прикладные программы могут получить доступ к программам за-
щищенного режима через модуль WinAPI. Модуль WinAPI, описанный в
следующем разделе, реализует подмножество функций API (прикладно-
го программного интерфейса) Windows, обеспечивая управление па-
мятью, обслуживание программных модулей, управление ресурсами,
загрузку динамически компонуемых библиотек и доступ к селекторам
на нижнем уровне. Поскольку администратор этапа выполнения API
является подмножеством API Windows, вы можете написать совмести-
мые на уровне двоичного кода динамически компонуемые библиотеки,
которые можно использовать и в защищенном режиме DOS, и в
Windows.
B.Pascal 7 & Objects/LR - 276 -
Разработка прикладных программ DOS защищенного режима
─────────────────────────────────────────────────────────────────
Написание прикладной программы защищенного режима не предс-
тавляет собой сложной задачи. Вам не нужно беспокоиться о селек-
торах и адресах памяти. Операционная система с расширениями
Borland все делает за вас. Фактически, большинство ваших программ
реального режима может прекрасно работать в защищенном режиме. В
следующих разделах описывается некоторая разница между реальным и
защищенным режимом, о которых вы должны знать при разработке
прикладной программы защищенного режима.
Надежное программирование в защищенном режиме
─────────────────────────────────────────────────────────────────
Существует несколько приемов, используемых обычно в програм-
мах реального режима, которые в программах защищенного режима бу-
дут приводить к общему нарушению защиты (сбой GP). Borland Pascal
при сбое GP выводит ошибку этапа выполнения 216. Сбой GP происхо-
дит, когда вы пытаетесь получить доступ к памяти, к которой ваша
прикладная программа обращаться не может. Операционная система
останавливает прикладную программу, но сбоя системы не происхо-
дит. Хотя сбои GP и прекращают работу вашей программы, система
"защищена" от сбоя. К сбою GP приводит следующее:
* загрузка в сегментные регистры недопустимых значений;
* обращение к памяти вне границы сегмента;
* запись в сегмент кода;
* разыменование указателей nil.
Примечание: Сбои по нарушению защиты предохраняют вашу
систему от плохой практики программирования.
B.Pascal 7 & Objects/LR - 277 -
Загрузка в сегментные
регистры недопустимых значений
─────────────────────────────────────────────────────────────────
Когда процессор работает в защищенном режиме, сегментные ре-
гистры (CS, DS, ES и SS) могут содержать только селекторы. Пос-
кольку селекторы являются индексами в таблице дескрипторов, они
не имеют физического отношения к памяти, на которую ссылается.
Если вы пытаетесь загрузить в сегментный регистр произвольное
значение, то возможно получите сбой GP, поскольку это значение
может не представлять допустимого дескриптора.
Функция Ptr и массивы Mem
─────────────────────────────────────────────────────────────────
При разыменовании указателей компилятор генерирует код для
загрузки сегментного регистра. Если вы строите указатели с по-
мощью стандартной функции Ptr, то нужно обеспечить, чтобы сег-
ментная часть указателя была допустимым селектором. Аналогично,
при работе с массивами Mem, MemW и MemL вы вместо физических ад-
ресов должны использоваться селекторы. Например, при доступе к
рабочей области ROM BIOS (сегмент $0040) или к областям видеопа-
мяти (сегменты $A000, $B000 и $B800) следует использовать вместо
абсолютных значений переменные SegXXXX. (Переменные SegXXXX опи-
сываются ниже.)
Абсолютные переменные
─────────────────────────────────────────────────────────────────
В защищенном режиме вы не можете задавать абсолютный адрес
переменной. Любой исходных код, где сегмент и смещение задаются в
операторе absolute, нужно переписать. Например, вам может потре-
боваться построить указатель, используя переменные SegXXXX.
B.Pascal 7 & Objects/LR - 278 -
Операции с сегментами
─────────────────────────────────────────────────────────────────
Добавление или вычитание значений из селекторной части ука-
зателя обычно не допускается. Например, добавление к селекторной
части указателя $1000 в реальном режиме увеличивает указатель на
64К, но в защищенном режиме результирующий указатель будет недо-
пустимым. Вместо этого для выделения и управления блоками памяти
следует использовать функцию GlobalXXXX модуля WinAPI.
В Borland Pascal существует способ выполнения арифметических
операций с селекторами с помощью переменной SelectorInc (см. ни-
же).
Использование сегментных
регистров в качестве временных переменных
─────────────────────────────────────────────────────────────────
В реальном режиме некоторые старые программы на ассемблере
используют сегментные регистры для хранения временных переменных.
В защищенном режиме это работать не будет, так как обычно сохра-
няемые в сегментных регистрах временные значения не являются до-
пустимыми селекторами.
Доступ к памяти вне границ сегмента
─────────────────────────────────────────────────────────────────
В реальном режиме каждый сегмент имеет размер 64К. В защи-
щенном режиме дескриптор сегмента содержит поле, специфицирующее
предельный размер сегмента, и если вы пытаетесь обратиться к дан-
ным вне границ сегмента, по получите сбой GP. При загрузке прик-
ладной программы администратор этапа выполнения устанавливает со-
ответствующие предельные значения для сегментов кода, данных и
стека. Кроме того, блок памяти, распределяемый с помощью функции
GlobalAlloc модуля WinAPI, имеет предельное значение сегмента,
соответствующее размеру блока памяти.
B.Pascal 7 & Objects/LR - 279 -
Запись в сегмент кода
─────────────────────────────────────────────────────────────────
В реальном режиме можно записывать переменные в сегмент ко-
да, поскольку реальные режим не определяет, что может и что не
может существовать в сегменте. В защищенном режиме это не так.
Селектор защищенного режима имеет флаг чтения/записи или доступа
только по чтению, а селекторы кода всегда отмечены как доступные
только по чтению. Если вы пытаетесь записывать в селектор сегмен-
та кода, происходит сбой GP. Однако вы можете использовать псев-
доним и написать самомодифицирующийся код (см. ниже).
Разыменование указателей nil
─────────────────────────────────────────────────────────────────
При преобразовании прикладной программы реального режима в
защищенный режим, в программе, которая уже годы работала без оши-
бок, возможно внезапное появление определенных ошибок. Например,
вы можете случайно разыменовывать указатель nil, или обнаружите,
что ваша программа содержит "потерянные" указатели, которые разы-
меновываются после их освобождения. В реальном режиме такие ошиб-
ки не обязательно проявляются, но в защищенном режиме они обычно
приводят к сбою GP. Согласно своему названию, защищенный режим
значительно лучше предохраняет вас от ошибок, связанных с указа-
телями.
Сегменты кода и данных
─────────────────────────────────────────────────────────────────
Аналогично программе Borland Pascal реального режима, прог-
рамма защищенного режима содержит несколько сегментов кода, сег-
мент данных и сегмент стека. При загрузке программы защищенного
режима администратор этапа выполнения автоматически выделяет се-
лекторы для сегментов кода, данных и стека. Для сегментов кода
с помощью директивы компилятора $C можно управлять отдельными ат-
рибутами. В частности, сегменты кода можно сделать перемещаемыми
или фиксированными в физической памяти, они могут загружаться
предварительно или по запросу, а также могут быть выгружаемыми
или постоянными.
Примечание: Подробнее о директиве компилятора $C расс-
казывается в Главе 21 данного руководства и в Главе 2 ("Ди-
рективы компилятора") "Справочного руководства программис-
та".
Атрибуты сегмента кода позволяют вам обозначать сегмент как
статический (перемещаемый, предварительно загружаемый, постоян-
ный) или динамический (перемещаемый, загружаемый по запросу, выг-
ружаемый). Таким образом, в защищенном режиме вам не нужно ис-
пользовать модуль Overlay и директиву компилятора $O, и в версии
модуля System для защищенного режима переменные OvrXXXXXX отсутс-
твуют.
B.Pascal 7 & Objects/LR - 280 -
Управление динамически распределяемой памятью
─────────────────────────────────────────────────────────────────
Администратор динамически распределяемой области памяти
Borland Pascal защищенного режима довольно существенно отличается
от администратора динамически распределяемой памяти Borland
Pascal реального режима. В частности, переменные HeapOrg,
HeapEnd, HeapPtr и FreeList в версии модуля System для защищенно-
го режима не определены. Администратор этапа выполнения динами-
чески распределяемой области памяти Borland Pascal защищенного
режима (который идентичен администратору этапа выполнения динами-
чески распределяемой области памяти Borland Pascal для Windows)
для выполнения основных операций по выделению и освобождению па-
мяти использует администратор этапа выполнения, а для оптимизации
распределения небольших блоков памяти включает в себя подсистему
вторичного распределения сегмента. Подробнее об администраторе
динамически распределяемой области памяти этапа выполнения расс-
казывается в Главе 21.
Предопределенные селекторы
─────────────────────────────────────────────────────────────────
В модуле System для обычно используемых адресов реального
режима предусмотрено несколько предопределенных селекторов. Они
именуются по физическому сегменту, которому данные селекторы
присвоены, и используются для совместимости между реальным и за-
щищенным режимом DOS.
Предопределенные селекторы Таблица 17.1
┌──────────────────┬────────────────────────────────────────────┐
│ Селектор │ Описание │
├──────────────────┼────────────────────────────────────────────┤
│ Seg0040 │ Используется для доступа к области данных│
│ │ BIOS $40 в младших адресах. │
├──────────────────┼────────────────────────────────────────────┤
│ SegA000 │ Используется для доступа к графической па-│
│ │ мяти EGA и VGA по адресу сегмента $A000. │
├──────────────────┼────────────────────────────────────────────┤
│ SegB000 │ Используется для доступа к видеопамяти мо-│
│ │ нохромного адаптера по адресу сегмента│
│ │ $A000. │
├──────────────────┼────────────────────────────────────────────┤
│ SegB800 │ Используется для доступа к видеопамяти│
│ │ цветного графического адаптера по адресу│
│ │ сегмента $A000. │
└──────────────────┴────────────────────────────────────────────┘
В реальном режиме переменные SegXXXX всегда содержат значе-
ния $0040, $A000, $B000 и $B800 соответственно. В защищенном ре-
жиме код запуска библиотеки исполняющей системы создает четыре
селектора, ссылающихся на конкретные области памяти реального ре-
жима. При ссылке на эти области памяти вам следует использовать
переменные SegXXXX. Например, если у вас был код следующего вида:
B.Pascal 7 & Objects/LR - 281 -
CtrMode := Mem[$40: $49];
то вместо него следует записать:
CtrMode := Mem[Seg0040: $49];
Используя переменные SegXXXX, вы можете гарантировать, что
ваша программа без изменений будет работать в реальном и защищен-
ном режимах.
Переменная SelectorInc
─────────────────────────────────────────────────────────────────
Переменная SelectorInc модуля System содержит значение, ко-
торое должно прибавляться к селектору или вычитаться из него для
получения следующего или предыдущего селектора в таблице дескрип-
торов. SelectorInc полезно использовать при работе с большими
блоками памяти (превышающими 64К) и при доступе к псевдонимам
сегментов.
Для выделения блоков, превышающих 64К (такие блоки называют
также большими блоками памяти), можно использовать функции
GlobalAlloc и GlobalAllocPrt в модуле WinAPI. Большие блоки неп-
рерывны в физической памяти, но из-за 16-разрядной архитектуры
процессора прикладная программа не может получить к ним доступ
целиком. Для большого блока памяти администратор памяти выделяет
несколько непрерывных (следующих подряд) селекторов, каждый из
которых (кроме последнего) ссылается на часть большого блока па-
мяти размером 64К. Например, чтобы выделить блока памяти размером
в 220К, администратор памяти создает четыре селектора, при этом
первые три селектора ссылаются на блоки по 64К, а последний се-
лектор - на блок размером 28К. Прибавляя SelectorInc к селектору,
принадлежащему большому блоку, вы можете получить селектор для
следующего сегмента, а вычитая SelectorInc - для предыдущего.
При распределении большого блока функция GlobalAlloc всегда
возвращает описатель первого сегмента, а GlobalAllocPtr - указа-
тель на первый сегмент.
Приведенная ниже функция GetPtr воспринимает указатель боль-
шого блока (возвращаемый функцией GlobalAllocPtr) и 32-разрядное
смещение и возвращает указатель на заданное внутри блока смеще-
ние.
function GetPtr(P: Pointer; Offset: Longint): Pointer;
type
Long = record
Lo, Hi: Word;
end;
begin
GetPtr := Ptr(
B.Pascal 7 & Objects/LR - 282 -
Long(P).Hi + Long(Offset).Hi * SelectorInc,
Long(P).Lo + Long(Offset).Lo);
end;
Заметим, что старшее слово параметра Offset используется для
определения того, сколько раз нужно увеличить селекторную часть P
для получения корректного сегмента. Например, если Offset равно
$24000, то селекторная часть P будет увеличена на 2 *
SelectorInc, а смещение P - на $4000.
Следующая функция LoadFile загружает в блок памяти весь файл
и возвращает указатель на блок. Если файл превышает 64К, то выде-
ляется большой блок памяти.
function LoadFile(const FileName: string): Pointer;
var
Buffer: Pointer;
Size, Offset, Count: Longint;
F: file;
begin
Buffer := nil;
Assign(F, FileName);
Reset(F, 1);
Size := FileSize(F);
Buffer := GlobalAllocPtr(gmem_Moveable, Size);
if Buffer <> nil then
begin
Offset := 0;
while Offset < Size do
begin
Count := Size - Offset;
if Count > $8000 then Count := $8000;
BlockRead(F, GetPtr(Buffer, Offset)^, Count);
Inc(Offset, Count);
end;
end;
LoadFile := Buffer;
end;
Переменная SelectorInc определена также в версии модуля
System для реального режима. В реальном режиме она всегда содер-
жит значение $1000, которое при сложении его с сегментной частью
указателя реального режима увеличивает указатель на 64К.
Другим образом вы можете использовать переменную SelectorInс
только в программах DOS защищенного режима. Используйте перемен-
ную SelectorInc для доступа к псевдонимам сегментов, выделяемых
администратором этапа выполнения при загрузке прикладной програм-
мы. Для каждого сегмента кода прикладной программы администратор
этапа выполнения создает селектор-псевдоним, ссылающийся на тот
же сегмент, но имеющий полномочия селектора данных. Для сегментов
стека и данных селекторы-псевдонимы не создаются.
B.Pascal 7 & Objects/LR - 283 -
Чтобы получить доступ к селектору-псевдониму для конкретного
сегмента, добавьте к селектору сегмента SelectorInc. Предположим,
например, что P - это переменная типа Pointer, а Foo - процедура
или функция. Тогда присваивание вида:
P := Addr(Foo)
приводит к тому, что P будет указывать на выполняемую доступную
только по чтению точку входа Foo, а после оператора:
P := Ptr(Seg(Foo) + SelectorInc, Ofs(Foo));
P будет ссылаться на тот же адрес, но с полномочиями на чте-
ние/запись.
B.Pascal 7 & Objects/LR - 284 -
Модуль WinAPI
─────────────────────────────────────────────────────────────────
Модуль WinAPI дает вам непосредственный доступ к расширениям
Borland защищенного режима DOS. Чтобы облегчить написание перено-
симых прикладных программ и совместимых на уровне двоичного кода
DLL, разработан интерфейс WinAPI, являющийся подмножеством интер-
фейса API Windows.
Модуль WinAPI позволяет вам использовать функции управления
памятью, управления ресурсами, модулями, селекторами и многие
другие функции API. Ниже приведено их краткое описание. Полное
описание констант, типов, процедур и функций модуля WinAPI вы мо-
жете найти в "Справочном руководстве программиста".
При работе под Windows подпрограммы API, поддерживаемые с
помощью модуля WinAPI, находятся в динамически компонуемых библи-
отеках KERNEL.DLL и USER.DLL. В защищенном режиме DOS эти DLL не
требуются, так как администратор этапа выполнения защищенного ре-
жима содержит реализацию подпрограмм KERNEL и USER, автоматичес-
ки перенаправляя их вызовы администратору.
Управление памятью
─────────────────────────────────────────────────────────────────
При разработке программ, работающих с динамической памятью,
обычно используются стандартные процедуры New, Dispose, GetMem и
FreeMem. Однако получить доступ к администратору памяти защищен-
ного режима Borland вы можете с помощью функций GlobalXXXX в мо-
дуле WinAPI.
Заметим, что функции GlobalXXXXPtr комбинируют в одной подп-
рограмме общие последовательности вызовов функций, такие как
GlobalAlloc, за которыми следуют вызовы GlobalLock, GlobalUnlock
или GlobalFree.
B.Pascal 7 & Objects/LR - 285 -
Подпрограммы управления памятью API
Таблица 17.2
┌─────────────────────┬─────────────────────────────────────────┐
│ Функция │ Описание │
├─────────────────────┼─────────────────────────────────────────┤
│ GetFreeSpace │ Определяет объем свободной памяти в ди-│
│ │ намически распределяемой области. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalAlloc │ Выделяет блок памяти в динамически расп-│
│ │ ределяемой области. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalAllocPtr │ Выделяет и блокирует блок памяти (с по-│
│ │ мощью вызовов GlobalAlloc и GlobalLock).│
│ │ │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalCompact │ Переупорядочивает память, распределен-│
│ │ ную в динамической области, так что ос-│
│ │ вобождается заданный объем памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDiscard │ Выгружает заданный объект памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDosAlloc │ Распределяет память, к которой можно по-│
│ │ лучить доступ в реальном режиме DOS. Эта│
│ │ память будет существовать в первом мега-│
│ │ байте линейного адресного пространства. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDosFree │ Освобождает память, выделенную ранее с│
│ │ помощью GlobalDosAlloc. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFlags │ Получает информацию о блоке памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFree │ Освобождает разблокированный блок памяти│
│ │ и делает его описатель недействительным.│
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFreePtr │ Разблокирует и освобождает блок памяти│
│ │ с помощью GlobalUnlock и GlobalFree. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalHandle │ Получает описатель объекта в памяти по│
│ │ заданному адресу сегмента. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLock │ Увеличивает счетчик ссылки блока памяти│
│ │ и возвращает указатель на него. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLockPtr │ То же, что и GlobalLock, но вместо опи-│
│ │ сателя воспринимает указатель. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLRUNewest │ Перемещает объект в памяти на новую не-│
│ │ давно используемую позицию, минимизируя,│
│ │ таким образом, вероятность выгрузки│
│ │ объекта. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLRUOldest │ Перемещает объект в памяти на самую│
│ │ "старую" недавно используемую позицию,│
B.Pascal 7 & Objects/LR - 286 -
│ │ максимизирую вероятность выгрузки объ-│
│ │ екта. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalNorify │ Вызывает адрес экземпляра процедуры уве-│
│ │ домления, передавая описатель блока, ко-│
│ │ торый нужно выгрузить. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPageLock │ Увеличивает значение счетчика блокиров-│
│ │ ки для памяти, связанной с данным селек-│
│ │ тором. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPageUnlock │ Уменьшает значение счетчика блокировки│
│ │ для памяти, связанной с данным селекто-│
│ │ ром. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPtrHandle │ По заданному указателю на блок памяти│
│ │ возвращает описатель этого блока. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalReAlloc │ Перераспределяет блок памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalReAllocPtr │ Разблокирует, перераспределяет и блоки-│
│ │ рует блок памяти (используя функции│
│ │ GlobalUnlock, GlobalReAlloc и│
│ │ GlobalLock). │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalSize │ Определяет текущий размер блока памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalUnfix │ Разблокирует блок памяти, блокированный│
│ │ ранее с помощью GlobalLock. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalUnockPtr │ То же, что и GlobalUnlock, но вместо│
│ │ описателя воспринимает указатель. │
├─────────────────────┼─────────────────────────────────────────┤
│ LockSegment │ Блокирует заданный выгружаемый сегмент. │
├─────────────────────┼─────────────────────────────────────────┤
│ UnlockSegment │ Разблокирует сегмент. │
└─────────────────────┴─────────────────────────────────────────┘
Функция GlobalAlloc используется для распределения блоков
памяти. Для их освобождения применяется функция GlobalFree. Адми-
нистратор памяти поддерживает три типа блоков памяти: фиксирован-
ный, перемещаемый и выгружаемый. Фиксированный блок остается в
одних и тех же адресах физической памяти. Перемещаемый блок может
перемещаться в физической памяти и освобождать место для других
запросов на выделение памяти, а выгружаемые блоки могут выгру-
жаться из памяти, освобождая место для других блоков. С помощью
передаваемых GlobalAlloc флагов вы можете выбрать один из этих
трех типов:
* gmem_Fixed (фиксированный)
* gmem_Moveable (перемещаемый)
* gmem_Moveable + gmem_Discardable (выгружаемый)
B.Pascal 7 & Objects/LR - 287 -
Прикладная программа обычно выделяет только перемещаемые
блоки памяти, которые представляются типом THandle в модуле
WinAPI. Описатель памяти - это значение размером в слово, которое
идентифицирует блок памяти аналогично тому, как описатель файла -
это значение размером в слово, идентифицирующее открытый файл.
Перед тем как вы сможете получить доступ к памяти, его нужно
заблокировать с помощью функции GlobalAlloc, а когда вы закончите
к нему обращаться, его нужно разблокировать с помощью функции
GlobalUnlock. GlobalLock возвращает полный 32-разрядный указатель
на первый байт блока. Смещение указателя всегда равно 0. В защи-
щенном режиме DOS селектор указателя - это тоже самое, что описа-
тель блока, но в Windows это не всегда так.
Правильная последовательность вызовов для выделения, блоки-
ровки, разблокировки или освобождения блока показана в приведен-
ном ниже примере. В данном примере H - это переменная типа
THandle, а P - указатель:
H := GlobalAlloc(gmem_Moveable, 8192); { выделение блока }
if H <> then { если память выделена }
begin
P := GlobalLock(H); { блокировка блока }
.
. { доступ к блоку через P }
.
GlobalUnlock(H); { разблокировать блок }
GlobalFree(H); { освободить блок }
end;
Блокировка и разблокировка блока при каждом обращении к нему
достаточно утомительна и ведет к ошибкам, и реально она необходи-
ма только для выгружаемых блоков и в прикладных программах
Windows, работающих в реальном режиме. Во всех других ситуациях
лучшим решением является блокировка блока сразу после его выделе-
ния и сохранение этого состояния до освобождения блока. С этой
целью модуль WinAPI включает в себя семейство подпрограмм-"оболо-
чек" GlobalXXXXPtr. Особый интерес представляет функция
GlobalAllocPtr, которая выделяет и блокирует блок памяти, и функ-
ция GlobalFreePtr, разблокирующая и освобождающая блок памяти. С
помощью этих подпрограмм приведенный выше пример можно упростить:
H := GlobalAlloc(gmem_Moveable, 8192); { выделение блока }
if H <> then { если память выделена }
begin
.
. { доступ к блоку }
.
GlobalFreePtr(P); { освободить блок }
end;
Вызвав функцию GlobalReAlloc, вы можете изменить размер или
атрибуты блока памяти, сохранив его содержимое. Функция
B.Pascal 7 & Objects/LR - 288 -
GlobalReAlloc возвращает новый описатель блока, который может от-
личаться от передаваемого функции описателя, если старый размер
или новый размер блок превышает 64К. Заметим, что в тех случаях,
когда старый размер блока и новый его размер меньше 64К,
GlobalReAlloc всегда может изменить размер блока, не изменяя его
описателя.
Функция GlobalReAlloc можно также использоваться для измене-
ния атрибутов блока. Это можно сделать, задав наряду с
gmem_Moveable или gmem_Discardable флаг gmem_Modify.
Функция GlobalReAlloc выполняет те же действия, что и
GlobalReAlloc, но обе они вместо описателей использует указатели.
Имеется также ряд других, менее часто используемых
GlobalXXXX. Все они подробно описаны в Главе 1 ("Справочник по
библиотеке") "Справочного руководства программиста".
B.Pascal 7 & Objects/LR - 289 -
Управление модулем
─────────────────────────────────────────────────────────────────
Администратор этапа выполнения поддерживает следующие подп-
рограммы обслуживания модулей:
Подпрограммы API обслуживания модулей Таблица 17.3
┌───────────────────────────┬───────────────────────────────────┐
│ Подпрограмма │ Описание │
├───────────────────────────┼───────────────────────────────────┤
│ FreeLibrary │ Делает недействительным загружен-│
│ │ ный модуль библиотеки, и освобож-│
│ │ дает соответствующую память, если│
│ │ ссылок на модуль больше нет. │
├───────────────────────────┼───────────────────────────────────┤
│ GetModuleFileName │ Дает полный маршрут и имя выполня-│
│ │ емого файла, задающий, откуда заг-│
│ │ ружен модуль. │
├───────────────────────────┼───────────────────────────────────┤
│ GetModuleHandle │ Определяет описатель заданного мо-│
│ │ дуля. │
├───────────────────────────┼───────────────────────────────────┤
│ GetModuleUsage │ Определяет счетчик ссылок на мо-│
│ │ дуль. │
├───────────────────────────┼───────────────────────────────────┤
│ GetProcAddress │ Определяет адрес экспортируемой│
│ │ библиотечной функции. │
├───────────────────────────┼───────────────────────────────────┤
│ LoadLibrary │ Загружает указанный библиотечный│
│ │ модуль. │
└───────────────────────────┴───────────────────────────────────┘
Некоторые из этих подпрограмм воспринимают в качестве пара-
метра описатель модуля. Описатель модуля самой прикладной прог-
раммы хранится в переменной HInstance, описанной в модуле System.
B.Pascal 7 & Objects/LR - 290 -
Управление ресурсами
─────────────────────────────────────────────────────────────────
Администратор этапа выполнения поддерживает следующие подп-
рограммы управления ресурсами:
Функции API управления ресурсами Таблица 17.4
┌──────────────────────┬────────────────────────────────────────┐
│ Функция │ Описание │
├──────────────────────┼────────────────────────────────────────┤
│ AccessResource │ Открывает заданный выполняемый файл и│
│ │ перемещает указатель файла на начало│
│ │ заданного ресурса. │
├──────────────────────┼────────────────────────────────────────┤
│ FindResource │ Определяет адрес ресурса в заданном│
│ │ файле ресурса. │
├──────────────────────┼────────────────────────────────────────┤
│ FreeResource │ Уменьшает счетчик ссылок для загружен-│
│ │ ного ресурса. Когда значение этого│
│ │ счетчика становится равным нулю, то ис-│
│ │ пользуемая ресурсом память освобождает-│
│ │ ся. │
├──────────────────────┼────────────────────────────────────────┤
│ LoadResource │ Загружает заданный ресурс в память. │
├──────────────────────┼────────────────────────────────────────┤
│ LoadString │ Загружает заданную строку ресурса. │
├──────────────────────┼────────────────────────────────────────┤
│ LockResource │ Блокирует заданный ресурс в памяти и│
│ │ увеличивает его счетчик ссылок. │
├──────────────────────┼────────────────────────────────────────┤
│ SizeOfResource │ Возвращает размер (в байтах) заданного│
│ │ ресурса. │
├──────────────────────┼────────────────────────────────────────┤
│ UnlockResource │ Разблокирует заданный ресурс и уменьша-│
│ │ ет на 1 счетчик ссылок на ресурс. │
└──────────────────────┴────────────────────────────────────────┘
Ресурсы могут компоноваться с прикладной программой с по-
мощью директив компилятора {$R имя_файла}. Указанные файлы должны
быть файлами ресурсов Windows (.RES). Обычно с прикладными прог-
раммами защищенного режима DOS компонуются только строковые ре-
сурсы и ресурсы, определенные пользователем. Другие типы ресурсов
Windows к прикладной программе DOS обычно неприменимы.
Примечание: Ресурсы Turbo Vision не следуют тем же
соглашениям, что ресурсы Windows, и к ним нельзя обращаться
с помощью подпрограмм API.
Некоторые подпрограммы API управления ресурсами требуют ука-
зания описателя экземпляра, которым обычно является указатель эк-
земпляра прикладной программы (который содержится в переменной
HInstance модуля System).
B.Pascal 7 & Objects/LR - 291 -
Управление селектором
─────────────────────────────────────────────────────────────────
Прикладной программе обычно не требуется манипулировать се-
лекторами, но в отдельных ситуациях полезно использовать следую-
щие подпрограммы обслуживания селектора:
Подпрограммы API управления селектором Таблица 17.5
┌───────────────────────┬───────────────────────────────────────┐
│ Функция │ Описание │
├───────────────────────┼───────────────────────────────────────┤
│ AllocDStoCSAlias │ Отображает селектор сегмента данных на│
│ │ селектор сегмента кода. │
├───────────────────────┼───────────────────────────────────────┤
│ AllocSelector │ Выделяет новый селектор. │
├───────────────────────┼───────────────────────────────────────┤
│ ChangeSelector │ Генерирует селектор кода, соответству-│
│ │ щий заданному селектору данных, или│
│ │ генерирует заданный селектор, соот-│
│ │ ветствующий селектору кода. │
├───────────────────────┼───────────────────────────────────────┤
│ FreeSelector │ Освобождает селектор, первоначально│
│ │ выделенный функциями AllocDStoCSAlias│
│ │ или AllocSelector. │
├───────────────────────┼───────────────────────────────────────┤
│ GetSelectorBase │ Дает базовый адрес селектора. │
├───────────────────────┼───────────────────────────────────────┤
│ GetSelectorLimit │ Возвращает предельное значение для за-│
│ │ данного селектора. │
├───────────────────────┼───────────────────────────────────────┤
│ PrestoChangoSelector│ Генерирует селектор кода, соответству-│
│ │ ющий заданному селектору данных, либо│
│ │ генерирует селектор данных, соответс-│
│ │ твующий селектору кода. │
├───────────────────────┼───────────────────────────────────────┤
│ SetSelectorBase │ Устанавливает базовый адрес селектора.│
├───────────────────────┼───────────────────────────────────────┤
│ SetSelectorLomit │ Устанавливает предельное значение се-│
│ │ лектора. │
└───────────────────────┴───────────────────────────────────────┘
B.Pascal 7 & Objects/LR - 292 -
Другие подпрограммы API
─────────────────────────────────────────────────────────────────
Администратор этапа выполнения поддерживает следующие допол-
нительные подпрограммы API:
Прочие подпрограммы API Таблица 17.6
┌───────────────────┬───────────────────────────────────────────┐
│ Функция │ Описание │
├───────────────────┼───────────────────────────────────────────┤
│ DOS3Call │ Вызывает функцию прерывания DOS 21h; вызы-│
│ │ вается только из подпрограмм ассемблера. │
├───────────────────┼───────────────────────────────────────────┤
│ FatalExit │ Передает отладчику текущее состояние опе-│
│ │ рационной среды защищенного режима и вы-│
│ │ выводит подсказку для ввода инструкций о│
│ │ продолжении работы. │
├───────────────────┼───────────────────────────────────────────┤
│ GetDOSEnviroment│ Определяет текущую строку операционной│
│ │ среды задачи. │
├───────────────────┼───────────────────────────────────────────┤
│ GetVersion │ Дает текущую версию операционной среды│
│ │ Windows или операционной системы DOS. │
├───────────────────┼───────────────────────────────────────────┤
│ GetWinFlags │ Дает используемые Windows флаги конфигура-│
│ │ ции памяти. │
├───────────────────┼───────────────────────────────────────────┤
│ MessageBox │ Создает, выводит на экран и обслуживает│
│ │ окно сообщений. │
└───────────────────┴───────────────────────────────────────────┘
Совместно используемая DLL, чтобы определить, выполняется ли
она в защищенном режиме DOS или под Windows, может использовать
функцию GetWinFlags, например:
if GetWinFlags and wf_DPMI <> 0 then
Message('Работа в защищенном режиме DOS')
else
Message('Работа в среде Windows');
B.Pascal 7 & Objects/LR - 293 -
Прямой доступ к DPMI-серверу
─────────────────────────────────────────────────────────────────
Прямой доступ к DPMI-серверу вы можете получить через преры-
вание $31, которое непосредственно вызывает DPMI-сервер в обход
администратора этапа выполнения. Однако это опасный прием. DPMI
не поддерживает очистку ресурсов, таких как векторы прерываний
памяти; корректно с этими проблемами работает администратор этапа
выполнения. Вы должны глубоко понимать концепции защищенного ре-
жима и знать о существенном риске, с которым связано использова-
ние данного метода доступа защищенного режима.
Компиляция прикладной программы защищенного режима
─────────────────────────────────────────────────────────────────
В большинстве случаев для получения прикладной программы за-
щищенного режима вам не нужно делать ничего особенного. Просто
скомпилируйте свою программу, задав в качестве целевой работы за-
щищенный режим одним из следующих способов:
* В IDE выберите команду Compile│Target и в диалоговом окне
Target Platform (Целевая платформа) выберите
Protected-mode Application.
* При использовании компилятора, работающего в режиме ко-
мандной строки, укажите для выбора в качестве целевой
платформы защищенного режима параметр /CP.
B.Pascal 7 & Objects/LR - 294 -
Выполнение программы защищенного режима DOS
─────────────────────────────────────────────────────────────────
Когда вы выполняете программу DOS защищенного режима, нужно
обеспечить наличие в текущем каталоге или по маршруту DOS файлов
DPMI16BI.OVL (сервер DPMI), RTM.EXE (администратор этапа выполне-
ния) и всех DLL, с которыми работает ваша программа.
Примечание: Лицензионное соглашение позволяет вам
распространять файлы DPMI16BI.OVL и RTM.EXE вместе с вашей
программой.
В выполняемом файле .EXE защищенного режима DOS используется
тот же формат файла, что и в Windows 3.x и OS/2 1.x. Этот формат
файла является надмножеством обычного формата .EXE DOS и состоит
из обычного образа файла .EXE, называемого фиктивным модулем, за
которым следует расширенный заголовок и код, данные и ресурсы за-
щищенного режима. Ниже показана последовательность событий при
выполнении программы защищенного режима DOS.
1. DOS загружает фиктивный модуль реального режима и переда-
ет ему управление.
2. Если средства DPMI отсутствуют, то фиктивный модуль заг-
ружает DPMI-сервер из файла DPMI16BI.OVL. Некоторые новые
администраторы памяти поддерживают средства DPMI (как,
например, это делается в окне DOS улучшенного режима
Windows 3.х). В таких конфигурациях фиктивный модуль не
загружает DPMI-сервер, но использует уже имеющийся.
3. Далее, если администратор этапа выполнения еще не загру-
жен в память, фиктивный модуль загружает его из файла
RTM.EXE. Если прикладная программа защищенного режима вы-
полняет другую программу защищенного режима, обе исполь-
зуют одну копию администратора этапа выполнения.
4. Если средства DPMI и администратор этапа выполнения при-
сутствуют, фиктивный модуль переключается из реального в
защищенный режим и передает управление расширенному заг-
рузчику .EXE в администратора этапа выполнения.
5. Загрузчик сначала загружает используемую прикладной прог-
раммой DLL (если она имеется), затем загружает сегменты
кода и данных прикладной программы. Наконец, загрузчик
передает управление на точку входа прикладной программы.
При выполнении вашей прикладной программы защищенного режима
DOS всегда возможно ситуация, когда уже присутствует DMPI-сервер,
отличный от сервера Borland. Поскольку между серверами могут быть
небольшие различия, особенно в плане обработки прерываний DOS, вы
должны проверить программу и убедиться, что она работает со всеми
возможными серверами, которые могут ей встретиться.
B.Pascal 7 & Objects/LR - 295 -
Когда прикладная программа защищенного режима DOS выполняет-
ся в окне DOS улучшенного режима Windows, вы можете управлять
объемом расширенной памяти, которую выделяет администратор этапа
выполнения, задав в файле .PIF прикладной программы предельное
значение памяти XMS.
Управление объемом используемой RTM памяти
─────────────────────────────────────────────────────────────────
По умолчанию администратор этапа выполнения использует при
загрузке всю доступную память. Затем по запросам он выделяет па-
мять своим клиентам (через подпрограммы API администратора памя-
ти).
В защищенном режиме нет разницы между обычной памятью (ниже
1 мегабайта) и расширенной памятью (с адресами выше 1 мегабайта);
для программ защищенного режима доступны оба типа памяти. Однако
администратор этапа выполнение отдает предпочтение расширенной
памяти. Только после того как вся расширенная память будет выде-
лена, или когда прикладная программа специально запрашивает
обычную память (например, с помощью функции GlobalDosAlloc), ад-
министратор этапа выполнения выделяет обычную память.
Причина, по которой администратор этапа выполнения предпочи-
тает расширенную память, заключается в том, что прикладная прог-
рамма может с помощью вызова подпрограммы Exec в модуле Dos по-
рождать другие прикладные программы. Порожденные прикладные прог-
раммы не обязательно являются программами защищенного режима; та-
ким образом, им может потребоваться обычная память. Фактически,
порожденные программы защищенного режима запускаются как програм-
мы реального режима и переключаются в защищенный режим только
после успешной загрузки фиктивным модулем средств DPMI и адми-
нистратора этапа выполнения.
Администратор этапа выполнения перед порождением прикладной
программы пытается освободить максимальный объем обычной памяти
(например, перенеся перемещаемые блоки в расширенную память). Од-
нако попытки освобождения расширенной памяти не предпринимаются.
Таким образом, если должны порождаться прикладные программы защи-
щенного режима, не использующие администратор этапа выполнения,
то необходим споcоб управления распределением памяти администра-
тором этапа выполнения.
Чтобы управлять тем, сколько памяти может использовать адми-
нистратор этапа выполнения, в командной строке DOS добавьте к
строке операционной среды DOS переменную среды RTM:
SET RTM={параметр nnnn}
Возможные параметры перечислены в следующей таблице. Значе-
ние nnnn может быть десятичным или шестнадцатиричным числом в ви-
де xAB54 или xab54.
B.Pascal 7 & Objects/LR - 296 -
Параметры переменной операционной
среды RTM, используемые для управления памятью Таблица 17.7
┌────────────────────┬──────────────────────────────────────────┐
│ Параметр │ Описание │
├────────────────────┼──────────────────────────────────────────┤
│ EXTLEAVE nnnn │ Всегда оставляет не менее nnnn килобайт│
│ │ доступной расширенной памяти. По умолча-│
│ │ нию это значение равно 640К. │
├────────────────────┼──────────────────────────────────────────┤
│ EXTMAX nnnn │ Не выделяет более nnnn килобайт расширен-│
│ │ ной памяти. По умолчанию используется│
│ │ значение 4 гигабайта. В Windows использу-│
│ │ емое по умолчанию значение равно половине│
│ │ доступной памяти. │
├────────────────────┼──────────────────────────────────────────┤
│ EXTMIN nnnn │ Если после применения EXTMAX или EXTLEAVE│
│ │ доступно менее nnnn килобайт, то програм-│
│ │ ма завершается с сообщением о нехватке│
│ │ памяти (Out of memory). По умолчанию это│
│ │ значение равно 0. │
├────────────────────┼──────────────────────────────────────────┤
│ REALLEAVE nnnn │ Всегда оставляет не менее nnnn параграфов│
│ │ доступной реальной памяти. По умолчанию│
│ │ это значение равно 64К или 4096 парагра-│
│ │ фов. │
├────────────────────┼──────────────────────────────────────────┤
│ REALMAX nnnn │ Не выделяет более nnnn параграфов реаль-│
│ │ ной памяти. По умолчанию это значение│
│ │ равно 1 мегабайту или 65535 параграфов. │
├────────────────────┼──────────────────────────────────────────┤
│ REALMIN nnnn │ Если после применения REALMAX и REALLEAVE│
│ │ доступно менее nnnn параграфов, то прог-│
│ │ рамма завершается с сообщением о нехватке│
│ │ памяти (Out of memory). По умолчанию это│
│ │ значение равно 0. │
└────────────────────┴──────────────────────────────────────────┘
Следующая команда DOS ограничивает RTM 2 мегабайтами расши-
ренной памяти и обеспечивает, что нераспределенными останутся
128К реальной памяти.
SET RTM=EXTMAX 2048 REALLEAVE 8192
B.Pascal 7 & Objects/LR - 297 -
───────────────────────────────────────────────────────────────────────