Микропроцессор 80286 дает новый способ адресации к памяти:
защищенный режим виртуальной адресации или просто защищенный ре-
жим. Этот новый режим адресации дает три основных преимущества:
* Адресация к памяти объемом до 16 мегабайт.
* Логическое адресное пространство, превышающее пространство
физических адресов.
* Способ изоляции программ друг от друга, так что одна прог-
рамма не может нарушать другой выполняющейся одновременно
с ней программы.
С помощью Borland Pascal вы легко можете писать работающие в
защищенном режиме прикладные программы DOS без необходимости при-
менения дополнительного "расширителя" DOS. Вы обнаружите, что
многие программы реального режима прекрасно работают в защищенном
режиме. Данная глава поможет вам модифицировать те программы, ко-
торые этого не делают, и прояснит некоторые основные моменты за-
щищенного режима и его отличия от реального режима.
Процессор 80286 и более поздние процессоры поддерживают два
режима операций: защищенный режим и реальный режим. Реальный ре-
жим совместим с работой процессора 8086 и позволяет прикладной
программе адресоваться к памяти объемом до одного мегабайта. За-
щищенный режим расширяет диапазон адресации до 16 мегабайт. Ос-
новное отличие между реальным и защищенным режимом заключается в
способе преобразования процессором логических адресов в физичес-
кие. Логические адреса - это адреса, используемые в прикладной
программе. Как в реальном, также и в защищенном режиме логический
адрес - это 32-разрядное значение, состоящее из 16-битового се-
лектора (адреса сегмента) и 16-битового смещения. Физические ад-
реса - это адреса, которые процессор использует для обмена данны-
ми с компонентами системной памяти. В реальном режиме физический
адрес представляет собой 20-битовое значение, а в защищенном ре-
жиме - 24-битовое.
Когда процессор обращается к памяти
(для выборки инструкции
или записи переменной), он генерирует
из логического адреса физи-
ческий адрес. В реальном режиме
генерация физического адреса сос-
тоит из сдвига селектора (адреса
сегмента) на 4 бита влево (это
означает умножение на 16) и
прибавления смещения. Полученный
в
результате 20-разрядный адрес
используется затем для доступа к
памяти.
16МбЪДДДДДДДДДДДДДДДДї
і і
ЪДДДДДДДДї і і
іСмещениеГДї і і
АДДДДДДДДЩ і і і
і
ГДДДДДДДДДДДДДДДДґї
АДДЕДДДДД>±±±±±±±±±±іГ сегмент 64К
ЪД>ГДДДДДДДДДДДДДДДДґЩ
і і і
і
і Пространство і
ЪДДДДДДДДї ЪДДДДДДї і
і адресов і
іСелекторГДґ x 16 ГДДДДДЩ і і
АДДДДДДДДЩ АДДДДДДЩ і і
0АДДДДДДДДДДДДДДДДЩ
Рис. 17.1 Генерация физического
адреса в реальном режиме.
Чтобы получить физический адрес в
защищенном режиме, селек-
торная часть логического адреса
используется в качестве индекса
таблицы дескрипторов. Запись
в таблице дескрипторов содержит
24-битовый базовый адрес, к которому затем для образования физи-
ческого адреса прибавляется смещение
логического адреса.
16МбЪДДДДДДДДДДДДДДДДї
і і
ЪДДДДДДДДї і і
іСмещениеГДї і і
АДДДДДДДДЩ і і і
і ГДДДДДДДДДДДДДДДДґї
Таблица дескрипторов
АДДЕДДДДД>±±±±±±±±±±іГ сегмент 64К
ЪДДДДДДї ЪД>ГДДДДДДДДДДДДДДДДґЩ
ГДДДДДДґ
і і і
ГДДДДДДґ і
і Пространство і
ГДДДДДДґ і
і адресов і
ЪД>ГДДДДДДґДДДЩ і і
і ГДДДДДДґ і і
і ГДДДДДДґ
0АДДДДДДДДДДДДДДДДЩ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
і ГДДДДДДґ
ЪДДДДДДДДї і ГДДДДДДґ
іСелекторГДЩ АДДДДДДЩ
АДДДДДДДДЩ
Рис. 17.2 Генерация физического
адреса в защищенном режиме.
Каждая запись в таблице
дескрипторов называется дескриптором
и определяет сегмент в памяти. Запись таблицы дескрипторов зани-
мает 8 байт, а записанная в
дескрипторе информация включает в се-
бя базовый адрес, предельное значение и флаги полномочий
доступа
к сегменту.
Записи предельного значения
сегмента и полномочий доступа в
дескрипторе определяют размер
и тип сегмента. Сегменты могут
иметь размер от 1 до 65536 байт и
могут быть сегментами кода или
сегментами данных. Сегменты кода могут содержать выполняемые
ма-
шинные инструкции и доступные только
по чтению данные. Сегменты
данных могут содержать данные, доступные по чтению и записи. За-
писывать данные в сегменты кода или
выполнять инструкции в сег-
ментах данных невозможно. Любая попытка сделать это или попытка
доступа к данным вне границ сегмента вызывает общий сбой по на-
рушению защиты
(сокращенно сбой GP). Поэтому
режим и называется
защищенным По данному адресу в реальном режиме
прикладная программа мо-
жет
определить физический адрес. В
защищенном режиме это обычно
не так, поскольку селекторная часть логического адреса является
индексом в таблице дескрипторов, и сам селектор не имеет прямого
отношения к вычислению физического
адреса. Это дает то
преиму-
щество, что управление
виртуальной памятью можно реализовать, не
влияя на прикладную программу. Например, путем простого обновле-
ния поля базового адреса дескриптора
сегмента, операционная сис-
тема может перемещать сегмент в
физической памяти без влияния на
использующую сегмент прикладную программу.
Прикладная программа
ссылается только на селектор
сегмента, и на селектор не
влияют
изменения в дескрипторе.
Прикладная программа редко имеет дело с дескрипторами. При
необходимости дескрипторы создаются
и уничтожаются операционной
системой и администратором памяти, а
прикладная программа знает о
соответствующих селекторах. Селекторы аналогичны описателям фай-
лов - с точки зрения прикладной
программы это то, что обслужива-
ется операционной системой, но в
операционной системе они работа-
ют как индексы содержащих
дополнительную информацию таблиц.
Расширения защищенного режима
Borland Pascal реализованы че-
рез два компонента: DPMI-сервер (файл
DPMI16BI.OVL) и администра-
тор этапа выполнения (файл RTM.EXE).
Интерфейс защищенного
режима 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).
Прикладные программы могут
получить доступ к программам за-
щищенного режима через модуль
WinAPI. Модуль WinAPI, описанный в
следующем разделе, реализует
подмножество функций API (прикладно-
го
программного интерфейса) Windows,
обеспечивая управление па-
мятью, обслуживание программных модулей, управление ресурсами,
загрузку динамически компонуемых библиотек и доступ к селекторам
на нижнем уровне. Поскольку администратор этапа выполнения
API
является подмножеством API
Windows, вы можете написать совмести-
мые на уровне двоичного кода
динамически компонуемые библиотеки,
которые можно использовать и в защищенном
режиме DOS, и в
Windows.
Написание прикладной программы защищенного режима не предс-
тавляет собой сложной задачи. Вам не нужно беспокоиться о селек-
торах и адресах памяти. Операционная система с расширениями
Borland все делает за вас. Фактически, большинство ваших программ
реального режима может прекрасно работать в защищенном режиме. В
следующих разделах описывается некоторая разница между реальным и
защищенным режимом, о которых вы должны знать при разработке
прикладной программы защищенного режима.
Существует несколько приемов, используемых обычно в програм-
мах реального режима, которые в программах защищенного режима бу-
дут приводить к общему нарушению защиты (сбой GP). Borland Pascal
при сбое GP выводит ошибку этапа выполнения 216. Сбой GP происхо-
дит, когда вы пытаетесь получить доступ к памяти, к которой ваша
прикладная программа обращаться не может. Операционная система
останавливает прикладную программу, но сбоя системы не происхо-
дит. Хотя сбои GP и прекращают работу вашей программы, система
"защищена" от сбоя. К сбою GP приводит следующее:
* загрузка в сегментные регистры недопустимых значений;
* обращение к памяти вне границы сегмента;
* запись в сегмент кода;
* разыменование указателей nil.
Примечание: Сбои по нарушению защиты предохраняют вашу
систему от плохой практики программирования.
Когда процессор работает в защищенном режиме, сегментные ре-
гистры (CS, DS, ES и SS) могут содержать только селекторы. Пос-
кольку селекторы являются индексами в таблице дескрипторов, они
не имеют физического отношения к памяти, на которую ссылается.
Если вы пытаетесь загрузить в сегментный регистр произвольное
значение, то возможно получите сбой GP, поскольку это значение
может не представлять допустимого дескриптора.
При разыменовании указателей компилятор генерирует код для
загрузки сегментного регистра. Если вы строите указатели с по-
мощью стандартной функции Ptr, то нужно обеспечить, чтобы сег-
ментная часть указателя была допустимым селектором. Аналогично,
при работе с массивами Mem, MemW и MemL вы вместо физических ад-
ресов должны использоваться селекторы. Например, при доступе к
рабочей области ROM BIOS (сегмент $0040) или к областям видеопа-
мяти (сегменты $A000, $B000 и $B800) следует использовать вместо
абсолютных значений переменные SegXXXX. (Переменные SegXXXX опи-
сываются ниже.)
В защищенном режиме вы не можете задавать абсолютный адрес
переменной. Любой исходных код, где сегмент и смещение задаются в
операторе absolute, нужно переписать. Например, вам может потре-
боваться построить указатель, используя переменные SegXXXX.
Добавление или вычитание значений из селекторной части ука-
зателя обычно не допускается. Например, добавление к селекторной
части указателя $1000 в реальном режиме увеличивает указатель на
64К, но в защищенном режиме результирующий указатель будет недо-
пустимым. Вместо этого для выделения и управления блоками памяти
следует использовать функцию GlobalXXXX модуля WinAPI.
В Borland Pascal существует способ выполнения арифметических
операций с селекторами с помощью переменной SelectorInc (см. ни-
же).
В реальном режиме некоторые старые программы на ассемблере
используют сегментные регистры для хранения временных переменных.
В защищенном режиме это работать не будет, так как обычно сохра-
няемые в сегментных регистрах временные значения не являются до-
пустимыми селекторами.
В реальном режиме каждый сегмент имеет размер 64К. В защи-
щенном режиме дескриптор сегмента содержит поле, специфицирующее
предельный размер сегмента, и если вы пытаетесь обратиться к дан-
ным вне границ сегмента, по получите сбой GP. При загрузке прик-
ладной программы администратор этапа выполнения устанавливает со-
ответствующие предельные значения для сегментов кода, данных и
стека. Кроме того, блок памяти, распределяемый с помощью функции
GlobalAlloc модуля WinAPI, имеет предельное значение сегмента,
соответствующее размеру блока памяти.
В реальном режиме можно записывать переменные в сегмент ко-
да, поскольку реальные режим не определяет, что может и что не
может существовать в сегменте. В защищенном режиме это не так.
Селектор защищенного режима имеет флаг чтения/записи или доступа
только по чтению, а селекторы кода всегда отмечены как доступные
только по чтению. Если вы пытаетесь записывать в селектор сегмен-
та кода, происходит сбой GP. Однако вы можете использовать псев-
доним и написать самомодифицирующийся код (см. ниже).
При преобразовании прикладной программы реального режима в
защищенный режим, в программе, которая уже годы работала без оши-
бок, возможно внезапное появление определенных ошибок. Например,
вы можете случайно разыменовывать указатель nil, или обнаружите,
что ваша программа содержит "потерянные" указатели, которые разы-
меновываются после их освобождения. В реальном режиме такие ошиб-
ки не обязательно проявляются, но в защищенном режиме они обычно
приводят к сбою GP. Согласно своему названию, защищенный режим
значительно лучше предохраняет вас от ошибок, связанных с указа-
телями.
Аналогично программе Borland Pascal реального режима, прог-
рамма защищенного режима содержит несколько сегментов кода, сег-
мент данных и сегмент стека. При загрузке программы защищенного
режима администратор этапа выполнения автоматически выделяет се-
лекторы для сегментов кода, данных и стека. Для сегментов кода
с помощью директивы компилятора $C можно управлять отдельными ат-
рибутами. В частности, сегменты кода можно сделать перемещаемыми
или фиксированными в физической памяти, они могут загружаться
предварительно или по запросу, а также могут быть выгружаемыми
или постоянными.
Примечание: Подробнее о директиве компилятора $C расс-
казывается в Главе 21 данного руководства и в Главе 2 ("Ди-
рективы компилятора") "Справочного руководства программис-
та".
Атрибуты сегмента кода позволяют вам обозначать сегмент как
статический (перемещаемый, предварительно загружаемый, постоян-
ный) или динамический (перемещаемый, загружаемый по запросу, выг-
ружаемый). Таким образом, в защищенном режиме вам не нужно ис-
пользовать модуль Overlay и директиву компилятора $O, и в версии
модуля System для защищенного режима переменные OvrXXXXXX отсутс-
твуют.
Администратор динамически распределяемой области памяти
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. Например, если у вас был код следующего вида:
CtrMode := Mem[$40: $49];
то вместо него следует записать:
CtrMode := Mem[Seg0040: $49];
Используя переменные SegXXXX, вы можете гарантировать, что
ваша программа без изменений будет работать в реальном и защищен-
ном режимах.
Переменная 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(
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 для доступа к псевдонимам сегментов, выделяемых
администратором этапа выполнения при загрузке прикладной програм-
мы. Для каждого сегмента кода прикладной программы администратор
этапа выполнения создает селектор-псевдоним, ссылающийся на тот
же сегмент, но имеющий полномочия селектора данных. Для сегментов
стека и данных селекторы-псевдонимы не создаются.
Чтобы получить доступ к селектору-псевдониму для конкретного
сегмента, добавьте к селектору сегмента SelectorInc. Предположим,
например, что P - это переменная типа Pointer, а Foo - процедура
или функция. Тогда присваивание вида:
P := Addr(Foo)
приводит к тому, что P будет указывать на выполняемую доступную
только по чтению точку входа Foo, а после оператора:
P := Ptr(Seg(Foo) + SelectorInc, Ofs(Foo));
P будет ссылаться на тот же адрес, но с полномочиями на чте-
ние/запись.
Модуль 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.
Таблица 17.2
ЪДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і Функция і Описание і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GetFreeSpace і Определяет объем свободной памяти в ди-і
і і намически распределяемой области. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalAlloc і Выделяет блок памяти в динамически расп-і
і і ределяемой области. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalAllocPtr і Выделяет и блокирует блок памяти (с по-і
і і мощью вызовов GlobalAlloc и GlobalLock).і
і і і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalCompact і Переупорядочивает память, распределен-і
і і ную в динамической области, так что ос-і
і і вобождается заданный объем памяти. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalDiscard і Выгружает заданный объект памяти. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalDosAlloc і Распределяет память, к которой можно по-і
і і лучить доступ в реальном режиме DOS. Этаі
і і память будет существовать в первом мега-і
і і байте линейного адресного пространства. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalDosFree і Освобождает память, выделенную ранее сі
і і помощью GlobalDosAlloc. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalFlags і Получает информацию о блоке памяти. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalFree і Освобождает разблокированный блок памятиі
і і и делает его описатель недействительным.і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalFreePtr і Разблокирует и освобождает блок памятиі
і і с помощью GlobalUnlock и GlobalFree. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalHandle і Получает описатель объекта в памяти поі
і і заданному адресу сегмента. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalLock і Увеличивает счетчик ссылки блока памятиі
і і и возвращает указатель на него. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalLockPtr і То же, что и GlobalLock, но вместо опи-і
і і сателя воспринимает указатель. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalLRUNewest і Перемещает объект в памяти на новую не-і
і і давно используемую позицию, минимизируя,і
і і таким образом, вероятность выгрузкиі
і і объекта. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і GlobalLRUOldest і Перемещает объект в памяти на самуюі
і і "старую" недавно используемую позицию,і
і і максимизирую вероятность выгрузки объ-і
і і екта. і
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і 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 (выгружаемый)
Прикладная программа обычно выделяет только перемещаемые
блоки памяти, которые представляются типом 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, вы можете изменить размер или
атрибуты блока памяти, сохранив его содержимое. Функция
GlobalReAlloc возвращает новый описатель блока, который может от-
личаться от передаваемого функции описателя, если старый размер
или новый размер блок превышает 64К. Заметим, что в тех случаях,
когда старый размер блока и новый его размер меньше 64К,
GlobalReAlloc всегда может изменить размер блока, не изменяя его
описателя.
Функция GlobalReAlloc можно также использоваться для измене-
ния атрибутов блока. Это можно сделать, задав наряду с
gmem_Moveable или gmem_Discardable флаг gmem_Modify.
Функция GlobalReAlloc выполняет те же действия, что и
GlobalReAlloc, но обе они вместо описателей использует указатели.
Имеется также ряд других, менее часто используемых
GlobalXXXX. Все они подробно описаны в Главе 1 ("Справочник по
библиотеке") "Справочного руководства программиста".
Администратор этапа выполнения поддерживает следующие подп-
рограммы обслуживания модулей:
Подпрограммы API обслуживания модулей Таблица 17.3
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і Подпрограмма і Описание і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і FreeLibrary і Делает недействительным загружен-і
і і ный модуль библиотеки, и освобож-і
і і дает соответствующую память, еслиі
і і ссылок на модуль больше нет. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetModuleFileName і Дает полный маршрут и имя выполня-і
і і емого файла, задающий, откуда заг-і
і і ружен модуль. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetModuleHandle і Определяет описатель заданного мо-і
і і дуля. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetModuleUsage і Определяет счетчик ссылок на мо-і
і і дуль. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetProcAddress і Определяет адрес экспортируемойі
і і библиотечной функции. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і LoadLibrary і Загружает указанный библиотечныйі
і і модуль. і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
Некоторые из этих подпрограмм воспринимают в качестве пара-
метра описатель модуля. Описатель модуля самой прикладной прог-
раммы хранится в переменной HInstance, описанной в модуле System.
Администратор этапа выполнения поддерживает следующие подп-
рограммы управления ресурсами:
Функции 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).
Прикладной программе обычно не требуется манипулировать се-
лекторами, но в отдельных ситуациях полезно использовать следую-
щие подпрограммы обслуживания селектора:
Подпрограммы API управления селектором Таблица 17.5
ЪДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і Функция і Описание і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і AllocDStoCSAlias і Отображает селектор сегмента данных наі
і і селектор сегмента кода. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і AllocSelector і Выделяет новый селектор. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і ChangeSelector і Генерирует селектор кода, соответству-і
і і щий заданному селектору данных, илиі
і і генерирует заданный селектор, соот-і
і і ветствующий селектору кода. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і FreeSelector і Освобождает селектор, первоначальноі
і і выделенный функциями AllocDStoCSAliasі
і і или AllocSelector. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetSelectorBase і Дает базовый адрес селектора. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і GetSelectorLimit і Возвращает предельное значение для за-і
і і данного селектора. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і PrestoChangoSelectorі Генерирует селектор кода, соответству-і
і і ющий заданному селектору данных, либоі
і і генерирует селектор данных, соответс-і
і і твующий селектору кода. і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і SetSelectorBase і Устанавливает базовый адрес селектора.і
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і SetSelectorLomit і Устанавливает предельное значение се-і
і і лектора. і
АДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
Администратор этапа выполнения поддерживает следующие допол-
нительные подпрограммы 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');
Прямой доступ к DPMI-серверу вы можете получить через преры-
вание $31, которое непосредственно вызывает DPMI-сервер в обход
администратора этапа выполнения. Однако это опасный прием. DPMI
не поддерживает очистку ресурсов, таких как векторы прерываний
памяти; корректно с этими проблемами работает администратор этапа
выполнения. Вы должны глубоко понимать концепции защищенного ре-
жима и знать о существенном риске, с которым связано использова-
ние данного метода доступа защищенного режима.
В большинстве случаев для получения прикладной программы за-
щищенного режима вам не нужно делать ничего особенного. Просто
скомпилируйте свою программу, задав в качестве целевой работы за-
щищенный режим одним из следующих способов:
* В IDE выберите команду CompileіTarget и в диалоговом окне
Target Platform (Целевая платформа) выберите
Protected-mode Application.
* При использовании компилятора, работающего в режиме ко-
мандной строки, укажите для выбора в качестве целевой
платформы защищенного режима параметр /CP.
Когда вы выполняете программу 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, вы
должны проверить программу и убедиться, что она работает со всеми
возможными серверами, которые могут ей встретиться.
Когда прикладная программа защищенного режима DOS выполняет-
ся в окне DOS улучшенного режима Windows, вы можете управлять
объемом расширенной памяти, которую выделяет администратор этапа
выполнения, задав в файле .PIF прикладной программы предельное
значение памяти XMS.
По умолчанию администратор этапа выполнения использует при
загрузке всю доступную память. Затем по запросам он выделяет па-
мять своим клиентам (через подпрограммы API администратора памя-
ти).
В защищенном режиме нет разницы между обычной памятью (ниже
1 мегабайта) и расширенной памятью (с адресами выше 1 мегабайта);
для программ защищенного режима доступны оба типа памяти. Однако
администратор этапа выполнение отдает предпочтение расширенной
памяти. Только после того как вся расширенная память будет выде-
лена, или когда прикладная программа специально запрашивает
обычную память (например, с помощью функции GlobalDosAlloc), ад-
министратор этапа выполнения выделяет обычную память.
Причина, по которой администратор этапа выполнения предпочи-
тает расширенную память, заключается в том, что прикладная прог-
рамма может с помощью вызова подпрограммы Exec в модуле Dos по-
рождать другие прикладные программы. Порожденные прикладные прог-
раммы не обязательно являются программами защищенного режима; та-
ким образом, им может потребоваться обычная память. Фактически,
порожденные программы защищенного режима запускаются как програм-
мы реального режима и переключаются в защищенный режим только
после успешной загрузки фиктивным модулем средств DPMI и адми-
нистратора этапа выполнения.
Администратор этапа выполнения перед порождением прикладной
программы пытается освободить максимальный объем обычной памяти
(например, перенеся перемещаемые блоки в расширенную память). Од-
нако попытки освобождения расширенной памяти не предпринимаются.
Таким образом, если должны порождаться прикладные программы защи-
щенного режима, не использующие администратор этапа выполнения,
то необходим споcоб управления распределением памяти администра-
тором этапа выполнения.
Чтобы управлять тем, сколько памяти может использовать адми-
нистратор этапа выполнения, в командной строке DOS добавьте к
строке операционной среды DOS переменную среды RTM:
SET RTM={параметр nnnn}
Возможные параметры перечислены в следующей таблице. Значе-
ние nnnn может быть десятичным или шестнадцатиричным числом в ви-
де xAB54 или xab54.
Параметры переменной операционной
среды 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К реальной памяти.