Глава 17. Программирование в защищенном режиме DOS

             Микропроцессор 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 защищенного режима 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).

             Прикладные программы могут получить доступ к программам  за-

        щищенного режима через модуль WinAPI.  Модуль WinAPI, описанный в

        следующем разделе, реализует подмножество функций API (прикладно-

        го  программного интерфейса) Windows,  обеспечивая управление па-

        мятью,  обслуживание программных модулей,  управление  ресурсами,

        загрузку  динамически компонуемых библиотек и доступ к селекторам

        на нижнем уровне.  Поскольку администратор этапа  выполнения  API

        является подмножеством API Windows,  вы можете написать совмести-

        мые на уровне двоичного кода динамически компонуемые  библиотеки,

        которые  можно  использовать  и  в  защищенном  режиме  DOS,  и в

        Windows.

Разработка прикладных программ DOS защищенного режима

             Написание прикладной программы защищенного режима не  предс-

        тавляет собой сложной задачи.  Вам не нужно беспокоиться о селек-

        торах и  адресах  памяти.  Операционная  система  с  расширениями

        Borland все делает за вас. Фактически, большинство ваших программ

        реального режима может прекрасно работать в защищенном режиме.  В

        следующих разделах описывается некоторая разница между реальным и

        защищенным режимом,  о которых вы  должны  знать  при  разработке

        прикладной программы защищенного режима.

Надежное программирование в защищенном режиме

             Существует несколько приемов, используемых обычно в програм-

        мах реального режима, которые в программах защищенного режима бу-

        дут приводить к общему нарушению защиты (сбой GP). Borland Pascal

        при сбое GP выводит ошибку этапа выполнения 216. Сбой GP происхо-

        дит, когда вы пытаетесь получить доступ к памяти,  к которой ваша

        прикладная программа  обращаться  не может.  Операционная система

        останавливает прикладную  программу,  но сбоя системы не происхо-

        дит.  Хотя сбои GP и прекращают работу вашей  программы,  система

        "защищена" от сбоя. К сбою GP приводит следующее:

 

             * загрузка в сегментные регистры недопустимых значений;

 

             * обращение к памяти вне границы сегмента;

 

             * запись в сегмент кода;

 

             * разыменование указателей nil.

 

                   Примечание: Сбои по нарушению защиты предохраняют вашу

              систему от плохой практики программирования.

Загрузка в сегментные регистры недопустимых значений

             Когда процессор работает в защищенном режиме, сегментные ре-

        гистры (CS,  DS,  ES и SS) могут содержать только селекторы. Пос-

        кольку селекторы являются индексами в таблице  дескрипторов,  они

        не имеют  физического  отношения к памяти,  на которую ссылается.

        Если вы пытаетесь загрузить  в  сегментный  регистр  произвольное

        значение, то  возможно  получите сбой GP,  поскольку это значение

        может не представлять допустимого дескриптора.

Функция Ptr и массивы Mem

             При разыменовании указателей компилятор генерирует  код  для

        загрузки сегментного  регистра.  Если  вы строите указатели с по-

        мощью стандартной функции 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

             При преобразовании  прикладной  программы реального режима в

        защищенный режим, в программе, которая уже годы работала без оши-

        бок,  возможно внезапное появление определенных ошибок. Например,

        вы можете случайно разыменовывать указатель 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

             Переменная 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

             Модуль 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.

Подпрограммы управления памятью 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   і Перемещает  объект  в  памяти  на  самуюі

        і                     і "старую" недавно  используемую  позицию,і

        і                     і максимизирую вероятность  выгрузки  объ-і

        і                     і екта.                                   і

        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

        і   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:

 

                             Прочие подпрограммы 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-серверу

             Прямой доступ к DPMI-серверу вы можете получить через преры-

        вание $31,  которое  непосредственно вызывает DPMI-сервер в обход

        администратора этапа выполнения.  Однако это опасный прием.  DPMI

        не поддерживает  очистку  ресурсов,  таких как векторы прерываний

        памяти; корректно с этими проблемами работает администратор этапа

        выполнения.  Вы должны глубоко понимать концепции защищенного ре-

        жима и знать о существенном риске,  с которым связано использова-

        ние данного метода доступа защищенного режима.

Компиляция прикладной программы защищенного режима

             В большинстве случаев для получения прикладной программы за-

        щищенного режима  вам  не нужно делать ничего особенного.  Просто

        скомпилируйте свою программу, задав в качестве целевой работы за-

        щищенный режим одним из следующих способов:

 

             * В  IDE выберите команду CompileіTarget и в диалоговом окне

               Target    Platform    (Целевая     платформа)     выберите

               Protected-mode Application.

 

             * При  использовании  компилятора,  работающего в режиме ко-

               мандной строки,  укажите для  выбора  в  качестве  целевой

               платформы защищенного режима параметр /CP.

Выполнение программы защищенного режима 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, вы

        должны проверить программу и убедиться, что она работает со всеми

        возможными серверами, которые могут ей встретиться.

             Когда прикладная программа защищенного режима DOS выполняет-

        ся в окне DOS улучшенного режима  Windows,  вы  можете  управлять

        объемом расширенной памяти,  которую выделяет администратор этапа

        выполнения,  задав в файле .PIF прикладной  программы  предельное

        значение памяти XMS.

Управление объемом используемой RTM памяти

             По умолчанию  администратор  этапа выполнения использует при

        загрузке всю доступную память.  Затем по запросам он выделяет па-

        мять своим  клиентам (через подпрограммы 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К реальной памяти.