Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Руководство по языку Паскаль 1.doc
Скачиваний:
12
Добавлен:
22.04.2019
Размер:
2.48 Mб
Скачать

Глава 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 -

───────────────────────────────────────────────────────────────────────

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]