Микропроцессор 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К реальной памяти.