Руководство по языку B.Pascal 7

         

Переменная 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 будет ссылаться на тот же адрес, но с полномочиями на чте- ние/запись.


Содержание раздела