                    12. Работа с памятью.
                          A. Обзор.

     О 640 Кбайтовом барьере MS-DOS было много сказано, и мно-
гие из нас испытали его на себе. Сложное программное обеспече-
ние требует  большой  объем памяти под код и особенно под дан-
ные, но что делать, если для его работы не хватает места. Име-
ется две альтернативы при использовании обычного ОЗУ.

     Первая из  них  - расширенная память,  доступна только на
машинах с процессорами 286,  386 или 486.  Расширенная  память
находится выше  границы 1 Мбайт и доступна только после перек-
лючения этих машин в защищенный режим.

     Вторая альтернатива -  дополнительная  память,  допустима
только на машинах,  совместимых с IBM, которые оснащены допол-
нительной платой, предназначенной для работы с Expanded Memory
Specification, или  сокращенно EMS.  Память EMS доступна через
драйвер Expanded Memory Manager (EMM),  а также насколько фирм
разработали драйверы,  которые позволяют эмулировать на расши-
ренной памяти дополнительную память.  Однако Turbo  Pascal  не
имеет средств для использования расширенной или дополнительной
памяти. Но эти средства вам предоставляет Object Professional.

     Юнита OPEMS содержит набор подпрограмм для работы  с  до-
полнительной памятью.  Они  позволяют  определить  наличный  и
доступный объем памяти EMS.  Вы можете выделить  и  освободить
память,  сохранить и восстановить текущее состояние (контекст)
системы управления дополнительной  памятью,  если  резидентной
программе требуется доступ к дополнительной памяти.

     Мы должны  сказать,  что  OPEMS предназначен для работы с
EMS версии 3.0 и выше.  В настоящее время он  не  поддерживает
новые функции, введенные в версии 4.0.

     Память EMS  выделяется  блоками по 16 Кбайт,  называемыми
страницами. Поэтому ее удобно использовать для хранения масси-
вов среднего размера,  связных списков и деревьев,  однако она
не идеальна для хранения небольших объемов данных,  к  которым
требуется частый и быстрый доступ.  Если вам требуются неболь-
шие объемы данных,  то лучше использовать динамическое выделе-
ние в  обычной памяти,  используя New или GetMem.  Хотя EMS не
очень подходит для хранения больших  массивов,  однако  Object
Professional   предлагает   решение   этой  проблемы  в  юните
OPLARRAY.  Используя OPLARRAY вы можете работать  с  массивами
размером до 8 Мбайт. Смотрите главу 8 раздел С.

     Аналогично, юнита OPEXTMEM предоставляет вам средства для
работы с расширенной памятью.  Подпрограммы  обеспечивают  вам
доступ к   расширенной   памяти   без  использования  программ
VDISK.SYS, RAMDRIVE.SYS или совместимым с ними.  Для доступа к
расширенной памяти вы должны сделать следующее:

     1. Определить,  сколько памяти доступно, используя проце-
дуру ExtMemAvail.
     2. Если места достаточно, функцией GetExtMem выделить не-
обходимый объем.
     3. После   выделения   памяти   с   помощью  подпрограммы
MoveExtMem вы можете перемещать данные  из  обычной  памяти  в
расширенную и наоборот.

     Как мы уже говорили, OPEXTMEM содержит функции для работы
с расширенной памятью парные  к  встроенным  процедурам  Turbo
Pasca: MemAvail,  GetMem,  FreeMem,  FreeMem,  Mark, Reliase и
Move. Хотя имена аналогичны,  они сильно отличаются и  при  их
использовании необходимо помнить некоторые вещи.

     Первое и самое важное то,  что выделять и освобождать па-
мять надо последовательно. Если вы выделили три блока памяти и
затем освободили  средний,  то  вся  память выше первого блока
станет доступной. (Причину этого вы найдете, просмотрев исход-
ники к OPEXTMEM.)

     Второе, вы  должны помнить,  что все адреса в расширенной
памяти считаются линейными и не  сегментными.  Например,  сег-
ментный  адрес  $0040:0012  соответствует линейному $00000412.
Небольшое неудобство заключается в том,  что  при  перемещении
данных из расширенной памяти в обычную и наоборот вам придется
транслировать адреса из сегментной нотации в  линейную  с  по-
мощью PtrToHuge.  Большое  преимущество  в том,  что указатель
huge - это просто длинное целое, и поэтому вы можете создавать
массивы размером  больше,  чем  64K  в  расширенной  памяти  и
использовать для индексации в  них  длинные  целые.  Например,
если HP - это huge указатель на массив, то вы можете вычислить
адрес N-ого элемента массива следующим образом:

     HPn :=HugrPtr(LongInt(HP)+(LongInt(N) * SizeOf(Element)));

     Третье, GetExtMem позволяет вам  выделять  память  только
блоками размером один килобайт (1024 байт).  Как и память EMS,
это делает ее менее удобной,  чем основная память, однако поз-
воляет вам  выделять  память размером несколько мегабайт одним
вызовом GetExtMem.  Кроме этого,  система управления памятью в
ранних версиях  RAMDRIVE.SYS  может  поддерживать только до 95
блоков памяти,  один из которых всегда используется в качестве
электронного диска.  Хотя OPEXTMEM позволяет вам иметь больше,
чем 94 блока памяти (пока не исопльзуется RAMDRIVE.SYS), вы не
должны использовать больше, если хотите, чтобы ваша прогорамма
была совместима с RAMDRIVE.SYS.

     Четвертое, процедура MoveExtMem, используемая для переда-
чи данных между нормальной памятью и расширенной, не позволяет
вам передавать данные байтами,  а только словами (два  байта).
Это означает, что вы должны быть вдвойне осторожными при выбо-
ре структур данных, и что вам придется иногда расширять струк-
туры данных  до границы слова.  Однако удобство состоит в том,
что вы можете одним вызовом MoveExtMem переместить 128 К  дан-
ных.

     Пятое, для приспособления к RAMDRIVE.SYS большинство про-
цедур OPEXTMEM требуют чуть больше 1К в  стеке  для  локальных
переменных. Вы должны помнить это при работе с юнитами,  кото-
рые ограничиваю объем стека.

     И последнее важное замечание состоит в том,  что OPEXTMEM
работает только  с DOS версии 3.х и 4.х.  Это ограничение про-
исходит из-за того,  что необходимо исключить конфликты, кото-
рые  могут  возникнуть  при работе в блоке совместимости OS/2.
Тот факт,  что OPEXTMEM не работает с DOS версии 2.х, не может
вам помешать,  поскольку машины с процессорами 286,  386 и 486
(там, где может использоваться расширенная память) не работают
под DOS 2.х.

     После того,  как был написан OPEXTMEM, Microsoft реализо-
вала новые спецификации и драйвер расширенной памяти,  назван-
ный XMS  (eXtended  Memory Specification).  В настоящий момент
OPEXTMEM не поддерживает XMS.



              B. OPEMS: Управление памятью EMS.

     В данном разделе мы опишем все типы, переменные, констан-
ты, процедуры и функции,  которые вы  найдете  в  интерфейсном
разделе юниты OPEMS.

                          Константы.

     EmsErroeCode = $0FFFF;

     Используется некоторыми  процедурами OPEMS для сигнализа-
ции об ошибке.

AllocateEmsPages
──────────────────────────────────────────────────────────────
Объявление

     function AllocateEmsPages(NumPages : Word) : Word;

Функция

     Выделяет указанное число страниц и возвращает дескриптор.

Описание

     Эта функция позволяет вам выделять дополнительную  память
страницами по 16К (16384 байт). Вы можете ее рассматривать как
комбинацию функций Turbo Pascal GetMem, которая выделяет обыч-
ную память, и функций открытия файла, которые возвращают деск-
риптор.  Как  и  дескриптор  файла,  дескриптор,  возвращаемый
AllocateEmsPages -  это ваш билет для доступа к выделенной па-
мяти. Обычно он используется для отображения страниц на  обыч-
ную  память (используя MapEmsPages) и для освобождения памяти,
когда она больше не нужна ( используя DeallocateEmsHandle).

     В случае ошибки AllocateEmsPages возвращает EmsErrorCode.
Чаще всего ошибка появляется,  если для удовлетворения запроса
нехватает памяти. Вы можете определить число доступных страниц
с помощью EmsPagesAvail.

     Замечание по поводу дескрипторов: Хотя стандартные версии
 систем управления EMS связывают дескрипторы в  порядке  $FE00,
$FE01, $FE02  и  т.д.,  этот порядок не гарантируется для всех
версий драйверов EMM. Мы обнаружили один драйвер, возвращавший
дескрипторы в порядке 0, 1, 2 и т.д.

Пример

     PagestoAllocate := 4;
     if (EmsPagesAvail >= PagesToAllocate) then begin
        MyEmsHandle := AllocateEmsPages(PagesToAllocate);
           if (MyEmsHandle = EmsErrorCode) then
             { ошибка }
       end else
        { не хватает памяти }

     Это пример  того,  ка  к выделить 64К (4 страницы по 16К)
памяти EMS,  используя AllocateEmsPages. Заметим, что в начале
вызывается EmsPagesAvail, чтобы убедиться, что хватает памяти.

Смотрите также

     DeallocateEmsHandle          MapEmsPage
     EmsPagesAvail

DeallocateEmsPages
──────────────────────────────────────────────────────────────
Объявление

     function DeallocateEmsPages(Handle : Word) : Boolean;

Функция

     Освобождает указанный дескриптор и связанную  с  ним  па-
мять.

Описание

     Эта функция  является эквивалентом для памяти EMS функций
Dispose и FreeMem.  Она позволяет вам освободить память, выде-
ленную до этого с помощью AllocateEmsPages. Заметим, что необ-
ходим только дескриптор,  который вернула AllocateEmsPages,  а
число страниц  не нужно.  DeallocateEmsPages возвращает False,
если дескриптор не может быть освобожден.  Чаще всего это слу-
чается, если дескриптор неверный, или если уже был освобожден.

     Очень важно:  В отличие от OPEXTMEM,  OPEMS автоматически
не освобождает выделенную вами память.  Поэтому ваша программа
должна содержать дескриптор выхода,  который освобождал бы па-
мять при завершении. Простейший пример смотрите ниже.

Пример

     MyEmsHandle := AllocateEmsPages(PagesToAllocate);
     ...
     if not DeallocateEmsPages(MyEmsHandle) then { ошибка }

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

     {$F+}
     procedure MyExitProc;
     begin
        ExitProc := SaveExitProc;
        if not DeallocateEmsPages(MyEmsHandle) then { ошибка }
     end;
     {$F-}
     ...
     SaveExitProc := ExitProc;
     ExitProc := @MyExitProc;

     Простейшая программа обработки выхода освобождает всю па-
мять, связанную с дескриптором MyEmsHandle.

Смотрите также

     AllocateEmsPages

EmmSigFound
──────────────────────────────────────────────────────────────
Объявление

     function EmmSigFound : Boolean;

Функция

     Возвращает True, если найдена сигнатура EMM.

Описание

     Как и  EmsInstalled,  эта  функция  пытается  определить,
установлена ли EMM. Однако использует для этого другой способ.
Она проверяет на равенство nil вектор $67,  используемый  этим
драйвером.  Если он равен nil, она возвращает False. Если нет,
она просматривает память по смещению  10  от  адреса  сегмента
вектора для поиска сигнатуры EMM.  Сигнатура - это массив, со-
держащий "EMMXXXX0". Если сигнатура найдена, EmmSigFound возв-
ращает Troe.

     Хотя этот   метод  широко  используется  (его,  например,
использует система управления оверлеями TurboPascal), мы реко-
мендуем,  если это возможно,  вместо этой функции использовать
EmsInstalled.  Некоторые ранние драйверы не прошли этот  тест,
но прошли тест на дескрипторы, используемые в EmsInstalled.

Смотрите также

     EmsInstalled

EmsActiveHandles
──────────────────────────────────────────────────────────────
Объявление

     function EmsActiveHandles : Word;

Функция

     Возвращает число активных дескрипторов EMS.

Описание

     Эта функция позволяет вам определить число активных деск-
рипторов EMS,  которые были связаны системой  управления  EMS.
Как и EmsTotalPages, она используется для отображения информа-
ции о текущем  состоянии.  В  случае  ошибки  EmsActiveHandles
возвращает EmsErrorCode. Во многих случаях ошибка та же, что и
для EmsStatusOk.

Пример

     WriteLn(LongInt(EmsTotalPages)*16384,' байт памяти имеется');
     WriteLn(LongInt(EmsPagesAvail)*16384,' байт доступно');
     WriteLn(EmsActiveHandles,' активных дескрипторов');

     Обращение к EmsActiveHandles позволяет вывести  программе
число активных дескрипторов.

Смотрите также

     EmsStatusOk                  EmsTotalPages

EmsInstalled
──────────────────────────────────────────────────────────────
Объявление

     function EmsInstalled : Boolean;

Функция

     Возвращает True, если загружена EMM.

Описание

     Эта функция  сообщает  вам,  установлена ли EMM (Expanded
Memory Manager).  Она не сообщает,  установлена  ли  плата  на
основе EMS.  Вы должны вызывать данную процедуру перед исполь-
зованием любых других процедур и функций из юниты OPEMS. Иног-
да  вам  придется использовать функцию EmsVersion,  чтобы быть
уверенным в том,  что определенная функция EMS в данной версии
доступна.

     EmsInstalled для определения наличия EMM использует  тест
дескрипторов. Она  пытается открыть "EMMXXXX0",  если операция
заканчивается успешно,  функция возвращает True.  Это наиболее
надежный тест на наличие EMM, однако в редких случаях он может
привести к определенным  проблемам.  Если  они  возникнут,  то
вместо нее вызовите EmmSigFound.

Пример

     if not EmsInstalled then begin
        WriteLn('Эта программа требует EMS. Завершение...');
        Halt;
     end;

     В этом примере программа,  которой для  работы  требуется
память EMS, завершается, если EmsInstalled возвращает False.

Смотрите также

     EmmSigFound                  EmsVersion

EmsPageFramePtr
──────────────────────────────────────────────────────────────
Объявление

     function EmsPageFramePtr : Pointer;

Функция

     Возвращает базовый  адрес страничного блока как указатель
на страничный блок.

Описание

     Эта функция возвращает указатель на базовый  адрес  стра-
ничного блока, используемого EMM. Страничный блок занимает це-
лый 64К блок,  разбитый на четыре страницы по 16К.  Эти четыре
страницы называют физическими страницами,  в противоположность
логическим страницам,  поскольку они присутствуют внутри 1 ме-
габайтового адресного пространства процессора 8086. Логические
же  страницы  находятся в расширенной памяти,  и их номера за-
висят от связанного с ними дескриптора.  Если вы выделяете три
страницы с помощью AllocateEmsPages для определенного дескрип-
тора,  то вы будете ссылаться на них как на  0,  1  и  2.  Для
доступа  к  содержимому логической страницы вы должны отобрра-
зить ее на  одну  из  четырех  физических  страниц  с  помощью
MapEmsPage.

     Простейший путь понимания концепции старничных блоков это
рассмотреть их в виде некоторой простой структуры данных:

     type EmsPage = array[1..16384] of Byte;
          EmsPageFrame = record
              Page0,Page1,Page2 : EmsPage;
              Page3 : array[1..16369] of Byte;
          end;
          PageFramePtr = ^EmsPageFrame;

     Заметим, что поскольку Turbo Pascal  не  позволяет  иметь
тип данных размером больше  65531  байт,  Page3  имеет  размер
меньше чем, первые три. Однако, пока выключена проверка диапа-
зонов,  вы можете спокойно ссылаться  на  все  16384  элемента
массива.

     Теперь для перемещения данных,  например,  в третью физи-
ческую страницу (с номером 2), вы должны сделать примерно сле-
дующее:

     MyPageFramePtr := EmsPageFramePtr; { нужно сделать только раз }

     Move(Source,MyPageFramePtr^.Page2[1],16384);

     Заметим, что  данные  типы  в  OPEMS   не   определяются,
поскольку нет гарантии,  что вы захотите рассматривать  данные
страницы как массивы байт.

Пример

     var  MyPageFramePtr : PageFramePtr;
          MyEmsPagePtr : ^EmsPage;
     ...
     MyPageFramePtr := EmsPageFramePtr;
     if not MapEmsPage(MyEmsHandle,0,2) then { ошибка }
     MyEmsPagePtr := @MyPageFramePtr^.Page2[1];

     Это пример того,  как вы можете отобразить  первую  логи-
ческую страницу   (с  номером  0),  связанную  с  дескриптором
MyEmsHandle, на третью физическую страницу (с номером 2) и за-
нести в MyPageFramePtr начальный адрес этой физической страни-
цы.

Смотрите также

     AllocateEmsPages             MapEmsPage

EmsPageAvail
──────────────────────────────────────────────────────────────
Объявление

     function EmsPageAvail : Word;

Функция

     Возвращает число  доступных  страниц,  которое   сообщает
система управления расширенной памятью.

Описание

     Эта функция  позволяет  вам определить,  сколько дополни-
тельной памяти доступно для использования.  EmsPageAvail возв-
ращает число доступных страниц размером 16К (16384 байта), или
в случае ошибки EmsErrorCode. Чаще всего причиной ошибки быва-
ют те же причины,  что и при EmsStatusOk. Чтобы определить об-
щее число страниц в системе, воспользуйтесь EmsTotalPages.

Пример

     PagesToAllocate := EmsPageAvail;
     if (PagesToAllocate = EmsErrorCode) then
        { ошибка }
     else
        MyEmsHandle := AllocateEmsPages(PagesToAllocate);

     В этом примере показано,  как выделить всю доступную  па-
мять.

Смотрите также

     EmsStatusOk                  EmsTotalPages

EmsPagesOwned
──────────────────────────────────────────────────────────────
Объявление

     function EmsPagesOwned(Handle : Word) : Word;

Функция

     Возвращает число   страниц,   связанных   с  дескриптором
Handle.

Описание

     Эта функция позволяет вам определить число страниц,  свя-
занных с указанным дескриптором. В случае успешного завершения
она возвращает значение в диапазоне  1-512  и  EmsErrorCode  в
случае  ошибки.  Чаще  всего  причиной  ошибки бывает неверный
дескриптор.  EmsPagesOwned используется в основном для  вывода
информации о текущем состоянии.

Пример

     var
        Handle, Pages : Word;
        HandleRec : record
                    LowByte,HighByte : Byte;
                    end absolute Handle;
     begin
        Handle := $FF00;
        repeat
           Pages := EmsPagesOwned(Handle);
           if (Pages <> EmsErrorCode) then
              WriteLn('Дескриптор $',HexW(Handle),':',Pages);
           Inc(HandleRec.LowByte);
           Dec(HandleRec.HighByte);
        until (Pages = EmsErrorCode);
     end;

     Эта программа  демонстрирует,  как можно выяснить сколько
страниц связано с каждым дескриптором.  (Не гарантируется, что
она будет работать, смотрите примечания в AllocateEmsPages).

Смотрите также

     AllocateEnsPages

EmsStatusOk
──────────────────────────────────────────────────────────────
Объявление

     function EmsStatusOk : Boolean;

Функция

     Возвращает True, если EMM сообщает, что все в порядке.

Описание

     EmsStatusOk позволяет вам проверить функциональность обо-
рудования дополнительной памяти. Она возвращает True, если EMM
сообщает, что ее статус Ok,  или False, если нет. Чаще всего к
ошибке приводит нарушение кода драйвера  EMM  или  сбой  платы
доплнительной памяти. Заметим, что EmsStatusOk можно использо-
вать только после вызова EmsInstalled,  которая  сообщает  что
EMM загружена.

Пример

     if not EmsInstalled then begin
        WriteLn('Эта программа требует EMS. Завершение...');
        Halt(1);
     end;
     if not EmsStatusOk then begin
        WriteLn('Ошибка оборудования. Завершение...');
        Halt(1);
     end;

     В данном примере для проверки  наличия  EMM  используется
EmsInstalled, а  EmsStatusOk  используется  для проверки того,
что она правильно работает.

Смотрите также

     EmsInstalled

EmsTotalPages
──────────────────────────────────────────────────────────────
Объявление

     function EmsTotalPages : Word;

Функция

     Возвращает общее число страниц,  имеющихся в памяти  EMS,
включая выделенные.

Описание

     Эта функция возвращает число страниц памяти EMS, размером
16К, установленной в системе,  или EmsErrorCode в случае ошиб-
ки. Ошибку  вызывают чаще всего те же причины,  что и в случае
EmsStatusOK.  EmsTotalPages используется для вывода информации
о текущем состоянии.

Пример

     WriteLn(LongInt(EmsTotalPages)*16384,'байт в EMS');

Смотрите также

     EmsPagesAvail

EmsVersion
──────────────────────────────────────────────────────────────
Объявление

     function EmsVersion : Byte;

Функция

     Возвращает номер  версии EMM в двоично-десятичном кодиро-
вании.

Описание

     Эта функция возвращает значение в двоично-десятичном  ко-
де, которое определяет версию драйвера EMM. Версия 3.2, напри-
мер, будет представлена в виде $32. В случае ошибки EmsVersion
возвращает 0,  что обычно говорит о том, что EMM не загружена.
Заметим, что в OPEMS доступны все функции EMS версии 3.0 и вы-
ше, и поэтому EmsVersion требуется редко.

Пример

     if EmsVersion < $32 then begin
        WriteLn('Требуется EMM версии 3.2 и выше. ');
        Halt(1);
     end;

MapEmsPage
──────────────────────────────────────────────────────────────
Объявление

     function MapEmsPage(Handle,LogicalPage : Word;
                         PhysicalPage : Byte) : Boolean;

Функция

     Отображает указанную  логическую  страницу,  связанную  с
дескриптором Handle, на физическую страницу.

Описание

     Эта функция используется для того,  чтобы сделать доступ-
ными данные,  хранящиеся в памяти EMS. (Замечание: Если вы еще
не прочитали описание EmsPageFramePtr, мы рекомендуем вам сде-
лать это теперь, поскольку там определяются термины, использу-
емые в данном описании.)  Что  значит  отображение  логической
страницы, определяемой параметрами Handle и LogicalPage на од-
ну из  четырех  физических  страниц,  определяемую  параметром
PhysicalPage, в   страничном  блоке  EMM.  Это  позволяет  вам
рассматривать память EMS как нормальную память.

     Параметр Handle - это значение,  которое возвращает вызов
функции AllocateEmsPages. LogicalPage - это число от 0 до n-1,
где n - это число страниц,  связанных с указанным дескриптором
функцией AllocateEmsPages. PhysicalPage - это число от 0 до 3,
которое определяет номер физической страницы.

     MapEmsPage возвращает True при успешном завершении и  при
ошибке  возвращает False.  Чаще всего причиной ошибки являются
неверный дескриптор или номер страницы.

Пример

     type EmsPage = array[1..16384] of Byte;
          EmsPageFrame = record
              Page0,Page1,Page2 : EmsPage;
              Page3 : array[1..16369] of Byte;
          end;
          PageFramePtr = ^EmsPageFrame;
     var MyPageFramePtr : PageFramePtr;
         MyEmsPagePtr : ^EmsPage;
     ...
        MyPageFramePtr := EmsPageFramePtr;
        if not MapEmsPage(MyEmsHandle,0,2) then { ошибка }
        MyEmsPagePtr := @MyPageFramePtr^.Page2[1];

     Это пример  того,  как  вы можете отобразить первую логи-
ческую страницу  (с  номером  0),  связанную  с   дескриптором
MyEmsHandle, на третью физическую страницу (с номером 2) и за-
нести в MyPageFramePtr начальный адрес этой физической страни-
цы.

Смотрите также

     AllocateEmsPages             EmsPageFramePtr

RestoreEmsContext
──────────────────────────────────────────────────────────────
Объявление

     function RestoreEmsContext(Handle : Word) : Boolean;

Функция

     Восстанавливает контекст  отображения  драйвера  EMM  для
указанного дескриптора.

Описание

     Эта функция  предназначена для использования в "всплываю-
щих" процедурах,  которые  используют  память  EMS.  Вместе  с
SaveEmsContext она  позволяет вам сохранить контекст отображе-
ния EMM при входе в процедуру и восстановить его при выходе из
"всплывающей" процедуры,  т.о.  чтобы  не  повлиять  на работу
прерванной программы.  Дескриптор, посылаемый в качестве пара-
метра, должен быть тем же,  что был использован в предшествую-
щем  вызове  SaveEmsContext.  При успешном восстановлении кон-
текста отображения RestoreEmsContext возвращает значение True.

Пример

     {$F+}
     procedure MyPopup;
     begin
        if not SaveEmsContext(MyEmsHandle) then Exit;
        { ... тело процедуры ... }
        if not RestoreEmsContext(MyEmsHandle) then
          { вывод предупреждения }
     end;

     Данный пример иллюстрирует использование в  "всплывающей"
процедуре функции RestoreEmsContext. При входе в "всплывающую"
процедуру необходимо сохранить контекст и восстановить его при
выходе.

SaveEmsContext
──────────────────────────────────────────────────────────────
Объявление

     function SaveEmsContext(Handle : Word) : Boolean;

Функция

     Сохраняет контекст EMM для резидентной программы.

Описание

     Эта функция  предназначена для использования в "всплываю-
щих" процедурах,  которые  используют  память  EMS.  Вместе  с
RestoreEmsContext она позволяет вам сохранить контекст отобра-
жения  EMM при входе в процедуру и восстановить его при выходе
из "всплывающей" процедуры,  т.о.  чтобы не повлиять на работу
прерванной программы.  Дескриптор, посылаемый в качестве пара-
метра, должен быть тем же, что был получен при выделении памя-
ти  AllocateEmsPages.  При  успешном завершении SaveEmsContext
возвращает значение True.

Пример

     MyEmsHandle := AllocateEmsPages(PagesToAllocate);
     { проверка на EmsErrorCode }
     ...

     {$F+}
     procedure MyPopup;
     begin
        if not SaveEmsContext(MyEmsHandle) then Exit;
        { ... тело процедуры ... }
        if not RestoreEmsContext(MyEmsHandle) then
          { вывод предупреждения }
     end;

     Данный пример иллюстрирует использование в  "всплывающей"
процедуре функции SaveEmsContext.  При входе  в  "всплывающую"
процедуру необходимо сохранить контекст и восстановить его при
выходе. MyEmsHandle - это дескриптор,  связанный с  программой
при вызове AllocateEmsPages.

Смотрите также

     AllocateEmsPages


         C. OPEXTMEM: Управление расширенной памятью.

     В данном разделе описываются типы, переменные, константы,
процедуры и функции,  которые находятся в  интерфейсной  части
юниты OPEXTMEM.

                            Типы.

     HugePtr = Pointer;

     HugePtr содержит  24-разрядный  линейный адрес.  Он может
быть приведен к LongInt (и наоборот) для использования  в  ка-
честве индекса, и вы можете сравнивать его с nil так же, как и
обычный сегментный адрес.

ExtMemAvail
──────────────────────────────────────────────────────────────
Объявление

     function ExtMemAvail : Word;

Функция

     Возвращает объем свободной расширенной памяти в  килобай-
тах.

Описание

     Точно так  же,  как  и  функция  Turbo  Pascal  MemAvail,
ExtMemAvail позволяет  определить  объем  расширенной  памяти,
доступный вашей программе.  Однако число, возвращаемое функци-
ей,  определяет объем памяти в килобайтах (1024),  поскольку в
этих   единицах   производится   выделение   памяти   функцией
GetExtMem.  Функция возвращает 0, если используется DOS версий
не 3.х или 4.х,  даже в том случае,  если в машине установлена
расширенная память.

Пример

     if ExtMemAvail >= KBtoAllocate then
        MyHugePtr := GetExtMem(KBtoAllcate)
     else  begin
        WriteLn('Не хватает расширенной памяти');
        MyHugePtr = nil;
     end;

     В данном примере ExtMemAvail используется для того, чтобы
определить: достаточно ли памяти для удовлетворения запроса.

Смотрите также

      GetExtMem

ExtMemTotal
──────────────────────────────────────────────────────────────
Объявление

     function ExtMemTotal : LongInt;

Функция

     Возвращает объем  установленной в системе расширенной па-
мяти в байтах.

Описание

     В отличии от ExtMemAvail,  которая возвращает объем в ки-
лобайтах, ExtMemTotal возвращает объем установленной расширен-
ной памяти в байтах.  Она используется в основном  для  вывода
информации о состоянии.  Функция возвращает 0,  если использу-
ется не DOS 3.x или  4.x,  даже  если  в  системе  установлена
расширенная память.

Пример

     WriteLn(LongInt(ExtMemAvail)*1024,
       'байт расширенной памяти доступны из общего объема',
       ExtMemTotal);

FreeExtMem
──────────────────────────────────────────────────────────────
Объявление

     function FreeExtMem(P : HugePtr) : Boolean;

Функция

     Освобождает блок расширенной памяти.

Описание

     FreeExtMem освобождает блок расширенной памяти,  выделен-
ный функцией GetExtMem.  Она работает, только если освобождае-
мый блок был выделен последним. Функция возвращает False, если
она не может освободить блок памяти. Заметим, что при заверше-
нии программы не нужно вызывать FreeExtMem, поскольку OPEXTMEM
автоматически освободит всю выделенную вами память.

Пример

     MyHugePtr := GetExtMem(KBtoAllocate);
     ...
     if not FreeExtMem(MyHugePtr) then begin
        WriteLn('Не могу освободить память');
        Exit;
     end;

     GetExtMem вызывается для выделения памяти и она  освобож-
дается при помощи FreeExtMem.

GetExtMem
──────────────────────────────────────────────────────────────
Объявление

     function GetExtMem(N : Word) : HugePtr;

Функция

     Выделяет N килобайт расширенной памяти.

Описание

     Как и  GetMem,  GetExtMem  позволяет  вам  выделить  блок
расширенной памяти,  однако  она выделяет память в килобайтах.
Поскольку функция возвращает nil в случае, если для удовлетво-
рения запроса не хватает памяти,  то не обязательно  перед  ее
использованием вызывать ExtMemAvail. Выделенный GetExtMem блок
расширенной памяти  может  быть  затем  освобожден  с  помощью
FreeExtMem.

Пример

     MyHugePtr := GetExtMem(KBtoAllocate);
     if MyHugePtr = nil then begin
        WriteLn('Не могу выделить память');
        Exit;
     end;

Смотрите также

     ExtMemAvail

MarkExtMem
──────────────────────────────────────────────────────────────
Объявление

     procedure MarkExtMem(var P : HugePtr);

Функция

     Сохраняет местоположение следующего блока расширенной па-
мяти в P.

Описание

     Как и Mark,  MarkExtMem позволяет вам сохранить положение
cледующего свободного блока в переменной.  Вы затем можете вы-
делить несколько блоков расширенной памяти с помощью GetExtMem
и освободить их все с помощью одного вызова  ReleaseExtMem.  В
отличие       от      Mark/Release      и      GetMem/FreeMem,
MarkExtMem/ReliaseExtMem        не        конфликтуют        c
GetExtMem/FreeGetMem. Если нет доступной расширенной памяти, P
получит значение nil.

Пример

     MarkExtMem(ExtMemStart);
     HP1 := GetExtMem(KBtoAllocate);
     HP2 := GetExtMem(KBtoAllocate);
     ...
     MemoryReleased := ReleaseExtMem(ExtMemStart);

     MarkExtMem вызывается перед выделением нескольких  блоков
расширенной памяти, и ReleaseExtMem вызывается для их освобож-
дения, когда они больше не нужны.

Смотрите также

     GetExtMem                    ReleaseExtMem

MoveExtMem
──────────────────────────────────────────────────────────────
Объявление

     procedure MoveExtMem(Src,Dest : HugePtr; WCount : Word);

Функция

     Перемещает WCount слов расширенной памяти из Srt в Dest.

Описание

     Как и Move,  MoveExtMem позволяет переместить блок памяти
между двумя точками. Вы можете использовать ее для перемещения
данных из расширенной памяти в нормальную и наоборот,  или для
переноса данных в  расширенной  памяти.  В  отличие  от  Move,
MoveExtMem не позволяет переносить данные по байтам, это нужно
помнить при использовании OPEXTMEM.

     Замечание: При использовании Move с обычными указателями,
вы должны раскрыть их:

     Move(PointA^,PointB^,BytesToMove);

     При использовании MoveExtMem с параметрами HugePtr вы не
должны раскрывать их (^).  При передаче данных  из  нормальной
памяти или  в нормальную память адрес в нормальной памяти дол-
жен быть приведен к виду HugePtr с помощью  PtrToHuge.  Напри-
мер:

     MoveExtMem(PtrToHuge(@MyArray[1]),MyHugePtr,512);

     перемещает 512 слов (1024  байт)  из  массива  MyArray  в
расширенную память по адресу MyHugePtr.

Пример

     MoveExtMem(PtrToHuge(MyByfferPtr),MyHugePtr,WordsToMove);

     Правильно. Переместит  WordsToMove слов из нормальной па-
мяти с адреса  MyByfferPtr  в  расширенную  память  по  адресу
MyHugePtr.

     MoveExtMem(PtrToHuge(MyByfferPtr)^,MyHugePtr,WordsToMove);

     Неверно. Указатели типа HugePtr не должны раскрываться.

Смотрите также

     PtrToHuge

PtrToHuge
──────────────────────────────────────────────────────────────
Объявление

     function PtrToHuge(P : Pointer) : HugePtr;

Функция

     Преобразует указатель в тип HugePtr.

Описание

     PtrToHuge преобразует обычный указатель, состоящий из ад-
реса сегмента  и смещения,  в линейный указатель.  Кроме всего
прочего,  PtrToHuge используется  для  перемещения  данных  из
обычной памяти в расширенную и наоборот.  Заметим,  что указа-
тель, передаваемый PtrToHuge в качестве параметра,  должен ле-
жать в диапазоне от $0:$0 до $FFFF:$000F.

Пример

     MoveExtMem(PtrToHuge(MyByfferPtr),MyHugePtr,WordsToMove);

ReleaseExtMem
──────────────────────────────────────────────────────────────
Объявление

     procedure ReleaseExtMem(P : HugePtr);

Функция

     Освобождает всю расширенную память, лежащую выше P.

Описание

     Аналогично Release,  ReleaseExtMem позволяет вам  освобо-
дить всю память,  лежащую выше  данного  указателя.  Указатель
хранится в переменной типа HugePtr и получает значение при вы-
зове MarkExtMem.  Вы можете  т.о.  выделить  несколько  блоков
расширенной  памяти  с помощью GetExtMem и освободить их все с
помощью одного вызова ReleaseExtMem. В отличие от Mark/Release
и  GetMem/FreeMem,  MarkExtMem/ReliaseExtMem  не конфликтуют c
GetExtMem/FreeGetMem. Заметим, что вам не нужно при завершении
программы  вызывать ReleaseExtMem,  поскольку OPEXTMEM сделает
это автоматически.

     Очень важно: Параметр P должен быть получен вызовом толь-
ко MarkExtMem, но не GetExtMem.

Пример

     MarkExtMem(ExtMemStart);
     HP1 := GetExtMem(KBtoAllocate);
     HP2 := GetExtMem(KBtoAllocate);
     ...
     MemoryReleased := ReleaseExtMem(ExtMemStart);

     MarkExtMem вызывается перед выделением нескольких  блоков
расширенной памяти, и ReleaseExtMem вызывается для их освобож-
дения, когда они больше не нужны.

Смотрите также

     MarkExtMem

                      13. Макрокоманды.

                          А. Обзор.

     Термин макрокоманда  широко  используется в различных об-
ластях. Многие программы, например, электронные таблицы, вклю-
чают макроязык, который позволяет вам настраивать ее на выпол-
нение определенных задач.  Аналогично,  многие  компиляторы  и
ассемблеры позволяют связывать с символическим именем последо-
вательность команд.  Встраиваемые процедуры Turbo Pascal могут
рассматриваться  как макрокоманды с этой точки зрения.  Однако
чаще всего этот термин относят к макрокомандам клавиатуры, ко-
торые позволяют вам нажатием на одну клавишу выполнить работу,
которая  требует  нажатия  многих.  Большинство   коммерческих
текстовых  редакторов  и  текстовых процессоров включают такую
возможность,  и теперь Object Proffessional предоставляет  вам
возможность включить это мощное средство в ваши программы.

     Юнита OPMACRO  содержит  все подпрограммы низкого уровня,
которые для этого нужны. Они позволяют вам определять макроко-
манды, присваивать им имена,  записывать их, выполнять, сохра-
нять в файле для дальнейшего использования и считывать,  когда
они понадобятся.

     После определения, макрокоманда может быть выполнена дву-
мя способами.  Если обработка  макрокоманд  включена  (вызовом
MacrosOn), то  макрокоманда  будет автоматически выполнена при
каждом нажатии соответствующей клавиши.  Вы можете  также  за-
пустить макрокоманду      подпрограммами      StartMacro     и
StartMacroByKey. В  обоих  случаях  макрокоманда   выполняется
скрытым процессором макрокоманд из OPMACRO.

     Необходимо не  забывать одно важное ограничение.  OPMACRO
не поддерживает вложенные макрокоманды.  Например,  если  одна
макрокоманда, скажем A, связана с клавишей <F1>, а вторая, на-
зовем ее B,  связана с клавишей <F2>, и макрокоманда A соддер-
жит <F2>,  то макрокоманда B не будет выполнена как часть мак-
рокоманды A.  Для этого ограничения  существуют  две  основные
причины. Первая,  этим  исключается  вероятность  бесконечного
цикла, когда, например, макрокоманда A присутствует в макроко-
манде B,  а макрокоманда B в A.  Вторая состоит в том, что это
позволяет переопределить клавиатуру с помощью OPMACRO,  напри-
мер, поменяв местами функции, выполняемые <F1> и <F3>. (Однако
вы можете организовывать цепочки макрокоманд, используя ловуш-
ку SetEndOfMacroProc).

     Макрокоманды Object  Proffessional  сохраняются в записях
переменной длины  типа  MacroRec.  Первое  поле  этой   записи
NumKeys - это слово, определяющее число клавиш в данной макро-
команде. Второе поле - KeyArray, это массив слов, младший байт
которых содержит код символа, а старший - скан-код, т.е. имеет
тот же формат, что используется BIOS. Конец массива отмечается
словом, содержащим  значение  EndOfMacro($FFFF,  или  -1).  Вы
должны помнить об этом формате также,  как и о  формате  строк
Turbo  Pascal,  где первый символ содержит длину,  и о формате
ASCII,  где строка оканчивается нулевым символом (#0).  Каждая
макрокоманда связана  с  клавишей типа <F1> и с необязательным
именем типа 'Help'. По умолчанию вы ограничены 100 макрокоман-
дами   (MaxMacros),   каждая   длиной  не  более  1000  клавиш
(MaxKeyInMacro),  но поскольку Object Proffessional  поставля-
ется с исходными кодами, в любой момент можете изменить данные
ограничения.

     Хотя возможность записывать и выполнять  макрокоманды  во
многих  случаях достаточна,  однако иногда возникает необходи-
мость редактировать уже  определенную  макрокоманду.  По  этой
причине Object Proffessional содержит зависимую юниту, которая
поддерживает полный редактор макрокоманд.  Этот  специализиро-
ванный редактор позволяет вам просто вставлять,  удалять и ре-
дактировать клавиши в данной макрокоманде, которая представля-
ется  в  качестве строки из одной или более символов.  Клавиша
<Esc> будет  отображаться  строкой  "<Esc>",   а   <Enter>   -
"<Enter>", так что вам не нужно ничего знать о кодах клавиш.

     В качестве завершенного примера использования макрокоманд
Object Proffessional  и  редактора  макрокоманд  смотрите  де-
монстрационную программу  SMACS.PAS.  SMACS  - это резидентный
процессор макрокоманд,  который  включает  многие  возможности
коммерческих программ типа SuperKey. Она поставляется с файлом
макрокоманд, TURBO5.MAC которые вам помогут при  использовании
редактора Turbo Pascal.

     И последняя юнита в этой группе,  OPREPLY, реализует под-
множество возможностей OPMACRO. OPREPLAY выполняет только одно
- предварительно записанные макрокоманды.  Она не позволяет за-
писывать макрокоманды или присваивать им имена, она только вы-
полняет  макрокоманды  при  нажатии пользователем определенных
клавиш.  Он менее мощный, чем OPMACRO, однако в некоторых слу-
чаях OPREPLAY лучший и возможно единственный выбор.  Например,
если вы пишете резидентную программу,  которая должна посылать
длинные  последовательности  клавиш,  лежащей  ниже прикладной
программе, то вы можете использовать OPMACRO, однако вы умень-
шите размер программы и данных,  если воспользуетесь OPREPLAY.
Однако более важно,  если ваша программа использует OPSWAP, то
у вас просто не будет другого выхода,  поскольку программа об-
работки прерывания $16  OPMACRO  зависит  от  данных,  которые
располагаются в сегменте данных и в "куче".  OPREPLAY содержит
все данные  в  собственном  кодовом  сегменте,  и  может  быть
использована в   прикладных  задачах,  где  OPMACRO  не  может
использоваться, например, в POPHELP.



             B. OPMACRO: Макрокоманды клавиатуры.

     В данном   разделе   описываются  все  типы,  переменные,
константы, процедуры и функции,  которые расположены в  интер-
фейсной части юниты OPMACRO.

                          Константы.

     EndOfMacro = $FFFF;

     Используется для маркировки конца макрокоманды. Использу-
ется также для маркировки неиспользуемых элементов  в  массиве
DefineKeys.

     Int16Handle = 12;

     Дескриптор программы обработки 16 прерывания для OPINT.

     MacroFileID : LongInt = $04001087;

     Идентификационные значения файла макрокоманд.  Это значе-
ние записывается в начало каждого файла макрокоманд.

     MaxKeiInMacro = 1000;

     Максимальное число клавиш в макрокоманде.  Если вы хотите
увеличить это число,  то помните, что MacroRec содержит массив
array[1..MaxKeyInMacro] of Word (смотрите ниже),  и  что  и  в
OPMACRO, и  в  OPMACED  объявляются глобальные переменные типа
MacroRec.  Иными словами,  абсолютным  ограничителем  является
значение примерно 32000 или 16000,  если используется OPMACED.
Практически используется намного меньше.

     MaxMacros = 100;

     Максимальное число макрокоманд,  которые может  обрабаты-
вать OPMACRO одновременно.

     PlayBackDelay : Word = 0;

     Длительность задержки в миллисекундах,  которая использу-
ется при выполнении каждой клавиши в макрокоманде.

                            Типы.

     MacroRec = record
            NumKeys : Word;
            KeyArray : array[1..MaxKeyInMacro] of Word;
            Overflow : Word;
     end;

     NumKeys - число клавиш в макрокоманде,  не считая послед-
нюю, которая всегда EndOfMacro ($FFFF). KeyArray - массив кла-
виш. Overflow содержит маркер конца  макрокоманды,  когда  она
полностью заполнена.

     MacroRecPtr = ^MacroRec;

     Указатель на запись MacroRec.

     StringPointer = ^String;

     Указатель на строку.

                         Переменные.

     DefineKeys : array[1..MaxMacros] of Word;

     Таблица определенных клавиш макрокоманд.  Не используемые
елементы содержат значение EndOfMacro.

     MacroInProgress : Boolean;

     Если равна True, то в настоящий момент выполняется макро-
команда.

     MacroNames : array[1..MaxMacros] of Pointer;

     Массив указателей на имена макрокоманд.

     MacroPointers : array[1..MacMacros] of Pointer;

     Массив указателей на определенные макрокоманды.

     MacroRecording : Boolean;

     Если True, то разрешена запись макрокоманд.

     MacrosAreOn : Boolean;

     Если True, то разрешено выполнение макрокоманд.

     ScrapMacro : MacroRec;

     Используется процессором  макрокоманд для записи макроко-
манды.

     ScrapMacroKey : Word;

     Может использоваться для хранения  клавиши,  связанной  с
ScrapMacro.

     ScrapMacroName : string;

     Может использоваться  для  хранения  имени,  связанного с
ScrapMacro.

AllocateMacro
──────────────────────────────────────────────────────────────
Объявление

     function AllocateMacro(Key : Word; var Macro;
                            var Name : string) : Byte;

Функция

     Выделяет место под макрокоманду в "куче".

Описание

     Эта подпрограмма определяет и выделяет место под макроко-
манду и под ее имя.  Если с данной клавишей уже связана макро-
команда, то  старая макрокоманда и ее имя удаляется,  а память
занимаемая ею, освобождается. AllocateMacro возвращает одно из
следующих значений:

     0 - Макрокоманда выделена.
     1 - Таблица макрокоманд полна.
     2 - Не хватает памяти.
     3 - Макрокоманда пуста.

     Заметим, что возвращаемое значение 3  не  рассматривается
как код ошибки.

Пример

     var
        TempMacroKey : Word;
        TempMacro : MacroRec;
     const
        NullString : string[1] = '';
     begin
        { получить TempMacro и TempMacroKey }
        case AllocateMacro(TempMacroKey,TempMacro,NullString) of
           { 0, 3 - все в порядке, 1 и 2 - ошибки }
           1 : WriteLn('Таблица заполнена');
           2 : WriteLn('Нет места');
           else WriteLn('Не хватает памяти');
        end;
     end;

Смотрите также

     DeallocateMacro              DefineMacro

AssignMacroName
──────────────────────────────────────────────────────────────
Объявление

     function AssignMacroName(Key : Word;
                              var Name : string) : Boolean;

Функция

     Связывает имя с макрокомандой.

Описание

     Эта функция позволяет вам изменить или присвоить имя мак-
рокоманды. Она удаляет присвоенное  данной  макрокоманде  имя,
если оно есть,  и возвращает False,  если для нового имени нет
места или если не найдена макрокоманда,  связанная с  клавишей
Key.

Пример

     var Name : string;
     begin
        Write('Введите имя макрокоманды:');
        ReadLn(Name);
        if not AssignMacroName(ScrapMacroKey,Name) then
           WriteLn('Не хватает памяти');
     end;

     Присваивает новое имя макрокоманде,  связанной с клавишей
ScarpMacroKey.

CharToMacro
──────────────────────────────────────────────────────────────
Объявление

     function CharToMacro(MacroChar : Char) : Word;

Функция

     Преобразует символ в представление в виде кода  клавиату-
ры/кода символа.

Описание

     Эта функция  позволяет  вам  преобразовать символы в коде
ASCII в коды клавиш, которые вставляются в макрокоманду. Если
необходимо преобразовать целую строку, используейте
StringToMacro.

Пример

     CharToMacro('A');

     Возвращает $1E41.

     CharToMacro(^M);

     Возвращает $1C0D.

Смотрите также

     KeyToString                  StringToMacro

ClearMacros
──────────────────────────────────────────────────────────────
Объявление

     procedure ClearMacros;

Функция

     Очищает текущую макрокоманду.

Описание

     ClearMacros необратимо удаляет макрокоманду и освобождает
память, занимаемую ею и ее именем.

Смотрите также

     DefineMacro

DeallocateMacro
──────────────────────────────────────────────────────────────
Объявление

     function DeallocateMacro(Key : Word) : Boolean;

Функция

     Если такая  макрокоманда  существует,  то  данная функция
очищает и освобождает занимаемую ею память.

Описание

     Эта процедура противоположна AllocateMacro. Если Key свя-
зана с макрокомандой, она удаляет макрокоманду и соответствую-
щее ей   имя   (если   есть),   и   освобождает   ее   память.
DeallocateMacro возвращает False,  если нет макрокоманды, свя-
занной с Key.

Пример

     if not DeallocateMacro(ScrapMacroKey) then { ошибка }

     Удаляет любую макрокоманду, связанную с ScrapMacroKey.

Смотрите также

     AllocateMacro                DefineMacro

DefineMacro
──────────────────────────────────────────────────────────────
Объявление

     function DefineMacro(Key : Word; var Macro) : Boolean;

Функция

     Определяет новую макрокоманду или удаляет существующую.

Описание

     Эта низкоуровневая функция позволяет  выполнить  основные
функции AllocateMacro/DeallocateMacro без автоматического вы-
деления/освобождения памяти. Она предназначена в основном для
внутреннего использования.

     Для определения макрокоманды: Key - это клавиша, связан-
ная с макрокомандой. DefineMacro возвращает False, если табли-
ца уже заполнена, или если макрокоманда пустая.

     Для удаления макрокоманды: Key - это клавиша, а Macro
должно быть пустой макрокомандой (NumKey = 0). DefineMacro
вернет значение False, если такая макрокоманда не найдена.

     В качестве     примеров    смотрите    AllocateMacro    и
DeallocateMacro в OPMACRO.PAS.

Смотрите также

     AllocateMacro                DeallocateMacro

FindMacroIndex
──────────────────────────────────────────────────────────────
Объявление

     function FindMacroIndex(Key : Word) : Word;

Функция

     Возвращает индекс в массиве макрокоманды, связанной с
Key.

Описание

     Эта процедура возвращает индекс в массиве макрокоманды,
связанной с Key, или 0, если такая макрокоманда не найдена.
Этот индекс может в свою очередь использоваться для доступа к
элементам массивов MacroPointers, MacroNames и DefineKeys. Она
предназначена в основном для внутреннего использования, однако
вы можете ее использовать в подпрограммах, которые не могут
быть написаны с помощью процедур высокого уровня из OPMACRO.
Вы можете ее использовать также в качестве более быстрой аль-
тернативы MacroAddress для определения того, что данная клави-
ша уже связана с макрокомандой. SMACS делает это в нескольких
местах.

Пример

     Index := FindMacroIndex(MacrtoKey);
     if Index <> 0 then WriteLn('Имя:',MacroNames[Index]^);

Смотрите также

     MacroAddress

InitMacros
──────────────────────────────────────────────────────────────
Объявление

     function InitMacros : Boolean;

Функция

     Инициализирует процессор макрокоманд.

Описание

     InitMacros активизирует  процессор макрокоманд.  Возможно
вы захотите отключить его (используя RemoveMacros) перед вызо-
вом командного процессора DOS,  а затем снова активизировать с
помощью InitMacros. После вызова InitMacros нет определенных
макрокоманд и отключено выполнение и запись макрокоманд.
InitMacros возвращает False, если не может захватить INT $16.
Это может произойти, если ваша программа использует дескриптор
программы обработки прерывания, используемый процессором мак-
рокоманд (Int16Handle). Вам не нужно в начале программы вызы-
вать InitMacros, поскольку это делается автоматически.

Пример

     RemoveMacros;
     Code := ExecDos('',True,NoExecDosProc);
     if not InitMacros then { ошибка }

Смотрите также

     RemoveMacros

KeyToString
──────────────────────────────────────────────────────────────
Объявление

     procedure KeyToString(Key: Word; var S : string;
                           var Special : Boolean);

Функция

     Возвращает строку (S), которая представляет Key.

Описание

     Эта процедура  может использоваться,  когда вы хотите вы-
вести список определенных макрокоманд.  Special  равно  False,
если возвращаются простые символы (типа 'A'), и True, если бу-
дут представлены символы с расширенным скан-кодом (типа <F1>).

Пример

     var I,Key : Word;
         S : string; Special : Boolean;
     begin
        for I := 1 to MaxMacros do begin
           Key := DefinedKeys[I];
           if Key <> EndOfMacro then begin
              KeyToString(Key,S,Special); WriteLn(S);
           end;
        end;
     end;

     Выводит список  всех  клавиш  и связанных с ними макроко-
манд.

Смотрите также

     CharToMacro

MacroAdress
──────────────────────────────────────────────────────────────
Объявление

     function MacroAdress(Key : Word) : Pointer;

Функция

     Возвращает указатель на макрокоманду,  связанную с данной
клавишей, или nil, если такая макрокоманда не определена.

Описание

     Эта подпрограмма позволяет вам определить, связана ли с
указанной клавишей макрокоманда или нет. Вы можете использо-
вать ее перед StartMacroByKey, или для того, чтобы определить,
нужно ли запрашивать у пользователя подтверждение тому, что он
хочет переписать существующую макрокоманду.

Пример

     var SavedKey : Word;
     begin
     Write('Нажмите клавишу макрокоманды,  которая должна быть
            позднее выполнена:');
        MacrosOff;
        SavedKey := ReadKeyWord;
        MacrosOn;
        WriteLn;
        if MacroAdress(SavedKey) = nil then begin
           WriteLn('макрокоманда не определена'); Exit;
        end;
        ...
        StartMacrosByKey(SavedKey);
     end;

Смотрите также

     StartMacrosByKey

MacroCount
──────────────────────────────────────────────────────────────
Объявление

     function MacroCount : Word;

Функция

     Возвращает количество определенных макрокоманд.

Описание

     Результатом функции    является    число    от    0    до
MaxMacros(100).

Пример

     WriteLn(MacroCount,' макрокоманд определено');

MacroRecordingOff
──────────────────────────────────────────────────────────────
Объявление

     procedure MacroRecordingOff;

Функция

     Выключает запись макрокоманды.

Описание

     Вызов данной  процедуры просто сообщает процессору макро-
команд,  что необходимо прекратить запись клавиш в ScrapMacro.
На вашей совести остается выделение для нее места и присвоение
ей клавиши (чаще всего с помощью AllocateMacro).

Пример

     В качестве примера смотрите  процедуру  PopupRecordingOff
из SNACS.PAS.

Смотрите также

     AllocateMacro                MacroRecordingOn

MacroRecordingOn
──────────────────────────────────────────────────────────────
Объявление

     procedure MacroRecordingOn;

Функция

     Включает запись макрокоманды.

Описание

     Вызов данной процедуры просто сообщает процессору макроко-
манд, что необходимо начать запись клавиш, которые будет нажи-
мать пользователь,  в ScrapMacro. Клавиши будут сохраняться до
тех пор, пока не будет вызвана MacroRecordingOff.

Пример

     В качестве примера смотрите процедуру PopupRecordingOт из
SNACS.PAS.

Смотрите также

     MacroRecordingOff

MacrosOff
──────────────────────────────────────────────────────────────
Объявление

     procedure MacrosOff;

Функция

     Выключает обработку макрокоманд.

Описание

     Эта процедура  отключает  обработку  макрокоманд.  SMACS,
например, вызывает эту функцию перед запросом  у  пользователя
клавиши макрокоманды, которую нужно отредактировать. После то-
го, как пользователь  нажмет  клавишу,  обработка  макрокоманд
включается функцией MacrosOn.

Пример

     MacrosOff;
     W := ReadKeyWord;
     MacrosOn;

     Выключает обработку   макрокоманд,  считывает  клавишу  и
включает обработку макрокоманд.

Смотрите также

     MacrosOn

MacrosOn
──────────────────────────────────────────────────────────────
Объявление

     procedure MacrosOn;

Функция

     Включает обработку макрокоманд.

Описание

     Эта процедура включает обработку макрокоманд. Хотя обычно
вы просто вызываете эту функцию в начале программы, однако бы-
вают случаи, когда необходимо временно отменить обработку мак-
рокоманд. SMACS, например, отключает обработку макрокоманд пе-
ред запросом у пользователя клавиши макрокоманды, которую нуж-
но отредактировать. После того, как пользователь нажмет клави-
шу, обработка макрокоманд включается.

Пример

     MacrosOff;
     W := ReadKeyWord;
     MacrosOn;

     Выключает обработку   макрокоманд,  считывает  клавишу  и
включает обработку макрокоманд.

Смотрите также

     MacrosOn

ReadMacroFile
──────────────────────────────────────────────────────────────
Объявление

     function ReadMacroFile(FName : string;
                            Merge : Boolean) : Byte;

Функция

     Считывает файл макрокоманд.

Описание

     Эта подпрограмма считывает содержимое файла макрокоманд в
память. Если  Merge  равно False,  перед считыванием удаляются
все существующие макрокоманды.  Если равно True,  существующие
макрокоманды, которые не конфликтуют с новыми, остаются в па-
мяти. В случае успешного завершения ReadMacroFile возвращает
0, если это недопустимый файл макрокоманд, то $FF, если не
хватает памяти, то $FE, иначе IoResult.

Пример

     if ReadMacroFile('MYMACROS.1',False) <> 0 then { ошибка }

     Существующие макрокоманды перекрываются.

     if ReadMacroFile('MYMACROS.2',True) <> 0 then { ошибка }

     Существующие макрокоманды не перекрываются.

Смотрите также

     WriteMacroFile

RemoveMacros
──────────────────────────────────────────────────────────────
Объявление

     procedure RemoveMacros;

Функция

     Восстанавливает все вектора, связанные с макрокомандами.

Описание

     Эта процедура отключает процессор макрокоманд.  Вам может
понадобиться это, например, перед запуском командного про-
цессора DOS. Процессор макрокоманд может быть активизирован с
помощью InitMacros. Пример

     RemoveMacros;
     Code := ExecDos('',True,NoExecDosProc);
     if not InitMacros then { ошибка }

Смотрите также

     InitMacros                   StartMacro

SetEndOfMacroProc
──────────────────────────────────────────────────────────────
Объявление

     procedure SetEndOfMacroProc(P : Pointer);

Функция

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

Описание

     SetEndOfMacroProc предоставляет  вам программную ловушку,
которая позволяет зацеплять макрокоманды. P это адрес процеду-
ры, которая  вызывается  сразу  же после завершения выполнения
макрокоманды. При вызове данная подпрограмма может запустить
вторую макрокоманду (с помощью StartMacro или
StartMacroByKey), отключить саму себя с помощью
SetEndOfMacroProc или ничего не делать.

     При использовании данной ловушки необходимо помнить
несколько важных вещей. Первое, процедура должна быть откомпи-
лирована под FAR моделью и не должна быть вложена в другую
процедуру. Второе, поскольку она вызывается из программы обра-
ботки прерывания OPMACRO, она должна использовать очень ма-
ленький объем в стеке. Третье, она не должна вызывать процеду-
ры, которые могут вызвать возникновение проблем, связанных с
реентерантностью (повторным вхождением), например, не должна
считывать с клавиатуры и не должна использовать подпрограмм,
которые производят чтение с клавиатуры. Однако, она может об-
ращаться к глобальным переменным, поскольку программа обработ-
ки прерывания OPMACRO гарантирует правильную установку регист-
ра DS перед ее вызовом.

Пример

     var
        OurMacros : array[1..3] of MacroRecPtr;
        CurrentMacro : Byte;

     {$F+}
     procedure OurEndOfMacroProc;
     begin
        { уменьшить счетчик }
        Dec(CurrentMacro);
        { есть еще макрокоманды? }
        if CurrentMacro = 0 then
           { отключить ловушку }
           SetEndOfMacroProc(nil);
        else
           { запустить следующую макрокоманду }
           StartMacros(OurMacros[CurrentMacro]);
       end;
       {$F-}

     begin
     { занести  в OurMacro указатели на 3 макрокоманды  в об-
        ратном порядке }
        SetEndOfMacroProc(@OurEndOfMacroProc);
        { запустить макрокоманду 3 }
        CurrentMacro := 3;
        StartMacro(OurMacros[CurrentMacro]);
     end.

     Здесь происходит выполнение трех макрокоманд подряд.

Смотрите также

     StartMacro                   StartMacroByKey

StartMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StartMacro(Macro : Pointer);

Функция

     Запускает выполнение указанной макрокоманды.

Описание

     Эта подпрограмма  позволяет  вам запустить любую макроко-
манду, даже если она не была определена (с помощью DefineMacro
или AllocateMacro).  Если в данный момент выполнялась макроко-
манда, то она будет сразу же замена указанной.

Пример

     var  MyMacroRec : MacroRec;
          MyMacroPtr : MacroRecPtr;
     ...
     MyMacroPtr := @MyMacroRec;
     StartMacro(MyMacroPtr);

     Правильно.

     StartMacro(@MyMacroRec);

     Тоже правильно.

StartMacroByKey
──────────────────────────────────────────────────────────────
Объявление

     procedure StartMacroByKey(Key : Word);

Функция

     Запускает выполнение макрокоманды, связанной с Key.

Описание

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

Пример

     const F1Key = $3800;
     ...
     StartMacroByKey(F1Key);

     Выполняет макрокоманду, связанную с клавишей F1, если та-
кая есть.

StringToMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StringToMacro(S : string; MRP : MacroRecPtr;
                             MaxKeys : Word);

Функция

     Инициализирует MRP^ для строки.

Описание

     Эта процедура  преобразует  строку  в  макрокоманду.  MRP
должна указывать на структуру макрокоманды,  в которой она те-
перь будет  храниться.  MaxKeys  определяет максимальное число
клавиш, которое может содержать MRP^.

Пример

     S := 'Это тест на StringToMacro^M;
     StringToMacro(S,@ScrapMacro,MaxKeyInMacro);

     Преобразует строку в макрокоманду и сохраняет ее в
ScrapMacro.

Смотрите также

     CharToMacro                  StringToScrapMacro

StringToScrapMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StringToScrapMacro(S : string);

Функция

     Инициализирует строкой ScrapMacro.

Описание

     Эта процедура формирует  оболочку  вокруг  StringToMacro.
Она преобразует  S  в макрокоманду и помещает ее в ScrapMacro.
Заметим, что процедура не может использоваться во время выпол-
нения макрокоманды, поскольку ScrapMacro используется для хра-
нения выполняемой макрокоманды.

Пример

     S := 'Это тест на StringToMacro^M;
     StringToMacro(S);

     Преобразует строку в макрокоманду и сохраняет ее в
ScrapMacro.

Смотрите также

     StringToMacro

WriteMacroFile
──────────────────────────────────────────────────────────────
Объявление

     function WriteMacroFile(FName : string) : Byte;

Функция

     Записывает файл  макрокоманд.  При  успешном   завершении
возвращщает 0, при ошибке IoResult.

Описание

     Эта процедура  используется для сохранения текущих макро-
команд в файле. В случае ошибки она возвращает IoResult, или 0
в противном случае.

Пример

     if WriteMacroFile('MYMACROS.3') <> 0 then { ошибка }
Смотрите также



              C. OPMACED: Редактор макрокоманд.

     В данном   разделе   описываются  все  типы,  переменные,
константы, процедуры и  функции,  приведенные  в  интерфейсной
части юниты OPMACED.

                          Константы.

     MacEdCmd : Word;

     Последняя команда, введенная пользователем в EditKeys.

     MacEdCommands : CommandProcessor;

     Процессор команд, используемый EditKeys. Заметим, что
данный командный процессор поддерживает те же ловушки, мышь,
контектсную стправочную систему, что описаны в OPCMD.

     MacEdKeyID : string[12] = 'opmaced keys';

     Идентифицирующая строка,   используемая   инсталлящионной
программой. Находится прямо перед MacEdKeySet.

     MacEdKeyMax = 70;

     Последний доступный слот в MacEdKeySet.

     MacEdKeySet : array[0..MacEdKeyMax] of  Byte = {...};

     Команды, используемые по умолчанием  редактором  макроко-
манд.

     NonMacroKey = $FFFF;

     Если это значение посылается EditKeys в качестве парамет-
ра Key, то Key не транслируется в строку, а отображается.

                         Переменные.

     TempMacro : MacroRec;

     Временная макрокоманда,  используемая для редактирования.
Поскольку она  используется  только при редактировании,  то вы
можете рассматривать ее как  ScrapMacro,  как  это  сделано  в
SMACS.PAS.

EditKeys
──────────────────────────────────────────────────────────────
Объявление

     function EditKeys(Key : Word; var Macro : MacroRec;
                       MinCol, MinRow, MaxCol, MaxRow, Dim,
                       Bright : Byte;
                       var Modifaed : Boolean) : Boolean;

Функция

     Редактирует макрокоманду, связанную с Key.

Описание

     EditKeys реализует полный редактор макрокоманд.  Окно ре-
дактирования определяется параметрами MinCol,  MinRow, MaxCol,
MaxRow. Окно должно быть шириной по крайней мере в 40 символов
и в высоту иметь 5 строк,  если нужно, можно больше. Поскольку
в окне осуществляется вертикальная прокрутка,  то вы не должны
заботиться о том, что макрокоманда не помещается в окне.

     Параметры Dim и Bright определяют атрибуты,  используемые
для отображения рамки окна (Bright),  и  клавиш  макрокоманды.
Обычные клавиши  отображаются  с  использованием  атрибутов из
Dim, клавиши,  которые должны  быть  представлены  строками  -
<Esc>, <Enter>, <F1., и т.д. выводятся с использованием Bright.

     Заметим, что   окно  используемое  для  редактирования  в
OPMACED, не является окном в смысле OPWINDOW. Содержимое экра-
на под окном не сохраняется, и оно не имеет строк прокрутки и
других аксессуаров, которые используются в стековых окнах. Ко-
нечно, EditKeys можно использовать внутри такого окна, чтобы
получить его удобства.

     Key - это клавиша, связанная с макрокомандой, и обычно
выводится в верхнем левом углу окна. Если вы не хотите, чтобы
оно отображалось, передайте в качестве Key значение
NonMacroKey.

     Макрокоманда - переменная типа MacroRec - в действитель-
ности никогда не изменяется EditKeys. EditKeys делает ее ко-
пию, в которой и производится редактирование, и возвращает
указатель на эту копию. Если не было произведено никаких изме-
нений макрокоманды, то параметр Modifaed получает значение
False, иначе True.

     Редактор макрокоманд  поддерживает  следующие команды ре-
дактирования:

     <Enter>, <ClickLeft>
     Завершение редактирования.

     <Esc>, <ClickRight>
     Завершение редактирования и отмена изменений.

     <Left>
     Курсор на одну клавишу влево.

     <Right>
     Курсор на одну клавишу вправо.

     <Up>
     Курсор вверх на одну строку.

     <Down>
     Курсор на одну строку вниз.

     <Ins>
     Включает/выключает режим вставки.

     <Del>
     Удалить клавишу под курсором.

     <BkSp>
     Удалить предшествующую клавишу.

     <CtrlBksp>
     Удалить все клавиши в макрокоманде.

     <ScrollLock>
     Переключение между  режимами литерным и командным.  В ли-
терном режиме нажатие всех вышеперечисленных клавиш приведет к
их вставке в макрокоманду, а не к выполнению связанных с ними
команд.

     <F1>, <ClickBoth>
     Помощь. Вызывает  процедуру выдачи справочной информации,
связанную с MacEdCommansds, если такая есть.

Пример

     const
        NullString : String[1] = '';
     var
        P,MyMacroPtr : MacroPtr;
        Modifaed : Boolean;
     begin
        MacrosOff;
        Write('Нажмите клавишу макрокоманды:');
        ScrapMacroKey := ReadKeyWord;
        MacrosOn;

        { поиск этой макрокоманды }
        P := MacroAdress(ScrapMacroKey);
        if P = nil then begin
           { не найдена, создать пустую для редактирования }
           ScrapMacro.NumKeys := 0;
           ScrapMacro.KeyArray[1] := EndOfMacro;
           P := @ScrapMacro;
        end;

        { редактирование макрокоманды }
        MyMacroPtr := EditKeys(ScrapMacroKey, P^,
                      1,1,ScreenWidht,ScreenHeight,$07,$0F,
                      Modifaed);
        ClrScr;

        { если была изменена, то занести }
        if Modifaed then
           case AllocateMacro(ScrapMacroKey,MyMacroPtr^,
                              NullString) of
              1..2 : WriteLn('Не хватает памяти');
           end;
     end;

     Этот пример демонстрирует использование окна редактирова-
ния макрокоманд во весь экран. Другой пример вы найдете в про-
цедуре EditMacro в SMACS.PAS.



             D. OPREPLAY: Выполнение макрокоманд.

     В данном   разделе   описываются  все  типы,  переменные,
константы, процедуры и функции,  которые расположены в  интер-
фейсной части юниты OPREPLAY.

                          Константы.

     EndOfMacro = $FFFF;

     Используется для маркировки конца макрокоманды.

     MaxKeiInMacro = 1000;

     Максимальное число  клавиш в макрокоманде.  Вы можете его
изменить.

                            Типы.

     MacroRec = record
            NumKeys : Word;
            KeyArray : array[1..MaxKeyInMacro] of Word;
            Overflow : Word;
     end;

     NumKeys - число клавиш в макрокоманде,  не считая послед-
ней, которая всегда EndOfMacro ($FFFF). KeyArray - массив кла-
виш. Overflow содержит маркер конца  макрокоманды,  когда  она
полностью заполнена.

     MacroRecPtr = ^MacroRec;

     Указатель на запись MacroRec.

     ScrapMacroPtr : MacroRecPtr = nil;

     Если была вызвана InitScrapMacroPtr,  то переменная будет
указывать на вырезанную макрокоманду, которая хранится в кодо-
вом сегменте OPREPLAY. Это дает вам удобное место для хранения
маленьких макрокоманд.      За      исключением      процедуры
StringToScrapMacro, OPREPLAY  никогда больше не использует ее.
Максимальный размер  вырезанной  макрокоманды   содержится   в
ScrapMacroSize.

     ScrapMacroSize : Word = 0;

     Максимальное число  клавиш  в ScrapMacroPtr^.  Если вы не
изменяли OPSCRAP.ASM,  то после вызова  InitScrapMacroPtr  оно
получит значение 127.

                         Переменные.

     CurrentMacroPtr : ^Pointer;

     Указатель на адрес текущей макрокоманды.

     MacroInProgressPtr : ^Boolean;

     Указатель на переменную типа Boolean, которая определяет,
выполняется ли в данный момент макрокоманда.

CharToMacro
──────────────────────────────────────────────────────────────
Объявление

     function CharToMacro(MacroChar : Char) : Word;

Функция

     Преобразует символ в представление в виде кода  клавиату-
ры/кода символа.

Описание

     Эта функция  позволяет  вам  преобразовать символы в коде
ASCII в коды клавиш,  которые вставляются в макрокоманду. Если
необходимо преобразовать целую строку, используейте
StringToMacro.

Пример

     CharToMacro('A');

     Возвращает $1E41.

     CharToMacro(^M);

     Возвращает $1C0D.

Смотрите также

     CharToMacro(OPMACRO)         StringToScrapMacro
     StringToMacro

InitScrapMacroPtr
──────────────────────────────────────────────────────────────
Объявление

     procedure InitScrapMacroPtr;

Функция

     Инициализирует ScrapMacroPtr.

Описание

     Эта процедура инициализирует ScrapMacroPtr т.о., чтобы он
указывал на  макрокоманду,  объявленную  в  кодовом   сегменте
OPREPLAY, и которая может хранить до 127 клавиш,  кроме этого,
InitScrapMacroPtr присваивает  ScrapMacroSize  значение   127.
Если вы не вызовете данную процедуру,  то вам придется инициа-
лизировать эти две переменные вручную.

Пример

     Смотрите пример в StringToMacro.

Int16
──────────────────────────────────────────────────────────────
Объявление

     procedure Int16;

Функция

     Это процессор макрокоманд,  который обрабатывает  нажатия
клавиш.

Описание

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


Пример

     uses
        Dos, OpReplay;
     const
        SaveInt16 : Pointer = nil;
     var
        SaveExitProc : Pointer;

     {$F+}
     procedure OurExitProc;
     begin
        ExitProc := SaveExitProc;
        if SaveInt16 <> nil then
           SetIntVec($16,SaveInt16);
     end;
     {$F-}

     begin
        SaveExitProc := ExitProc;
        ExitProc := @OurExitProc;
        GetIntVec($16,SaveInt16);
        SetIntVec($16,@Int16);
        ...
        SetIntVec($16,SaveInt16);
     end;

     Активизирует в  начале программы программу обработки пре-
рываний OPREPLAY и устанавливает программу выхода, которая де-
активизирует Int16 при выходе.

SetEndOfMacroProc
──────────────────────────────────────────────────────────────
Объявление

     procedure SetEndOfMacroProc(P : Pointer);

Функция

     Устанавливает указатель на процедуру, которая будет вызы-
ваться после завершения выполнения макрокоманды.

Описание

     SetEndOfMacroProc предоставляет  вам программную ловушку,
которая позволяет зацеплять макрокоманды. P - это адрес проце-
дуры, которая вызывается сразу же после завершения выполнения
макрокоманды. При вызове данная подпрограмма может запустить
вторую макрокоманду (с помощью StartMacro или
StartMacroByKey), отключить саму себя с помощью
SetEndOfMacroProc или ничего не делать.

     При использовании данной ловушки необходимо помнить
несколько важных вещей. Во-первых, процедура должна быть от-
компилирована под FAR моделью и не должна быть вложена в дру-
гую процедуру. Во-вторых, поскольку она вызывается из програм-
мы обработки прерывания OPREPLAY, она должна использовать
очень маленький объем в стеке. В-третьих, она не должна вызы-
вать процедуры, которые могут вызвать возникновение проблем,
связанных с реентерантностью (повторным вхождением), например,
не должна считывать с клавиатуры и не должна использовать
подпрограмм, которые производят чтение с клавиатуры. Однако
она может обращаться к глобальным переменным, поскольку прог-
рамма обработки прерывания OPREPLAY гарантирует правильную
установку регистра DS перед ее вызовом.

     Самое важное:  если OPREPLAY используется в подкачиваемых
резидентных программах,  то вы должны быть уверены,  что уста-
навливаемая процедура находится в кодовом сегменте и постоянно
резидентна, и  что  она не обращается к переменным из сегмента
данных.

Пример

     Смотрите SetEndOfMacroProc в OPMACRO.

StartMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StartMacro(Macro : MacroRecPtr);

Функция

     Запускает выполнение указанной макрокоманды.

Описание

     Эта подпрограмма позволяет вам запустить  созданную  вами
макрокоманду, передавая указатель на нее. Если в данный момент
выполнялась макрокоманда, то она будет сразу же заменена ука-
занной.

Пример

     InitScrapMacroPtr;
     StringToScrapMacro('Это тест на StartMacro'^M);
     StartMacro(ScrapMacroPtr);
     ReadLn(S);

     Преобразует строку  в  макрокоманду,   сохраняет   ее   в
ScrapMacroPtr^ и затем считывает ее в S.

StringToMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StringToMacro(S : string; MRP : MacroRecPtr;
                             MaxKeys : Word);

Функция

     Инициализирует MRP^ для строки.

Описание

     Эта процедура  преобразует  строку  в  макрокоманду.  MRP
должна указывать на структуру макрокоманды,  в которой она те-
перь будет  храниться.  MaxKeys  определяет максимальное число
клавиш, которое может содержать MRP^.

Пример

     InitScrapMacroPtr;
     S := 'Это тест на StringToMacro^M;
     StringToMacro(S,@ScrapMacro,MaxKeyInMacro);

     Преобразует строку в макрокоманду и сохраняет ее в
ScrapMacro.

Смотрите также

     CharToMacro                  InitScrapMacroPtr

StringToScrapMacro
──────────────────────────────────────────────────────────────
Объявление

     procedure StringToScrapMacro(S : string);

Функция

     Инициализирует строкой ScrapMacroPtr^.

Описание

     Эта процедура формирует  оболочку  вокруг  StringToMacro.
Она преобразует  S  в  макрокоманду  и  помещает  по  адресу в
ScrapMacroPtr.

     Заметим, что ScrapMacroPtr должна быть инициализирована
или с помощью InitScrapMacroPtr, или для указания на собствен-
ную ScrapMacro до вызова процедуры.

Пример

     InitScrapMacroPtr;
     S := 'Это тест на StringToMacro^M;
     StringToScrapMacro(S);

     Преобразует строку в макрокоманду и сохраняет ее в
ScrapMacroPtr^.

Смотрите также

     InitScrapMacroPtr


                     E. Примеры программ.

     Имеются две программы, иллюстрирующие использование юнит,
описанных в данной главе.  SMACS,  описание которой приводится
ниже, демонстрирует использование OPMACRO и OPMACED.  POPHELP,
описанная в главе 1, демонстрирует использование OPREPLAY.

                SMACS: Процессор макрокоманд.

     SMACS это резидентный процессор макрокоманд,  очень похо-
жий на SyperKey фирмы Borland. Для загрузки SMACS наберите:

     SMACS [MacroFile]

     в командной строке DOS,  где MacroFile это необязательный
параметр, определяющий имя файла,  содержащего уже  записанные
макрокоманды. SMACS  поставляется  с  примером  такого  файла,
TURBO5.MAC, который вы можете использовать при работе с редак-
тором Turbo Pascal.

     После загрузки SMACS вы можете активизировать его простым
нажатием <Alt><->. Когда вы это сделаете, вы увидите примерно
следующее:

 ┌────────────────── SUPER MACS: Macro Processor 1.00 ─────────────┐
 │Edit Delete Read Write List Status Configure Unload cApture Print│
 └─────────────────────────────────────────────────────────────────┘

     В основном меню доступны следующие команды:

                            Edit.

     Отредактировать существующую макрокоманду или создать но-
вую. Когда вы выберете эту команду,  SMACS попросит вас нажать
клавишу, соответствующую данной макрокоманде, и затем имя (не-
обязательное). В редакторе макрокоманд вы можете перемещаться
по клавишам с помощью клавиш управления курсором. По умолчанию
редактор макрокоманд находится в режиме вставки, поэтому после
позиционирования курсора вы можете вставлять новые клавиши
просто их нажатием. Клавиша <Ins> включает и выключает режим
вставки. <Del> и <Bksp> удаляют клавиши. Если вам нужно вста-
вить в макрокоманду клавиши, которые имеют в редакторе специ-
альное значение - <Esc>, <Enter>, <Ins>, <Del>, клавиши управ-
ления курсором, и т.п., нажмите <ScrollLock> для активизации
режима <Literal>, затем нажмите клавишу (клавиши). Для возвра-
та в режим Command нажмите <ScrollLock> опять. Для завершения
сеанса редактирования вы можете нажать <Enter> и тогда сделан-
ные вами изменения будут сохранены, или <Esc>, и тогда измене-
ния сохранены не будут. Описание редактора макрокоманд вы най-
дете в разделе, посвященном юните OPMACED.

                           Delete.

     Удаляет все или одну макрокоманду. В начале SMACS спросит
вас, не хотите ли вы удалить все макрокоманды. Если вы ответи-
те <Y>, то она запросит подтверждения вашего намерения. Если
вы нажмете <N> или <Enter>, то она попросит вас нажать клави-
ши, соответствующие макрокоманде, которую вы хотите удалить.
Вы можете нажать соответствующую клавишу или <Ctrl@> для отме-
ны операции.

                            Read.

     Считывает в память файл макрокоманд.  Если уже есть опре-
деленные макрокоманды, то SMACS спросит вас, хотите ли вы что-
бы она удалила уже определенные макрокоманды до того,  как бу-
дут считаны новые.  Заметим, что вы можете загрузить файл мак-
рокоманд прямо из командной строки DOS. Например:

     cd \turbo
     smacs turbo5.mac
     turbo

     Загружает файл макрокоманд TURBO5.MAC и удаляет  все  су-
ществующие макрокоманды без запроса подтверждения.

                            Write.

     Сохраняет определенные  в настоящий момент макрокоманды в
файле макрокоманд. Если файл уже существует, то SMACS запросит
у вас подтверждение, нужно ли его перезаписывать.

                            List.

     Выводит прокручиваемый  список  определенных  в настоящий
момент макрокоманд.  Клавиши <Up> и <Dowm> позволяют прокручи-
вать список,  если все определенные макрокоманды не помещаются
на экране. <Home> и <End> прокручивают на начало и конец
списка соответственно, а <Esc> возвращает в основное меню.

                           Status.

     Выводит число  определенных  макрокоманд  и объем памяти,
который остался под новые.

                          Configure.

     Выводит меню,  которое позволит вам изменить конфигурацию
SMACS:

     Main menu.
     Изменить "горячие" клавиши,  которые активизирую основное
меню.

     Begin macro.
     Изменить "горячие" клавиши, используемые для включения
записи макрокоманды.

     End macro.
     Изменить "горячие" клавиши, используемые для выключения
записи макрокоманды.

     Screen Reader.
     Изменить "горячие" клавиши, используемые для включения
процедуры записи экрана.

     Macro memory.
     Изменить объем памяти, используемый для макрокоманд.

     Playback delay.
     Определяет задержку,  которая используется при выполнении
макрокоманд. Если задержка не равна 0, то SMACS ожидает данное
время перед возвратом клавиши из макрокоманды. Эта задержка
часто необходима, чтобы предотвратить потерю данных. По умол-
чанию задержка равна 0, максимальное значение равно 100.

     Macro playback.
     Включает и выключает обработку макрокоманд.

     Remap keyboard.
     Если данная опция включена, то вы можете присвоить макро-
командам клавиши типа <F11> или <AltUP>, чего в обычном состо-
янии сделать нельзя.  Список новых клавиш, которые поддержива-
ются данной опцией, вы найдете в описании юниты OPENHKBD.

     Save configuration
     Сохраняет текущую  конфигурацию.  SMACS.EXE  должен нахо-
дится в текущей директории, на диске и в директории, из кото-
рой был загружен SMACS (если вы используете DOS 3.0 и выше),
или директория должна быть в PATH.

     С помощью клавиш <Up> и <Down> выберите нужный элемент  и
нажмите <Enter>. Первые четыре позволяют вам определить "горя-
чие" клавиши SMACS. В некоторых ситуациях имеются некоторые
ограничения на эти клавиши, однако вы можете экспериментиро-
вать с ними как угодно. За исключением размера памяти, все из-
менения конфигурации вступают в действие немедленно. Для выбо-
ра размера памяти подразумевается, что вы сохраните конфигура-
цию с тем, чтобы при следующем запуске она будет действовать.

                           Unload.

     Позволяет вам во многих случаях выгрузить SMACS из памяти
без перезагрузки системы.  SMACS не может выгрузить себя, если
другая программа,  загруженная  после него,  захватила вектора
прерываний, используемые SMACS,  поэтому обычно, если SMACS не
последняя загруженная программа, то вы не можете ее выгрузить.
Кроме этого,  вы можете выгрузить SMACS  из  командной  строки
DOS:

     SMACS -U

                           cApture.

     Позволяет вам захватить содержимое всего экрана под  меню
SMACS и сохранить его в файле.

                            Print.

     Посылает файл на печать.  Если не загружен PRINT.COM, или
если вы работаете под DOS 2.x, выводится сообщение об ошибке.

                  Другие "горячие" клавиши.

     Кроме команд,  доступных в основном меню, имеются еще три
команды, которые доступны через "горячие"  клавиши  (приведены
во втором столбце).

     Запись макрокоманды          <Alt><=>
     Включает запись макрокоманды.  У вас будет запрошена кла-
виша, связанная с данной макрокомандой. Если такая макрокоман-
да уже существует, SMACS спросит, нужно ли ее перезаписать.
Также, если вы определяете клавишу типа <+> или <A>, которые
используются при обычном наборе текстов, то SMACS запросит
подтверждение.

     Конец записи                 <Alt><->
     Выключает запись макрокоманды. У вас будет запрошено имя.
Если вы не хотите присваивать имя, просто нажмите <Enter>.

     Чтение экрана                <Alt><Space>
     Активизирует програму чтения экрана. Программа чтения эк-
рана позволяет  вам  сохранить часть экрана до 1000 символов и
записать его  в  макрокоманду.  С  помощью  клавиш  управления
курсором переместите курсор на начало блока и нажмите <Enter>,
затем переместите курсор на конец блока и нажмите <Enter>  еще
раз. При перемещении курсора блок будет подсвечиваться для
указания текущей выбранной последовательности. После того, как
блок будет выбран, SMACS спросит у вас клавишу, которая должна
быть связана с макрокомандой. Для отмены операции перед тем,
как блок будет выделен, нажмите <Esc>.

     Заметим, что  одновременно  доступна только одна команда,
активизируемая через "горячие" клавиши. И вы не можете, напри-
мер, запустить чтение экрана из основного меню.

                        14. Остальные.
                          A. Обзор.

     В данной главе содержится описание юнит, которые не попа-
дают ни в одну из основных  категорий.  OPBCD  содержит  набор
процедур, используемых  для  выполнения вычислений с плавающей
точкой высокой точности.  OPERRHAN предоставляет  вам  возмож-
ность восстановления  после  появления ошибки времени выполне-
ния. OPINLINE содержит набор встраиваемых макрокоманд, и набор
процедур для вычислений указателей. И OPSORT предоставляет вам
быструю нерекурсивную сортировку, которая работает с любыми
типами данных.



          B. OPBCD: Вычисления с высокой точностью.

     Иногда возникает  необходимость в вычислениях с плавающей
точкой высокой точности. Примерами таких вычислений могут слу-
жить финансовые расчеты, когда суммы в миллионы долларов долж-
ны быть представлены с точностью до цента, или таблицы аморти-
зации, которые  должны содержать по крайней мере 10 цифр на 30
лет.

     Для представления таких чисел не хватает типа шестибайто-
вого числа с плавающей точкой, который встроен в Turbo Pascal.
Возникают две проблемы: 1) 6 байт не хватает для представления
достаточной точности; и 2) поскольку числа хранятся в двоичном
формате, то при преобразовании чисел из и в десятичный формат
могут возникнуть ошибки округления. Хотя типы данных, обраба-
тываемые сопроцессором 8087, поддерживают до 19 значащих цифр,
но они используют двоичных формат, что приводит к ошибкам ок-
ругления.

     Turbo Pascal версии 3.0  предоставлял  для  решения  этой
проблемы специальную версию компилятора. Этот компилятор опре-
делял тип чисел с плавающей точкой  как 10 байтовое  число  в
двоично-десятичном кодировании, которые могли содержать до 18
значащих цифр и имели диапазон представления 1E-63 до 1E+63. В
дальнейшем компиляторы Turbo Pascal не поддерживали арифметику
в двоично-десятичном кодировании, однако Object Professional
поддерживает ее.

     Юнита OPBCD содержит расширенный набор процедур для рабо-
ты с двоично-десятичными числами.  Число в  двоично-десятичном
кодировании представляется как массив байт из 10 элементов с
внутренним форматом, аналогичным Turbo Pascal версии 3.0. Кро-
ме полного набора арифметических функций, функций сравнения и
преобразования, OPBCD предоставляет вам смешанный набор
трансцендентных функций: Sqrt, Exp, Ln, Sin, Cos и ArcTan.
Кроме этого, OPBCD содержит функцию Form для простого формати-
рования числовых результатов.

     За исключением  функции  Form,  все  функции  написаны на
ассемблере для увеличения скорости работы и уменьшения разме-
ра. Если не используются трансцендентные функции, то OPBCD до-
бавляет к программе около 3К. Если же используются какие-либо
трансцендентные функции, то добавляется еще 3 Кбайта.

     Все нетрансцендентные функции поддерживают во всех опера-
циях точность до 18  значащих  цифр,  трансцендентные  функции
поддерживают точность по крайней мере 17 значащих цифр.

     Поскольку вычисления над числами в двоично-десятичном ко-
дировании не являются инфиксными операциями, и поскольку функ-
ции Pascal  не могут возвращать данные сложных типов (например
массивы), то процесс вычислений с использованием чисел в  дво-
ично-десятичном кодировании более сложен. Все процедуры OPBCD,
вычисляющие результат в виде чисел с плавающей точкой в двоич-
но десятичном кодировании, возвращают их в виде параметра var.
Смотрите следующий раздел для ознакомления с синтаксисом вызо-
ва процедур.

     Обработка ошибок в OPBCD осуществляется стандартным обра-
зом. При появлении ошибки,  независимо от того какая она - де-
ление на ноль,  переполнение или неверная операция типа взятие
квадратного корня от отрицательного  числа,  OPBCD  генерирует
прерывание 0 (деление на ноль). По умолчанию системная прог-
рамма обработки ошибок Turbo Pascal ловит это прерывание, вы-
дает сообщение "Divade by zero" и прекращает выполнение прог-
раммы. Адрес ошибки, который сообщает Turbo Pascal, может ле-
жать где-нибудь внутри OPBCD, что затрудняет определение при-
чины ошибки. Вы можете использовать юниту OPERRHAN, при этом
все ошибки OPBCD будут восстанавливаемыми. Проверяя ExitCode
после восстановления ошибки, вы сможете определить причину ее
возникновения.

     В качестве  примера  использования юниты OPBCD посмотрите
исходные тексты юниты OPCALC.  DESCPOP использует  OPCALC  для
реализации программистского калькулятора, который может встав-
лять результаты вычислений в файл,  загруженный в окно тексто-
вого редактора. Эти значения могут быть в форме обычного числа
('123.456') или в форме типизированных констант,  которые под-
ходят для  представления  чисел в двоично-десятичном кодирова-
нии: '($42,$00,$00,$00,$00,$00,$00,$56,$34,$12)'   (=123.456).
OPCALC демонстрирует удобную технику обработки ошибок, сообща-
емых OPBCD.

     Хочется выразить  благодарность  Филипу  Бернсу   (Philip
R.Burns) за алгоритмы,  использованные в трансцендентных функ-
циях.

                          Константы.

     BCDsize = 10;

     Определяет число байт,  требуемых для  хранения  чисел  в
двоично-десятичном кодировании.  10 используется для совмести-
мости с Turbo Pascal 3.0.  Изменив это значение в константе  в
OPBCDLOW.ASM, можно  получить числа в двоично-десятичном коди-
ровании большей точности.  (важное замечание:  Значение  может
быть увеличено, но не уменьшено, и оно должно быть четным. Для
перекомпиляции OPBCD.ASM и BCDTRANS.ASM  вам  потребуется  или
Turbo Assembler   фирмы  Borland  или  Macro  Assembler  фирмы
Microsoft). Десять байт поддерживают числа с точностью  до  18
значащих цифр и каждый дополнительный байт увеличивает точ-
ность на две цифры. Трансцендентные функции будут поддерживать
только 18 значащих цифр, поскольку при увеличении их числа па-
дает скорость вычислений и растет размер кода.

     CommaForPeriod : Boolean = False;

     Если равна True,  функция Forma будет возвращать '.'  для
',' и наоборот. Это позволяет просто писать программы, которые
могут использоваться в Англии и в странах,  где на месте деся-
тичной точки пишется запятая.

     MaxBCD : BCD = ($7F,$00,$00,$00,$00,$00,$00,$00,$00,$99);
                        { +9.9e+63 }

     Максимальное значение двоично-десятичного числа.

     MinBCD : BCD = ($FF,$00,$00,$00,$00,$00,$00,$00,$00,$99);
                        { -9.9e-63 }

     Минимальное значение двоично-десятичного числа.

     MoneySign : Char = '$';

     Этот символ  используется для отображения чисел в формате
доллар-цент. Если нужно, вы можете изменить его на #, чтобы
Form могла выводить суммы в английских фунтах.

     PiBcd : BCD = ($40,$24,$93,$97,$58,$53,$26,$59,$41,$31);

     Определяет число  пи  в двоично-десятичном формате с точ-
ностью 18 цифр.

     ZeroBcd : BCD = ($0,$0,$0,$0,$0,$0,$0,$0,$0,$0);

     Ноль в формате двоично-десятичного числа.

                            Типы.

     BCD = array[1..BCDSize] of Bytes;

     Внутренний формат чисел в двоично-десятичном кодировании.
Детальное описание формата двоично-десятичных чисел вы найдете
в файле OPBCD.ASM.

AbsBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure AbsBCD(B1:BCD, var B2 : BCD);

Функция

     Возвращает в B2 абсолютное значение B1.

Описание

     Это очень быстрая операция,  которая требует только обну-
ление одного бита  и передачи 10 байт в выходное значение.

Пример

     { предположим в B1 содержится -1.2345 }
     AbsBCD(B1,B2);

     B2 получит значение 1.2345.

AddBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure AddBCD(B1,B2 : BCD; var B3 : BCD);

Функция

     Прибавляет к B1 значение B2 и помещает результат в B3.

Описание

     AddBCD создает временный результат с точностью 19 знаков,
затем округляет его до 18 знаков.

     Если результат  превышает  значение  1.0E64  генерируется
ошибка по переполнению.

Пример

     { предположим в B1 содержится 0.999999999999999999 }
     AddBCD(B1,B1,B2);

     B2 будет   после   выполнения   операции  содержать  2.0,
поскольку внутренний результат был округлен.

ArcTanBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure ArcTanBCD(B1: BCD; var B2 : BCD);

Функция

     Возвращает в B2 арктангенс от B1.

Описание

     Как и при работе с обычными числами ArcTanBCD  возвращает
угол в радианах, чей тангенс содержится в B1. ArcTanBCD всегда
возвращает значение в диапазоне между  -Pi/2  и  +Pi/2.  Любое
значение, которое  попадает  в  диапазон представления чисел в
двоично-десятичном кодировании, может быть входным.

Пример

     { предположим B1 содержит 1.0 }
     ArcTanBCD(B1,B2);
     { предположим, что B3 содержит 4.0 }
     MultBCD(B2,B3,B4);

     В B4 будет занесено значение 3ю14159265358979323, которое
равно числу Pi с точностью до последнего знака.

BCDtoReal
──────────────────────────────────────────────────────────────
Объявление

     function BCDtoReal(B:BCD):Real;

Функция

     Преобразует число из двоично-десятичной формы в тип Real.

Описание

     Эта функция преобразует число  из  двоично-десятичного  в
6 байтовое число с плавающей точкой не в форме 8087. Мы подра-
зумеваем, что вы не используете 8087 при работе с OPBCD.

     Эта процедура вначале преобразует число из  двоично-деся-
тичного в строку символов в коде ASCII, а затем с помощью про-
цедуры Val из юниты SYSTEM преобразует строку в число с плава-
ющей точкой.  18 значащих цифр округляются до 11, представимых
в Turbo Pascal.

Смотрите также

     LongIntToBCD                 RealToBCD

CosBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure CosBCD(B1:BCD; var B2 : BCD);

Функция

     Возвращает в B2 косинус B1.

Описание

     Как и обычная функция Turbo Pascal Cos,  CosBCD  получает
угол в радианах и возвращает косинус в параметре B2. B1 должен
лежать в диапазоне от 3.14E9 до -3.14E9 радиан. Выходное зна-
чение всегда лежит в диапазоне от -1.0 до +1.0.

     CosBCD вычисляет  значение с точностью до трех цифр на 18
позиции. Результат вычислений совпадает с результатом 80287  с
точностью до трех цифр на широком диапазоне входных значений.

Пример

     CosBCD(PiBCD,B1);

     В B1 будет занесено значение -0.999999999999999997 (долж-
но быть -1.0).

DivBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure DivBCD(B1,B2 :BCD; var B3 : BCD);

Функция

     Делит B1 на B2 и возвращает результат в B3.

Описание

     При делении используется алгоритм, аналогичный "вычесть и
сдвинуть", который  изучается  в  школе.  Точность 18 значащих
цифр.

     Если результат превышает 1.0Е64, возникает ошибка по пе-
реполнению. Если результат меньше -1.0E-63, возвращается 0.

Смотрите также

     MultBCD

EqualBCD
──────────────────────────────────────────────────────────────
Объявление

     function EqualBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 = B2.

Описание

     EqualBCD сравнивает  два  операнда.  Минимальное различие
приведет к тому, что она вернет False.

     Для примерного сравнения вы  должны  определить  функцию,
типа приведенной ниже:

     function ApproxEqual(B1,B2,Epsilon : BCD) : Boolean;
        { возвращает False, если Abs(B1-B2)<Epsilon }
     var
        Difference : BCD;
     begin
        SubBCD(B1,B2,Difference);
        AbsBCD(Difference,Difference);
        ApproxEqual := LessBCD(Difference,Epsilon);
     end;

     Для определения того, что два числа отличаются меньше,
чем на одну, сотую нужно написать следующее:

     RealToBCD(0.001,OneTenthCent);
     if ApproxEqual(B1,B2,OneTenthCent); then
       ...;

Смотрите также

     NotEqualBCD

ExpBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure ExpBCD(B1 : BCD; var B2 : BCD);

Функция

     Возвращает в B2 экспоненту B1.

Описание

     Максимальное допустимое значение B1 равно 147.36. Большие
значения приведут к переполнению.

     Наименьшее значение B1,  которое приведет к получению ре-
зультата, равно -145.06. ExpBCD для меньших значений возвраща-
ет 0.0.

     ExpBCD вычисляет  с точностью до единицы в последнем раз-
ряде. Результат соответствует результату,  полученному  с  по-
мощью сопроцессора 80287, с точностью до трех единиц в 18 раз-
ряде на широком диапазоне входных значений.

Пример

     { предположим, что B1 содержит 1.0 }
     ExpBCD(B1,B2);

     Вернет значение  2.71828182845904524 (e с точностью до 18
знака).

Смотрите также

     LnBcd

Form
──────────────────────────────────────────────────────────────
Объявление

     function Form(Masc : string; B : BCD) : string;

Функция

     Возвращает отформатированную строку со вставленными в нее
цифрами из B.

Описание

     Form предоставляет  вам наиболее важные возможности функ-
ции Form Turbo Pascal 3.0.  Эта функция обеспечивает  дополни-
тельные возможности  форматирования  чисел с плавающей точкой.
Это единственная функция OPBCD, написанная на Pascal так, что
вы можете изменить ее возможности или добавить новые.

     Смотрите описание функции Form в разделе OPSTRING.

Смотрите также

     Form(OPSTRING)               StrExpBCD
     StrBCD

FracBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure FracBCD(B1 : BCD; var B2 : BCD);

Функция

     Возвращает в B2 дробную часть B1.

Описание

     Результат FracBCD аналогичен вычислению
           FracBCD := B1-IntBCD(B1);

Пример

     { подразумеваем, что B1 содержит 1.46 }
     FracBCD(B1,B2);

     Возвратит 0.46.

     { подразумеваем, что B1 содержит -1.46 }
     FracBCD(B1,B2);

     Возвратит -0.46.

GreaterBCD
──────────────────────────────────────────────────────────────
Объявление

     function GreaterBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 > B2.

Описание

     Все функции  сравнения двоично-десятичных чисел разделяют
общую низкоуровневую функцию сравнения,  которая  и  выполняет
само сравнение, и возвращает набор флагов 8086 для результата.
Функции высокого уровня  затем  интерпретируют  результат  для
возврата соответствующего значения типа Boolean.

     Сравнение производится  над  всеми  18  цифрами,  поэтому
1.000000000000000001 больше, чем 1.000000000000000000.

GreaterEqualBCD
──────────────────────────────────────────────────────────────
Объявление

     function GreaterEqualBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 >= B2.

Описание

     Все функции  сравнения двоично-десятичных чисел разделяют
общую низкоуровневую функцию сравнения,  которая  и  выполняет
само сравнение, и возвращает набор флагов 8086 для результата.
Функции высокого уровня  затем  интерпретируют  результат  для
возврата соответствующего значения типа Boolean.

     Сравнение производится  над  всеми  18  цифрами.

IntBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure IntBCD(B1: BCD; var B2 : BCD);

Функция

     Возвращает в B2 целую часть от B1.

Описание

     Если B1 больше или равен нулю,  то IntBCD возвращает наи-
большее целое меньшее или равное B1.  Если B1 меньше нуля,  то
IntBCD возвращает наименьшее целое, большее или равное B1.

     Заметим, что результат в B2 не целое,  а  целая  часть  в
форме числа с плавающей точкой.

Пример

     { предположим B1 содержит 1.46 }
     IntBCD(B1,B2);

     Возвратит 1.0.

     { предположим B1 содержит -1.46 }
     IntBCD(B1,B2);

     Возвратит -1.0.

LessBCD
──────────────────────────────────────────────────────────────
Объявление

     function LessBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 < B2.

Описание

     Все функции  сравнения двоично-десятичных чисел разделяют
общую низкоуровневую функцию сравнения,  которая  и  выполняет
само сравнение, и возвращает набор флагов 8086 для результата.
Функции высокого уровня  затем  интерпретируют  результат  для
возврата соответствующего значения типа Boolean.

     Сравнение производится  над  всеми  18  цифрами.

LessEqualBCD
──────────────────────────────────────────────────────────────
Объявление

     function LessEqualBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 <= B2.

Описание

     Все функции  сравнения двоично-десятичных чисел разделяют
общую низкоуровневую функцию сравнения,  которая  и  выполняет
само сравнение, и возвращает набор флагов 8086 для результата.
Функции высокого уровня  затем  интерпретируют  результат  для
возврата соответствующего значения типа Boolean.

     Сравнение производится  над  всеми  18  цифрами.

LnBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure LnBCD(B1 : BCD; var B2 : BCD);

Функция

     Возвращает в B2 натуральный логарифм B1.

Описание

     Входное значение  для  LnBCD  должно  быть  положительным
числом, иначе будет сгенерирована ошибка.

     LnBCD возращает  результат  с  точностью  до  единицы   в
последнем разряде для всех случаев, где мы нашли гарантирован-
ную точность.  Результат совпадает со  значением,  вычисленным
сопроцессором 80287  с  точностью  до  двух единиц в последнем
разряде на широком диапазоне входных значений.

Пример

     { Предположим B1 содержит 2.0 }
     LnBCD(B1,B2);

     Возвращает 6.93147180559945308E-01 (последняя цифра долж-
на быть 9).

Смотрите также

     ExpBCD

LongIntToBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure LongIntToBCD(L : LongInt; var B : BCD);

Функция

     Преобразует значение типа LongInt в значение типа BCD.

Описание

     Эта процедура предоставляет  метод  преобразования  целых
значений в  значения  типа BCD.  BCD содержит все десять цифр,
которые может содержать значение типа LongInt.

Пример

     LongIntToBCD(0,B1);

     Помещает 0 в B1.

     LongIntToBCD(MaxLongInt,B1);

     Помещает 2147483647.

Смотрите также

     RealToBCD

MultBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure MultBCD(B1,B2 : BCD; var B3 : BCD);

Функция

     Возвращает в B3 результат умножения B1 и B2.

Описание

     При умножении используется алгоритм,  изучаемый  в  школе
"умножить цифры  и  перенести".  Он имеет точность 18 значащих
цифр.

     Если результат превышает 1.0Е64,  то возникает ошибка пе-
реполнения, если результат меньше, чем 1.0E-63, возвращается
ноль.

Смотрите также

     DivBCD

NotEqualBCD
──────────────────────────────────────────────────────────────
Объявление

     function NotEqualBCD(B1,B2 : BCD) : Boolean;

Функция

     Возвращает True, если B1 <> B2.

Описание

     NotEqualBCD возвращает True,  если значения совпадают  по
всем 18  цифрам.  Таким  сравнением  необходимо пользоваться с
осторожностью.

     Для примерного сравнения вы должны определить функцию,
типа приведенной ниже:

     function ApproxEqual(B1,B2,Epsilon : BCD) : Boolean;
        { возвращает False, если Abs(B1-B2)<Epsilon }
     var
        Difference : BCD;
     begin
        SubBCD(B1,B2,Difference);
        AbsBCD(Difference,Difference);
        ApproxEqual := GreaterBCD(Difference,Epsilon);
     end;

Смотрите также

     EqualBCD

RealToBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure RealToBCD(R : Real; var B : BCD);

Функция

     Преобразует число с плавающей точкой в число в форме BCD.

Описание

     Эта процедура   предоставляет   вам  метод  инициализации
чисел в двоично-десятичном кодировании константами с плавающей
точкой. Пока значение константы не превышает значения, которое
может храниться в стандартном 6-байтовом числе с плавающей
точкой, значение BCD будет содержать точное значение констан-
ты.

     Если вам необходима константа,  которая требует  точность
больше 11 значащих цифр,  мы рекомендуем воспользоваться каль-
кулятором из DESKPOP,  который может генерировать типизирован-
ные константы   в  формате  BCD.  Таким  образом  можно  иметь
константы, которые будут иметь точность 18 значащих цифр. Кро-
ме этого, вы можете использовать процедуру ValBCD для преобра-
зования строки в число в формате BCD.

     RealToBCD используется только для преобразования 6-байто-
вых чисел  с  плавающей точкой в формате Turbo Pascal.  Она не
работает с форматом представления  чисел  с  плавающей  точкой
сопроцессора 8087. Мы предполагаем, что вы не будете использо-
вать OPBCD при использовании сопроцессора.

Пример

     RealToBCD(1.5,B1)

     Инициализирует B1 числом 1.5.

     RealToBCD(-1.78234976E-22,B1);

     Инициализирует B1 константой -1.78234976E-22.

Смотрите также

     LongIntToBCD

RoundBCD
──────────────────────────────────────────────────────────────
Объявление

     function RoundBCD(B1 : BCD) : LongInt;

Функция

     Возвращает значение B1 округленной до  ближайшего  целого
числа (длинного целого).

Описание

     Если B1   превышает   MaxLongInt  (2.147.483.647),  тогда
RoundBCD генерирует ошибку  по  переполнению.  Иначе  RoundBCD
возвращает нормальный округленный до LongInt результат.

     Если B1   больше  или  равен  нулю,  RoundBCD  возвращает
TruncBCD(B1+0.5). Иначе он возвращает TruncBCD(B1-0.5).

Примеры

     { Предположим B1 содержит 1.46 }
     RoundBCD(B1);

     Возвратит 1.

     { Предположим B1 содержит 1.50 }
     RoundBCD(B1);

     Возвратит 2.

     { Предположим B1 содержит -1.46 }
     RoundBCD(B1);

     Возвратит -1.

     { Предположим B1 содержит 1.50 }
     RoundBCD(B1);

     Возвратит -2.

Смотрите также

     TruncBCD

SinBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure SinBCD(B1:BCD; var B2 : BCD);

Функция

     Возвращает в B2 синус B1.

Описание

     Как и обычная функция Turbo Pascal Sin,  SinBCD  получает
угол в радианах и возвращает синус в параметре B2. B1 должен
лежать в диапазоне от 3.14E9 до -3.14E9 радиан.

     SinBCD вычисляет значение с точностью до трех  единиц  на
18 позиции. Результат вычислений совпадает с результатом 80287
с точностью до трех единиц в последнем разряде на широком диа-
пазоне входных значений.

Пример

     RealToBCD(4.0,B1);
     Div(PiBCD,B1,B2);  { Вычислить Pi/4 }
     SinBCD(B2,B4);

     Возвратит Sin(Pi/4) = 7ю07106781186547525E-01.

Смотрите также

     CosBCD

SqrBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure SqrBCD(B1 : BCD; var B2 : BCD);

Функция

     Возвращает в B2 возведенное в квадрат значение B1.

Описание

     Эта функция аналогична MultBCD(B1,B1,B2), но работает
быстрее и проще вызывается.

     Если результат превышает 1.0Е64,  генерируется ошибка  по
переполнению, если результат меньше 1.0Е-63, SqrBCD возвращает
ноль.

Смотрите также

     MultBCD

SqrtBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure SqrtBCD(B1 : BCD; var B2 : BCD);

Функция

     Возвращает в B2 корень квадратный от B1.

Описание

     Входное значение должно быть неотрицательным числом, ина-
че возникнет числовая ошибка.

     Алгоритм использует  апроксимацию Херон'a.  Он имеет точ-
ность 18 значащих цифр и требует 4 итерации.

Пример

     { предположим B1 содержит 2.0 }
     SqrtBCD(B1,B2);

     Вернет 1.41421356237309505,  с  точностью  до 18 значащих
цифр.

StrBCD
──────────────────────────────────────────────────────────────
Объявление

     function StrBCD(B : BCD; Wigth, Places : Byte) : string;

Функция

     Возвращает значение из BCD в виде строки.

Описание

     Эта процедура по синтаксису является функциональным экви-
валентом функции  Tyrbo  Pascal Str(R;Wigth;Places,S).  StrBCD
возвращает строку в формате  числа  с  плавающей  точкой  (без
экспоненты). Заметим,  что  StrBCD  в  отличие от Str является
функцией, а не процедурой.

     Если вы хотите получить число BCD в формате  с  экспонен-
той, используйте  функцию  StrExpBCD.  Form  предоставляет вам
другой путь форматирования чисел в двоично-десятичном  формате
для вывода.

     Максимальное число  десятичных  знаков определяется в 18,
хотя StrBCD может вернуть и больше (заполняются нулями),  если
вам потребуется.  Если  действительная  длина строки превышает
требуемую Wigth,  то StrBCD будет использовать  действительную
длину. Если  действительная  длина меньше,  то в результате вы
получите выровненную по правому краю строку требуемой длины.

Пример

     WriteLn(StrBCD(B1,10,2);

     Выведет B1 на экран так же как

     WriteLn(R1:10:2);

     выводит нормальные числа в формате с плавающей точкой.

     StrBCD(B1,0,0);

     Возвратит число B1 округленное  до  ближайшего  целого  в
строке минимальной длины.

Смотрите также

     Form

StrExpBCD
──────────────────────────────────────────────────────────────
Объявление

     function StrExpBCD(B : BCD; Wigth : Byte) : string;

Функция

     Возвращает значение B в экспоненциальной форме.

Описание

     Эта процедура форматирует число типа BCD в строку в
экспоненциальной форме. Если Wigth равна 0, результат будет
помещен в строку длиной 24 байта в форме
-n.nnnnnnnnnnnnnnnnE+ee; для неотрицательных значений первый
символ будет содержать пробел. Если Wigth не равно 0, то возв-
ращаемая строка будет иметь длину Wigth символов. Если Wigth
будет меньше 24, то остающиеся цифры будут округлены, если
Wigth будет больше 24, то значение будет выровнено по правому
краю и заполнено спереди пробелами. Если Wigth будет больше 0,
но меньше 8, то будет использоваться строка длиной 8 символов.

Пример

     { предположим, B1 содержит 123456.9 }
     StrExpBCD(B1,0);

     Возвратит '1.23456900000000000E+05'.

     StrExpBCD(B1,9);

     Возвратит '1.23E+05'.

Смотрите также

     Form

SubBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure SubBCD(B1,B2 : BCD; var B3 : BCD);

Функция

     Вычитает B2 из B1, возвращает результат в B3.

Описание

     SubBCD создает временный результат с точностью до 19 зна-
чащих цифр, и затем округляет его до 18 цифр.

     Если результат превышает 1.0E64,  генерируется ошибка  по
переполнению, если   результат  меньше  1.0E-63,  возвращается
ноль.

TruncBCD
──────────────────────────────────────────────────────────────
Объявление

     function TruncBCD(B1 : BCD) : LongInt;

Функция

     Возвращает наибольшее длинное целое,  меньшее или  равное
B1.

Описание

     Если B1 больше или равно 0,  TruncBCD возвращает наиболь-
шее длинное целое, меньшее или равное B1. Иначе TruncBCD возв-
ращает наименьшее длинное целое, большее или равное B1.

     Если B1  превышает MaxLongInt (2.147.483.647),  генериру-
ется ошибка по переполнению.

Примеры

     { предположим B1 содержит 1.46 }
     TruncBCD(B1);

     Возвратит 1.

     { предположим B1 содержит 1.999999 }
     TruncBCD(B1);

     Возвратит 1.

     { предположим B1 содержит -1.999999 }
     TruncBCD(B1);

     Возвратит -1.

Смотрите также

     RoundBCD

ValBCD
──────────────────────────────────────────────────────────────
Объявление

     procedure ValBCD(S : string; var B : BCD; var Code : Word);

Функция

     Преобразует строку в BCD.

Описание

     Эта процедура эквивалентна процедуре Turbo Pascal Val.  S
это строка,  содержащая строковое представление числа в  любом
допустимом экспоненциальном  формате или в формате с плавающей
точкой. Допустимы начальные пробелы, но концевые не допустимы.

     Если преобразование произведено успешно,  Code будет  со-
держать 0,  а  в B будет помещено преобразованное значение.  В
противном случае Code будет содержать ненулевое значение, ука-
зывающее на  позицию в строке,  которая вызвала проблемы,  а B
будет содержать неопределенное значение.  Если строка содержит
значение слишком большое, чтобы быть преобразованным в BCD, то
Code будет указывать за конец строки.

Примеры

     ValBCD('0.57721566490153286061',B1,Code);

     Возвратит Code = 0, а константу Эйлера в B1. Заметим, что
лишние цифры  будут  обрезаны,  чтобы  число  поместилось в 18
цифр.

     ValBCD('  1.0E22   ',B1,Code);

     Возвратит Code = 9,  поскольку присутствуют концевые про-
белы.

     ValBCD(э'-1.0E99',B1,Code);

     Возвратит Code  =  8,  поскольку указанное число не может
быть представлено в формате BCD.

Смотрите также

     Form                         StrBCD
     StrExpBCD



               C. OPCLONE: Настройка программ.

     Прикладные программы   все  время  увеличиваются,  как  в
смысле размера, так и в смысле сложности, и все чаще возникает
необходимость в  предоставлении пользователю возможности наст-
ройки программ для удовлетворения индивидуальных нужд  и  зап-
росов. Для решения этой задачи существует множество путей, од-
нако мы не будем их здесь перечислять.  Мы остановимся на двух
более общих методах,  которые могут быть реализованы с исполь-
зованием OPCLONE.

     Первый - это программы, изменяющие сами себя. Если вы ра-
ботаете на Turbo Pascal, то основу написания таких программ
составляет помещение всех данных конфигурации в виде строковых
констант. Эти константы сохраняются в одной или нескольких
группах, каждой из которых предшествует уникальная идентифици-
рующая строка. Например:

     const
        { пометить начало данных конфигурации }
        MyProgIdString : string[9] = 'MYPROG ID';
        { данные конфигурации }
        MyProgColors : ColorSet = (...);
        MyProgHotKey : array[1..100] of Byte = (...);
        { пометить конец данных }
        MyProgCfgEnd : Byte = 0;

     Записав значения этих констант на соответствующее место в
EXE файле, которое определяется поиском идентификационной
строки, мы можем создать настроенную версию программы. (Исто-
рически сложилось так, особенно среди программистов, работаю-
щих на Turbo Pascal, что такие программы стали называть клона-
ми, отсюда и название юниты). При следующем запуске программы
эти сохраненные значения будут использоваться по умолчанию, и
пользователь не должен перенастраивать программу, если он не
хочет изменить что-либо еще.

     Второй метод - это программы установки или настройки. Он
отличается от первого метода тем, что программа настройки пол-
ностью отдельна от настраиваемой программы. Основное отличие
между этими двумя методами состоит в том, что программа уста-
новки должна считать текущие значения переменных из другой EXE
программы перед тем, как изменять их. В программах, изменяющих
самих себя, вы можете пропустить этот шаг. В остальном эти два
метода идентичны:

     1. Открыть EXE-файл, который нужно изменить.
     2. Определить местоположение  данных,  для  этого  искать
идентифицирующую строку.
     3. Считать текущие значения (только для программ настрой-
ки).
     4. Позволить пользователю изменить эти значения.  В прог-
раммах, изменяющих самих себя, это возможно уже сделано.
     5. Вывести измененные значения обратно на диск,  на место
откуда они были считаны.
     6. Закрыть EXE-файл.

     Имеется большое число вариаций этой базовой технологии  -
некоторые не требуют идентификационной строки,  некоторые про-
пускают второй шаг,  после того, как эта операция уже один раз
была выполнена, однако данная версия используется очень широко
и время показало ее надежность и удобство.

     В юните OPCLONE эта технология реализована в объекте,
названном Cloner. Cloner - это простой объект, который имеет
несколько методов, которые вы должны изучить, позволяющих
просто писать программы, изменяющие сами себя:

     {$A-}         { требуется для OPCLONE }
     program CloneTest;      { EXCLONE.PAS }
     uses
        Dos, OpInline, OpString, OpRoot, OpClone;
     const
        { Маркирует начало данных }
        Id : string[12] = 'CloneTest ID';
        { данные конфигурации }
        TimesRun : LongInt = 0;
        TestString : string[20] = 'Hello World';
        { Маркирует конец данных конфигурации }
        CfgEnd : Byte = 0;
     var
       C : Cloner;
     begin
        { Показать, что программа работает }
        WriteLn('Программа успешно запущена',TimesRun,' раз.');
        Inc(TimesRun);
        WriteLn("Тестовая строка =',TestString,'"');
        Write('Введите новую строку: ');
        ReadLn(TestString);
        { инициализация Cloner }
        if not C.InitCustom('EXCLONE.EXE',UpdateAll,DefBufSize) then
           WriteLn('Не могу модифицировать EXE файл');
        else begin
           { определить местоположение данных конфигурации }
           if not C.FindDefaultsEnd(Id,SizeOf(Id),0) then
              WriteLn('Не могу найти данные конфигурации');
           else begin
              { записать новые значения }
              C.StoreDefaults(C.GetPos,Id,Ofs(CfgEnd)-Ofs(Id));
              { есть ошибки? }
              if C.GetLastError <> 0 then
                 WriteLn('Ошибка при записи данных')
              else
                 WriteLn('Данные записаны');
           end;
           { закрыть EXE файл }
           C.Done;
        end;
     end.

     Первое, что вы заметили, это директива компилятора {$A-}.
Эта директива сообщает компилятору, что не нужно производить
выравнивание данных по границе слов переменных из области кон-
фигурационных данных. Хотя это нужно только в программах уста-
новки (настройки) и в программах, которые они модифицируют, вы
должны использовать эту директиву при каждом использовании
OPCLONE.

     Следующее замечание касается области данных конфигурации.
Она начинается с идентификационой строки (Id) и заканчивается
пустой переменной, которая маркирует конец области данных. Все
переменные, находящиеся между ними, считаются областью данных
конфигурации. Хотя пустая переменная в конце области данных
необязательна, имеются две причины для ее использования: 1)
это упрощает вычисление размера этой области, и 2) это до-
пускается добавление в эту область данных или удаление данных
из области без каких-либо изменений в вызовах методов
Cloner'а.

     Первая часть примера программы просто демонстрирует, что
она работает. Вы можете убедиться в этом, откомпилировав прог-
рамму и запустив ее несколько раз.

     Вызов C.InitCustom открывает EXE файл  и  выделяет  буфер
размером 4К (DefBufSize = 4096),  который используется при по-
иске строки.  Поиск производится при вызове C.FindDefaultsEnd.
Если поиск  оканчивается  успешно,  то смещение области данных
относительно начала файла  можно  получить  с  помощью  метода
GetPos. В   нашем   примере   это  значение  посылается  прямо
C.StoreDefaults, которая записывает текущее содержимое области
данных конфигурации  обратно в EXE-файл.  Вызов C.GetLastError
возвращает ошибку,  которая могла произойти при записи  данных
на диск. И наконец, C.Done закрывает EXE-файл, модифицирует
его время/дату и освобождает буфер.

     Cloner можно также использовать  для  написания  программ
настройки. Основное  отличие заключается в том,  что вы должны
вызвать LoadDefaults для загрузки данных конфигурации из наст-
раиваемой программы в область данных программы настройки. В
качестве примера такой программы посмотрите исходные тексты
DPINST - программы настройки DESKPOP. В качестве более сложно-
го примера использования OPCLONE для написания программ, из-
меняющих самих себя, смотрите SMACS.PAS.

                          Константы.

     MinBufSize = 512;

     Минимальный размер буфера.

     DefBufSize = 4096;

     Размер буфера, используемый по умолчанию.

                            Типы.

     Cloner =
        object(Root)
           ...
        end;

     Объект, используемый для написания программ настройки.

     DateUpdateType = (UpdateNone, UpdateDate, UpdateAll);

     Тип, который используется для указания  того,  должен  ли
Cloner изменять время и дату в файле после его модификации.
UpdateNone определяет, что время и дата не должны изменяться.
UpdateDate говорит о том, что должна изменяться только дата.
UpdateAll говорит о том, что должны быть модифицированы и вре-
мя и дата.

     SearchBuffer= array[0..DefBufSize-1] of Char;

     Буфер, используемый для поиска идентификационной строки.

Done
──────────────────────────────────────────────────────────────
Объявление

     destructor Done; virtual;

Функция

     Закрывает EXE-файл, изменяет время/дату, освобождает бу-
фер поиска.

Описание

     Этот метод должен вызываться после  завершения  работы  с
объектом Cloner. Он делает три вещи: 1) закрывает EXE-файл,
который был изменен, 2) изменяет время/дату в соответствии с
параметром, переданным конструктору, и 3) освобождает буфер,
который был выделен конструктором.

Пример

     Смотрите пример в начале данного раздела.

Смотрите также

     Init                         InitAndFind

FindDefaultsEnd
──────────────────────────────────────────────────────────────
Объявление

     function FindDefaultsEnd(var ID; IdSize : Word;
                              Skip : LongInt) : Boolean;

Функция

     Ищет ID в файле,  просматривая его в направлении от конца
к началу.

Описание

     Этот метод  используется  для  поиска   идентификационной
строки ID в EXE-файле. Он начинает поиск с конца файла и ищет
в направлении к началу до тех пор, пока он не найдет строку
или пока не просмотрит весь файл. Если идентификационная стро-
ка найдена, он возвращает True, и False, если не найдена. Если
строка найдена, ее положение может быть получено с помощью
GetPos.

     ID - это искомая строка, а IdSize определяет ее размер.
ID обычно является обычной строкой Turbo Pascal
('IdString,SizeOf(IdString)'), массивом символов
(IdArray,SizeOf(IdArray)'), или первым байтом строки Turbo
Pascal ('IdString[1],Lenght(IdString)'). Допустим любой тип
данных, при условии что его значение никогда не меняется и га-
рантируется, что он встречается в настраиваемом EXE-файле
только один раз.

     Skip определяет число байт, которые должны быть пропущены
в начале поиска. Например, если Skip = 1000, то в EXE-файле не
будут просматриваться последние 1000 байт. Это значение обычно
равно 0, но в некоторых ситуациях вы можете использовать боль-
шее значения,  если известно, что идентификационная строка на-
ходится далеко от конца файла,  и  важны  скорость  выполнения
операции.

     Если FindDefaultsEnd возвращает False,  вы можете опреде-
лить причину, вызвав метод GetLascError. Возвращаемый этим ме-
тодом код обычно является кодом ошибки ввода/вывода (например,
ошибка чтения диска), или epNonFatal+ecStringNotFound, что оз-
начает, что искомая строка не найдена. Чаще всего причиной та-
кой ошибки служат: 1) ошибки программиста (особенно если Skip
<> 0), 2) порча EXE-файла, и 3) EXE-файл был упакован с по-
мощью утилиты EXEPACK фирмы MicroSoft или PACK из Turbo
Analist.

Пример

     Смотрите пример в начале данного раздела.

Смотрите также

     FindDefaultsStart            GetPos
     GetLastError                 LoadDefaults

FindDefaultsStart
──────────────────────────────────────────────────────────────
Объявление

     function FindDefaultsStart(var ID; IdSize : Word;
                                Skip : LongInt) : Boolean;

Функция

     Ищет местонахождение ID, просматривая файл от начала к
концу.

Описание

     FindDefaultsStart аналогична FindDefaultsEnd, за исключе-
нием того, что производит поиск с начала файла по направлению
к концу. FindDefaultsStart используется в основном в том слу-
чае, если известно, что ID строка находится ближе к началу
EXE-файла, что случается, если данные конфигурации были подк-
лючены к файлу в объектном модуле, а не в группе типизирован-
ных констант.

     Параметры идентичны FindDefaultsEnd, за исключением того,
что Skip определяет число пропускаемых байт от начала файла.

Пример

     const
        Id : string[9] = 'MYPROG ID';
     var
        C : Cloner;
     begin
        if not C.Init('MYPROG.EXE',UpdateAll) then
           { обработка ошибки }
        else begin
           if not C.FindDefaultsStart(Id,SizeOf(Id),0) then
              { обработка ошибок }
           else begin
              ...
           end;
           C.Done;
        end;
     end;

Смотрите также

     FindDefaultsEnd              LoadDefaults

GetLastError
──────────────────────────────────────────────────────────────
Объявление

     function GetLastError : Word;

Функция

     Получает код последней ошибки.

Описание

     Этот метод возвращает код последней ошибки, которая прои-
зошла при работе одного из методов (за исключением конструкто-
ров, которые возвращают коды ошибок в InitStatus). Расшифровка
кода ошибки приведена в приложении D.

     Заметим, что  как  и  IoResult,  GetLastError  сбрасывает
внутреннюю переменную,  которая используется для хранения кода
ошибки, так что повторный вызов GetLastError всегда возвращает
0.

Пример

     Смотрите пример в начале данного раздела.

GetPos
──────────────────────────────────────────────────────────────
Объявление

     function GetPos : LongInt;

Функция

     Возвращает точку, в которой найдена строка.

Описание

     Этот метод может быть вызван после  успешного  завершения
вызова методов FindDefaultsStart и FindDefaultsEnd для опреде-
ления смещения в файле местоположения идентификационной стро-
ки. Если произошла ошибка, GetPos всегда возвращает 0 (невоз-
можное смещение для идентификационной строки. Иначе она возв-
ращает значение в диапазоне от 1 до FileSize(ExeFile)-1. Это
значение может быть затем передано LoadDefaults, для загрузки
данных конфигурации.

     Заметим, что возвращается смещение начала идентификацион-
ной строки. Поэтому при вызове LoadDefaults последний параметр
(Bytes) должен включать размер идентификациооной строки.

Пример

     Смотрите пример в начале данного раздела.

Смотрите также

     FindDefaultsEnd              LoadDefaults
     FindDefaultsStart

Init
──────────────────────────────────────────────────────────────
Объявление

     constructor Init(FName : string; DUT : DateUpdateType);

Функция

     Открывает для клонирования EXE-файл и выделяет буфер.

Описание

     Этот конструктор просто вызывает  InitCustom  с  размером
буфера DefBufSize.

InitCustom
──────────────────────────────────────────────────────────────
Объявление

     constructor InitCustom(FName : string; DUT : DateUpdateType;
                            BufSize : Word);

Функция

     Открывает EXE-файл для клонирования и выделяет буфер.

Описание

     Этот конструктор пытается открыть EXE-файл,  определяемый
FName, и выделяет буфер, используемый для поиска в файле иден-
тификационной строки.  BufSize определяет  размер  выделяемого
буфера. Он должен быть от MinBufSize до 65521.

     InitCustom завершается по ошибке только, если EXE-файл не
может быть открыт, или если буфер не может быть выделен. Для
определения конкретной причины ошибки проверьте содержимое
глобальной переменной InitStatus, объявленной в OPROOT.

     DUT, определяет должны ли быть изменены дата и время фай-
ла. Обсуждение возможных значений данного параметра вы найдете
в описании DataUpdateType.

Пример

     Смотрите пример в начале данного раздела.

Смотрите также

     Done                         InitAndFind

InitAndFind
──────────────────────────────────────────────────────────────
Объявление

     constructor InitAndFind(FName : string; DUT : DateUpdateType;
                             var ID; IdSize : Word);

Функция

     Инициализирует объект и ищет идентификационную строку.

Описание

     Этот конструктор    комбинирует    возможности   Init   и
FindDeaultsEnd и предназначен в основном для удобства. Он за-
вершается по ошибке в случае: 1) не может быть открыт EXE-файл
(FName), 2) не может быть выделен буфер, и 3) идентификацион-
ная строка не может быть найдена. Для определения конкретной
причины ошибки проверьте содержимое глобальной переменной
InitStatus, объявленной в OPROOT.

     InitAndFind не делает ничего,  кроме того, что просто пе-
редает   первые   два   параметра   Init,   а    вторые    два
FindDefaultsEnd. Смотрите описание этих двух методов. Заметим,
что InitAndFind всегда передает FindDefaultsEnd в качестве па-
раметра Skip 0.

Пример

     var
        C : Cloner;
     begin
        if not C.InitAndFind('MYPROG.EXE',UpdateAll,Id,SizeOf(Id)) then
           { обработка ошибки }
        else begin
           { изменение данных конфигурации }
           C.Done;
        end;
     end;

Смотрите также

     FindDefaultsEnd              Init

LoadDefaults
──────────────────────────────────────────────────────────────
Объявление

     procedure LoadDefaults(FileOfs : LongInt;
                            var Defaults; Bytes : Word);

Функция

     С позиции FileOfs считывает Defaults.

Описание

     Этот метод используется для загрузки данных конфигурации,
после определения      их      местоположения      процедурами
FindDefaultsEnd, FindDefaultsStart  и  InitAndFind.  Если  при
считывании данных произошла ошибка,  ее код можно получить при
помощи метода GetLastError.

     FileOfs - смещение относительно начала файла считываемых
данных - обычно получает с помощью метода GetPos. Defaults оп-
ределяет начало области памяти, в которую должны быть считаны
данные, а Bytes определяет объем считываемых данных.

     Важно: GetPos возвращает смещение начала идентификацион-
ной строки, а не смещение для реальных данных конфигурации.
Поэтому вы должны, или 1) в качестве параметра Defaults пере-
давать имя идентификационной строки, а в качестве параметра
FileOfs передавать значение полученное методом GetPos, или 2)
передавать в качестве параметра Defaults имя первой перемен-
ной, следующей за идентификационной строкой, а в качестве па-
раметра FileOfs передавать GetPos+SizeOf(IdString). Если вы
выбираете первый вариант, то параметр Bytes должен включать
длину идентификационной строки, если вы выбираете 2), то не
должен.

     Заметим, что LoadDefaults не должен вызываться  из  прог-
рамм, изменяющих самих себя (как SMACS),  а только из программ
(как DPINST),  которые изменяют другие  программы  (DESKPOP  в
случае DPINST).

Пример

     var
        C : Cloner;
     const
        Id : string[9] = 'MYPROG ID';
        { ...данные конфигурации... }
        CfgEnd : Byte : 0;
     var
        SeekOfs : LongInt;
     begin
        if not C.InitAndFind('MYPROG.EXE',UpdateAll,Id,SizeOf(Id)) then
           { обработка ошибки }
        else begin
           SeekOfs := C.GetPos;
           C.LoadDefaults(SeekOfs,Id,Ofs(CfgEnd)-Ofs(Id));
           {... изменение данных конфигурации ...}
           C.Done;
        end;
     end;

Смотрите также

     FindDefaultsEnd              InitEndFind
     FindDefaultsStart            StoreDefaults
     GetPos

StoreDefaults
──────────────────────────────────────────────────────────────
Объявление

     procedure StoreDefaults(FileOfs : LongInt;
                             var Defaults; Bytes : Word);

Функция

     Записывает с позиции FileOfs данные из Defaults.

Описание

     Этот метод позволяет сохранить измененные данные конфигу-
рации в EXE файле.  Если при записи возникла  ошибка,  ее  код
можно получить с помощью метода GetLastError.

     FileOfs - это смещение относительно начала файла начала
области данных конфигурации, и обычно это значение получается
с помощью функции GetPos. Defaults определяет начало области
данных, а Bytes ее длину.

     Как описано в  документации  по  GetPos  и  LoadDefaults,
GetPos возвращает смещение начала идентификационной строки,  а
не самих  данных  конфигурации.  Смотрите  по   этому   поводу
LoadDefaults.

Пример

     Смотрите пример в начале данного раздела.

Смотрите также

     GetPos                       LoadDefaults



 D: OPERRHAN: Восстановление при ошибках времени выполнения.

     Turbo Pascal  обладает  довольно мощными возможностями по
обработке ошибок времени выполнения.Программист  может  отклю-
чить проверку диапазонов, проверку переполнения стека, провер-
ку результатов операций ввода/вывода.  Ошибки выделения памяти
в "куче"  могут  отключаться  с помощью HeapError.  Все ошибки
времени выполнения могут отслеживаться пользовательской проце-
дурой выхода.

     Однако один вопрос остается без ответа: Как программа мо-
жет восстановиться после ошибки времени выполнения и продол-
жить работу. Object Professional дает вам ответ на этот вопрос
с помощью юниты OPERRHAN.

     OPERRHAN отслеживает  ошибки  через  программу  обработки
ошибок Turbo Pascal. Управление передается от нормальной юниты
SYSTEM процедуре,  определенной в OPERRHAN. OPERRHAN классифи-
цирует ошибки как поддающиеся восстановлению и фатальные,  вы-
числяет куда должно быть возвращено управление  после  восста-
новления, необязательно  вызывает процедуру определенную поль-
зователем и возвращает управление программе или программе  об-
работки ошибок из юниты SYSTEM.

     Некоторые ошибки времени выполнения к сожалению невосста-
новимы - OPERRHAN распознает их и возвращает управление  прог-
рамме обработки ошибок из SYSTEM,  которая обрывает выполнение
программы и вызывает пользовательские процедуры  выхода,  если
они есть. Раньше мы классифицировали как невосстановимые четы-
ре типа ошибок времени выполнения Turbo Pascal: ошибка 202
(переполнение стека), 203 (переполнение "кучи"), ошибки 208 и
209 (ошибки оверлеев), и любые ошибки, генерируемые сопро-
цессором 80х87 (или эмулятором Turbo Pascal). Все остальные
ошибки времени выполнения Turbo Pascal, включая ошибки вво-
да/вывода, рассматривались как поддающиеся восстановлению.

     Проблемы, возникающие при переполнении стека, могут быть
решены увеличении стека программы с помощью директивы компиля-
тора {$M}, или путем переорганизации использования локальных
переменных в программе. Вы можете превратить ошибки переполне-
ния "кучи" в восстанавливаемые с помощью HeapError.

     Восстановление после ошибок сопроцессора можно обеспечить
программированием регистра состояния сопроцессора,  чтобы он в
случае ошибки не генерировал прерывание, а возвращал код ошиб-
ки. Смотрите описание юниты OP8087.

     Заметим, что ошибки ввода/вывода (ошибки времени выполне-
ния с номерами меньше 200) приводят к занесению в IoResult не-
нулевого значения. IoResult должен быть очищен перед выполне-
нием следующих операций ввода/вывода. Хотя вы можете отключить
проверку успешности операций ввода/вывода с помощью директивы
компилятора {$I-}, для обработки ошибок ввода/вывода не очень
хорошо использовать OPERRHAN. Однако в некоторых ситуациях мо-
жет быть необходима централизация обработки ошибок.

     Ниже приведена  программа,  демонстрирующая использование
юниты OPERRHAN.

     {$R+}
     program TestErrHan;   { EXERRHAN.PAS }
     uses
        Dos, OpErrHan, OpString;
     var
        I, J, K : Integer;
        V : 1..10;

     {$F+}  { Должна использовать модель FAR }
     function RecoverError : Boolean;
     { вызывается при возникновении ошибки.  Возвращает  True,}
       если возможно восстановление. }
     var
        I : Word;
     begin
        { Очистить IoResult }
        I := IoResult;
        WriteLn('Программа обработки ошибок: код',ExitCode:3,
                 ' в ',HexW(Seg(ErrorAddr^)),':',
                 HexW(Ofs(ErrorAddr^)));
        RecoverError := True;
     end;

     begin
        { Разрешить обработку ошибок и установить пользова-
          тельскую процедуру. }
        ErrorRecovery(True,@RecoverError);
        I := 0;
        J := 1;
        K := J div I;
        if ExitCode <> 0 then
           WriteLn('Деление на 0');
        I := 20;
        V := I;
        if ExitCode <> 0 then
           WriteLn('Ошибка диапазона');
     end;

     Поскольку OPERRHAN должен внести поправки в  систему  вы-
полнения Turbo Pascal, ее инициализационный код осторожно ищет
точку поправки.  Если все сделано успешно, OPERRHAN устанавли-
вает флаг ErrorRecovery в True.  Раньше мы знали о двух причи-
нах, приводивших  к  тому,  что  CanRecover  получал  значение
False: или  библиотека SYSTEM Turbo Pascal была радикально из-
менена, или прикладная программа захватывает  вектора  INT  $0
(деление на 0) и INT $23 (обработка Ctrl-Break) до вызова кода
инициализации OPERRHAN.  Первая проблема приводит к  необходи-
мости изменения  кода инициализации OPERRHAN.  Вторая проблема
может быть решена помещением OPERRHAN в операторе  USES  перед
процедурой, определяемой пользователем.

ErrorRecovery
──────────────────────────────────────────────────────────────
Объявление

     procedure ErrorRecovery(On: Boolean; UserRoutine: Pointer);

Функция

     Включает и  выключает  восстановление ошибок и подключает
пользовательскую процедуру.

Описание

     Вызов этой процедуры приводит к активизации или деактиви-
зации восстановления ошибок времени выполнения.  Если параметр
On равен True, то восстановление активизируется, иначе оно де-
активизируется и  используется  стандартная  система обработки
ошибок Turbo Pascal.  OPERRHAN позволяет восстанавливать после
большинства, но  не  всех ошибок времени выполнения.  Смотрите
описание OPERRHAN.

     UserRoutine - это указатель на функцию, определяемую
пользователем, который должен определить дальнейшее поведение
прикладной программы. Если вы не хотите определять такой про-
цедуры, то вместо этого параметра передайте nil. UserRoutine
должен указывать на функцию, объявленную следующим образом:

     {$F+}
     function RecoverError : Boolean;
     { вызывается при возникновении ошибки.  Возвращает  True,}
       если возможно восстановление. }

     Заметим, что процедура должна быть глобальной, откомпили-
рованной под моделью FAR.  Отсутствие перед функцией директивы
{$F+} приведет к краху системы.

     Функция UserRoutine  вызывается при возникновении ошибок,
которые поддаются восстановлению. В этот момент глобальная пе-
ременная ExitCode содержит номер ошибки времени выполнения,  а
ErrorAddr содержит нормализованный адрес точки, в которой про-
изошла ошибка.  UserRoutine  может  вычислить  эти  значения и
предпринять необходимые    действия.     Перед     завершением
UserRoutine должна  установить результат True,  если требуется
восстановление, и False, если выполнение программы должно быть
завершено.

     Если ошибка  времени выполнения не поддается восстанавле-
нию, или если UserRoutine вернула False, OPERRHAN передает уп-
равление стандартному обработчику ошибок, который выполняет
обычные действия: вызывает пользовательские процедуры выхода,
закрывает все файлы, восстанавливает вектора прерываний и за-
вершает выполнение программы.

     Если ошибка времени выполнения поддается  восстановлению,
и UserRoutine  возвращает  True,  OPERRHAN передает управление
команде, непосредственно следующей  за  той,  которая  вызвала
возникновение ошибки.  Прикладная программа отвечает за запол-
нение ExitCode, определяющего номер возникшей ошибки. ExitCode
содержит нормальные коды ошибок Turbo Pascal: 0, если не было
ошибки, ненулевое значение при ошибке. Смотрите список кодов
ошибок и их описание в документации по Turbo Pascal.

     Если прикладная программа использует систему восстановле-
ния ошибок Object Professional, код инициализации OPERRHAN ав-
томатически вызывает  ErrorRecovery  для  активизации  системы
восстановления ошибок. По умолчанию OPERRHAN не устанавливает
пользовательскую процедуру UserRoutine.

Пример

     {$F+}
     function RecoverError : Boolean;
     var
        I : Word;
     begin
        { Очистить IoResult }
        I := IoResult;
        RecoverError := True;
     end;
     {$F-}
     begin
        ErrorRecovery(True,@RecoverError);
        ...

     Это простейшая UserRoutine.  Она очищает IoResult,  чтобы
могли выполняться последующие операции ввода/вывода, и возвра-
щает True для восстановления любых ошибок времени выполнения.


Смотрите также

     Error8087(OP8087)            Exception8087(OP8087)



    E. OPINLINE: Смешанные встраиваемые макроопределения.

     Одним из наиболее мощных расширений Turbo Pascal являются
встраиваемые процедуры.  В отличие от  нормальных  процедур  и
функций, код  которых располагается в определенном месте,  со-
держимое встраиваемой процедуры непосредственно вставляется  в
объектный код при каждой ссылке на эту процедуру.  Хотя встаи-
ваемые процедуры могут получать параметры и возвращать резуль-
тат функций как обычные процедуры и функции, компилятор
рассматривает их как обычные макроопределения, аналогично име-
ющимся в C. По этой причине мы назвали их встраиваемыми макро-
определениями.

     В OPINLINE вы найдете встраиваемые макроопределения,  ко-
торые позволяют:

     - Устанавливать  маркер  и  впоследствии возвращаться на
него из любого места программы.
     - Устанавливать, сбрасывать и проверять битовые флаги.
     - Нормализовывать указатели.
     - Обмениваться значениями двух переменных  без использо-
вания временной переменной.
     - Инициализировать  массив  любого типа без использования
цикла FOR.

     Кроме этого вы найдете много процедур (большинство из ко-
торых реализовано  не как макроопределения) для выполнения вы-
числений с использованием указателей.

                            Типы.

     JumpRecord =
        record
           SpReg, BpReg : Word;
           JmpPt : Pointer;
        end;

     Используется SetJump и LongJump для сохранения данных для
нелокального перехода.

     LH =
        record
           L, H : Word;
        end;

     Используется для определения длинных целых, позволяет
осуществить доступ к старшему и младшему слову, которые
составляют LongInt.

     OS =
        record
           O, S : Word;
        end;

     Используется для  определения указателей,  позволяет осу-
ществить простой доступ к адресу сегмента (S) и смещению (O).

AddLongToPtr
──────────────────────────────────────────────────────────────
Объявление

     function AddLongToPtr(P : Pointer; L : LongInt) : Pointer;

Функция

     Прибавляет к указателю LongInt и возвращает нормализован-
ный указатель.

Описание

     Эта процедура  преобразует сегментированный адрес P в ли-
нейный адрес, прибавляет L и возвращает нормализованный сег-
ментированный адрес.

Пример

     type
        BytePtr = ^Byte;
     var
        P : Pointer; { указатель на массив байт размером 128K }
        L : LongInt;
     begin
        { ... выделение и инициализация P ... }
        for L := 0 to $1FFFF do
           Write(BytePtr(AddLongToPtr(P,L)^:4);
     end;

     Выводит значение всех байт из массива, адресуемого P.

Смотрите также

     Normalized

AddWordToPtr
──────────────────────────────────────────────────────────────
Объявление

     function AddWordToPtr(P : Pointer; W : Word) : Pointer;

Функция

     Прибавляет к указателю значение типа Word.

Описание

     AddWordToPtr аналогична AddLongToPtr,  однако не произво-
дит нормализации и проверки переноса.  В случаях,  когда могут
использоваться обе  процедуры,  предпочтительнее  использовать
AddWordToPtr, поскольку она быстрее. (AddWordToPtr реализована
как встравиваемое макрорасширение, а AddLongToPtr нет.)

Пример

     P := Ptr($40,$01);
     P1 := AddWordToPtr(P,$400);
     P2 := AddLongToPtr(P,$400);

     P1 указывает на $40:$401,  P2 устанавливается на $80:$01,
поскольку AddLongToPtr  в  отличие от AddWordToPtr нормализует
указатель. Однако в обоих случаях они указывают на одну  и  ту
же точку.

Смотрите также

     Normalized

Array2Str
──────────────────────────────────────────────────────────────
Объявление

     function Array2Str(var A; Len : Byte) : string;

Функция

     Преобразует массив символов в строку.

Описание

     Быстрое преобразование  массива символов (часто использу-
ется в прикладных базах данных) в строку. Поскольку это встра-
иваемое макрорасширение, то оно несколько быстрее встроенной в
Turbo Pascal процедуры преобразования,  которая требует вызова
юниты SYSTEM.

Пример

     const
        A : arra[1..4] of Char = 'Test';
     var
        S : string;
     ...
        S := Array2Str(A,4);

     S будет присвоено 'Test'. S[0] будет содержать #4.

     FastWrite(Array2Str(A,4),1,1,$07);

     Выводит в левом верхнем углу экрана 'Test'.

ByteFlagIsSet
──────────────────────────────────────────────────────────────
Объявление

     function ByteFlagIsSet(Flags, FlagMask : Byte) : Boolean;

Функция

     Возвращает True, если в Flags установлен бит, определяе-
мый параметром FlagMask.

Описание

     Это макрорасширение проверяет, установлен ли бит, уста-
новленный в FlagMask и в Flags. В большинстве случаев FlagMask
не должен иметь больше одного установленного бита. Хотя
ByteFlagIsSet может сообщить вам, что один из них установлен
или что ни один из них не установлен, но не может сказать, что
все они установлены.

Пример

     ByteFlagIsSet(Flags,$02);

     Правильно. Возвращает True,  если бит 1 в Flags  установ-
лен. ($02 = 00000010).

     ByteFlagIsSet(Flags,$3);

     Возможно, не верно. Вы не сможете определить, что биты 0
и 1 установлены. ($03 = 00000011). Вы можете определить, что
один из них установлен.

Смотрите также

     ClearByteFlag                SetByteFlag

CallOldIsr
──────────────────────────────────────────────────────────────
Объявление

     procedure CallOldIsr(OldIsr : Pointer);

Функция

     Вызывает старую  программу обработки прерывания из проце-
дуры обработки прерывания.

Описание

      Эмулирует прерывание,  помещая  в  стек  регистр  флагов
центрального процессора, и осуществляет дальний вызов по ад-
ресу, передаваемому в параметре OldIsr. Это макрорасширение
позволяет вызывать программу обработки прерывания, которая
обслуживала данное прерывание до того, как вы его захватили. В
отличие от EmulateInt, она предназначена для вызова из прог-
рамм обработки прерываний, написанных на встраиваемом коде, а
не на Psacal. Заметим, что данное макрорасширение разрушает
содержимое регистра BX.

Пример

     procedure MyIsr(BP : Word); interrupt;
     begin
        CallOldIsr(SaveInt09);
        ...
     end;

     Вызывает старый вектор прерывания 09 (обработка клавиату-
ры).

Смотрите также

     EmulateInt(OPINT)            JumpToOldIsr

ClearByteFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure ClearByteFlag(var Flags : Byte; FlagMask : Byte);

Функция

     Сбрасывает в Flags бит(ы), определяемые FlagMask.

Описание

     Это макрорасширение  очищает  в  Flags все биты,  которые
установлены в FlagMask.  Заметим,  что Flags должен быть пере-
менным параметром типа Byte.

Пример

     ClearByteFlag(BitFlags,$02);

     Сбрасывает в Flags бит 1 ($02 = 00000010);

Смотрите также

     ByteFlagIsSet                SetByteFlag

ClearFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure ClearFlag(var Flags : Word; FlagMask : Word);

Функция

     Сбрасывает в Flags бит(ы), определяемые FlagMask.

Описание

     Это макрорасширение  очищает  в  Flags все биты,  которые
установлены в FlagMask.  Заметим,  что Flags должен быть пере-
менным параметром типа Word.

Пример

     ClearFlag(BitFlags,$0002);

     Сбрасывает в Flags бит 1 ($0002 = 0000000000000010);

Смотрите также

     FlagIsSet                    SetFlag

ClearLongFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure ClearLongFlag(var Flags : LongInt;
                             FlagMask : LongInt);

Функция

     Сбрасывает в Flags бит, определяемый FlagMask.

Описание

     Это макрорасширение  очищает  в  Flags все биты,  которые
установлены в FlagMask.  Заметим,  что Flags должен быть пере-
менным параметром типа Long.

Пример

     ClearLongFlag(BitFlags,$00000002);

     Сбрасывает в Flags бит 1
     ($00000002 = 00000000000000000000000000000010);

Смотрите также

     LongFlagIsSet                SetLongFlag

ExchangeBytes
──────────────────────────────────────────────────────────────
Объявление

     procedure ExchangeBytes(var I,J : Byte);

Функция

     Обменивает содержимое байт I и J.

Описание

     Это макрорасширение позволяет вам произвести обмен содер-
жимого двух байт без использования временной переменной. Часто
используется при сортировке. Заметим, что использование вре-
менной переменной работает быстрее в случае, если обменивае-
мые переменные не являются элементами массива.

Пример

     if MyArray[I] > MyArray[I+1] then
        ExchangeBytes(MyArray[I],MyArray[I+1]);

     Если MyArray[I] больше MyArray[I+1], то обменивает содер-
жимое этих двух ячеек.

ExchangeLongInts
──────────────────────────────────────────────────────────────
Объявление

     procedure ExchangeLongInts(var I,J : LongInt);

Функция

     Обменивает содержимое длинных целых I и J.

Описание

     Это макрорасширение позволяет вам произвести обмен содер-
жимого двух длинных целых без использования временной перемен-
ной. Часто используется при сортировке. Заметим, что использо-
вание временной переменной работает быстрее в случае, если об-
мениваемые переменные не являются элементами массива.

     Заметим, что  ExchangeLongInts можно использовать для об-
мена значений указателей,  если их привести  предварительно  к
LongInt (смотрите второй пример).

Пример

     if MyArray[I] > MyArray[I+1] then
        ExchangeLongInts(MyArray[I],MyArray[I+1]);

     Если MyArray[I] больше MyArray[I+1], то обменивает содер-
жимое этих двух ячеек.

     if MyPtrArray[I]^ > MyPtrArray[I+1]^ then
        ExchangeLongInts(LongInt(MyPtrArray[I]),
                         LongInt(MyPtrArray[I+1]));

     Если MyPtrArray[I]^ больше MyPtrArray[I+1]^, то обменива-
ет значения указателей .

Смотрите также

     ExchangeWords                ExchangeStructs

ExchangeStructs
──────────────────────────────────────────────────────────────
Объявление

     procedure ExchangeStructs(var I,J; Size : Word);

Функция

     Производит обмен содержимого структур I и J.

Описание

     Это макрорасширение позволяет вам произвести обмен содер-
жимого структур  I и J без использования временной переменной.
I и J могут быть переменными любого типа, но должны иметь оди-
наковый размер. Данное макрорасширение специально предназначе-
но для использования при сортировке. Заметим, однако, что если
I и J не являются элементами одного массива, то вариант с вре-
менной переменной будет работать быстрее, чем ExchangeStructs.
ExchangeStructs лучше всего использовать, когда вы не можете
выделить место для временных переменных.

Пример

     if MyRec1.Field > MyRec2.Field then
        ExchangeStructs(MyRec1,MyRec2,SizeOf(MyRec1));

     Если поле  Field структуры MyRec1 больше содержимого поля
Field структуры  MyRec2,  то  производится  обмен  содержимого
структур.

     if MyString1 > MyString2 then begin
        I := MaxWord(Length(MyString1),Length(MyString2));
        ExchangeStructs(MyString1,MyString2,I+1);
     end;

     Если MyString1 больше MyString2, то производится обмен
значениями. Заметим, что число перемещаемых байт ограничено
длиной самой длинной строки плюс еще один байт, в котором хра-
нится длина строки.

Смотрите также

     ExchangeBytes                ExchangeLongInt

ExchangeWords
──────────────────────────────────────────────────────────────
Объявление

     procedure ExchangeWords(var I,J : Word);

Функция

     Обменивает содержимое слов I и J.

Описание

     Это макрорасширение позволяет вам произвести обмен содер-
жимого двух слов без использования временной переменной. Часто
используется при сортировке. Заметим, что использование вре-
менной переменной работает быстрее в случае, если обмениваемые
переменные не являются элементами массива.

Пример

     if MyArray[I] > MyArray[I+1] then
        ExchangeWords(MyArray[I],MyArray[I+1]);

     Если MyArray[I] больше MyArray[I+1], то обменивает содер-
жимое этих двух ячеек.

Смотрите также

     ExchangeBytes                ExchangeLongInt

FarCall
──────────────────────────────────────────────────────────────
Объявление

     procedure FarCall(ProcAddr : Pointer);

Функция

     ProcAddr - это адрес вызываемой Far процедуры.

Описание

     Это макрорасширение позволяет вам вызвать любую процедуру
из любого кодового сегмента, если: 1) она не получает парамет-
ров, 2) она была откомпилирована под моделью FAR, использована
директива {$F+}, 3) она не вложена внутрь другой процедуры.
FarCall можно использовать при реализации таблицы переходов.
Эта процедура предназначена для обеспечения совместимости с
Turbo Professional.

Примеры

     FarCall(ProcPtr);

     Правильно. Производит дальний вызов MyProc.

     ProcPtr := @MyProc;
     ...
     FarCall(ProcPtr^);

     Неправильно! '^' ненужно.

     var MyJumpTable : array[1..10] of Pointer;
     ...
     FarCall(MyJumpTable[Index]);

     Осуществляет дальний вызов процедуры из таблицы адресов.

Смотрите также

     NearCall

FillStruct
──────────────────────────────────────────────────────────────
Объявление

     procedure FillStruct(var Dest; Count : Word; var Filler;
                          FillerSize : Word);

Функция

     Заполняет память с адреса Dest экземплярами Filler.

Описание

     Это макрорасширение  аналогично  процедуре  FillChar,  за
исключением того, что она заполняет память значениями размером
FillerSize, а не байтами.  Dest определяет область памяти, ко-
торую необходимо заполнить. Filler - это значение, которым
происходит заполнение. Его размер содержится в FillerSize.
Count - это число экземпляров Filler. FillStruct обычно
используется для инициализации массивов. Заметим, что не про-
изводится никакой проверки диапазона для предотвращения перек-
рытия сегментов.

Пример

     var MyArray : array[1..1000] of Real;
     const R : Real = 1.2345;
     ...
     FillStruct(MyArray,1000,R,SizeOf(R));

     Инициализирует все 1000 элементов массива числом 1.2345.

FillWord
──────────────────────────────────────────────────────────────
Объявление

     procedure FillWord(var Dest; Count,Filler : Word);

Функция

     Заполняет область  памяти  с адреса Dest,  записывая туда
Count экземпляров Filler.

Описание

     Это макрорасширение  аналогично  процедуре  FillChar,  за
исключением того,  что  она  заполняет  память значениями типа
Word, а не байтами.  Dest определяет область  памяти,  которую
необходимо заполнить. Filler - это значение, которым происхо-
дит заполнение. Count - это число экземпляров Filler. FillWord
обычно используется для инициализации массивов. Заметим, что
не производится никакой проверки диапазона для предотвращения
перекрытия сегментов.

Пример

     var
        MyArray1 : array[1..100] of Word;
        MyArray2 : array[1..100] of Integer;
        I : Integer;
     ...
     FillWord(MyArray1,100,1);
     I := 1;
     FillWord(MyArray2,100,Word(1));

     Инициализирует все  100  элементов  массивов  MyArray1  и
MyArray2 значением 1.

FlagIsSet
──────────────────────────────────────────────────────────────
Объявление

     function FlagIsSet(Flags, FlagMask : Word) : Boolean;

Функция

     Возвращает True, если в Flags установлен бит, определяе-
мый параметром FlagMask.

Описание

     Это макрорасширение проверяет, установлен ли в Flags бит,
установленный в FlagMask. В большинстве случаев FlagMask не
должен иметь больше одного установленного бита. Хотя FlagIsSet
может сообщить вам, что один из них установлен, или что ни
один из них не установлен, но не может сказать, что все они
установлены.

Пример

     FlagIsSet(Flags,$0002);

     Правильно. Возвращает True,  если бит 1 в Flags  установ-
лен. ($0002 = 0000000000000010).

     FlagIsSet(Flags,$3);

     Возможно, не верно. Вы не сможете определить, что биты 0
и 1 установлены. ($0003 = 0000000000000011). Вы можете опреде-
лить, что один из них установлен.

Смотрите также

     ClearFlag                SetFlag

HiWord
──────────────────────────────────────────────────────────────
Объявление

     function HiWord(L:LongInt) : Word;

Функция

     Возвращает старшее слово L.

Описание

     Это макрорасширение возвращает старшее слово длинного це-
лого значения.  HiWord  имеется  в  версии  Turbo  Pascal  для
Macintosh, однако ее нет в версии для IBM.

Пример

     const MyLongInt = $FFFF0000;
     ...
     MyWord := HiWord(MyLongInt);

     MyWord будет присвоено значение $FFFF.

Смотрите также

     LoWord                       SwapWord

JumpToOldIsr
──────────────────────────────────────────────────────────────
Объявление

     procedure JumpToOldIsr(OldIsr : Pointer);

Функция

     Переходит на старую  программу  обработки  прерывания  из
процедуры обработки прерывания.

Описание

     Как ChainInt (OPINT) это макрорасширение позволяет вам
восстановить регистры центрального процессора, сохраненные в
стеке в начале процедуры обработки прерывания, и затем пере-
дать управление программе обработки прерывания, которая обслу-
живала данный вектор до того, как ваша программа его захвати-
ла. В отличие от ChainInt, JumpToOldIsr предназначена для
использования в процедурах обработки прерываний, написанных на
встроенном коде, а не на Pascal.

Пример

     GetIntVect($09,SaveInt09);
     ...
     procedure MyIsr(BP : Word); interrupt;
     begin
        { ... какие либо действия ... }
        JumpToOldIsr(SaveInt09);
     end;

     Правильно. Переходит на старую программу обработки преры-
вания $09.

     JumpToOldIsr(SaveInt09^);

     Неправильно. '^' ненужно.

Смотрите также

     CallOldIsr                   ChainInt(OPINT)

LongFlagIsSet
──────────────────────────────────────────────────────────────
Объявление

     function LongFlagIsSet(Flags,
                            FlagMask : LongInt) : Boolean;

Функция

     Возвращает True, если в Flags установлен бит, определяе-
мый параметром FlagMask.

Описание

     Это макрорасширение проверяет, установлен ли в Flags бит,
установленный в FlagMask. В большинстве случаев FlagMask не
должен иметь больше одного установленного бита. Хотя
LongFlagIsSet может сообщить вам, что один из них установлен,
или что ни один из них не установлен, но не может сказать, что
все они установлены.

Пример

     LongFlagIsSet(Flags,$00000002);

     Правильно. Возвращает True,  если бит 1 в Flags  установ-
лен. ($00000002 = 00000000000000000000000000000010).

     LongFlagIsSet(Flags,$00000003);

     Возможно, не верно. Вы не сможете определить, что биты 0
и 1 установлены. ($00000003 =
00000000000000000000000000000011). Вы можете определить, что
один из них установлен.

Смотрите также

     ClearLongFlag                SetLongFlag

LongJump
──────────────────────────────────────────────────────────────
Объявление

     procedure LongJump(var JumpDest : JumpRecord;
                        Result : Word);

Функция

     Восстанавливает регистры SP, BP и осуществляет переход на
JumpDest.JmpPt.

Описание

     Это макрорасширение   использует  данные,  сохраненные  в
JumpRecord при вызове SetJump для  осуществления  нелокального
перехода. Восстанавливает стек в состояние, в котором он нахо-
дился при вызове SetJump, и осуществляет переход на команду,
непосредственно следующую за SetJump. Result - это значение,
возвращаемое как результат вызова SetJump. (Смотрите описание
SetJump).

     Очень важно: LongJump нельзя использовать для перехода от
стека, расположенного в старших адресам,  к стеку, расположен-
ному в младших адресах. Рассмотрим следующий пример:

     program MyProg;
        procedure MyProc;
        begin
        { Point B }
        end;
     begin
        { Point A }
     end;.

     Можно вызвать SetJump в точке A и LongJump в точке B  для
возврата в точку A. Однако нельзя осуществлять обратную после-
довательность (переход из A то B).  Хотя  LongJump  использует
для перехода команду дальнего перехода,  использование дальней
(FAR {$F+}) модели или ближней (NEAR {$F-} модели не имеет
значения.

Пример

     Смотрите пример на SetJump.

Смотрите также

     SetJump

LongToPtr
──────────────────────────────────────────────────────────────
Объявление

     function LongToPtr(L : LongInt) : Pointer;

Функция

     Возвращает LongInt как нормализованный указатель.

Описание

     Преобразует L, представляющее линейный адрес, в номализо-
ванный указатель (сегментный адрес).

Пример

     LongToPtr($401);

     Возвращает $40:$01.

     P := LongToPtr(PtrToLong(Ptr($40,$01)) + $100);

     P будет присвоено значение $50:$01.

Смотрите также

     PtrToLong

LoWord
──────────────────────────────────────────────────────────────
Объявление

     function LoWord(L:LongInt) : Word;

Функция

     Возвращает младшее слово L.

Описание

     Это макрорасширение возвращает младшее слово длинного це-
лого  значения.  LoWord  имеется  в  версии  Turbo  Pascal для
Macintosh, однако ее нет в версии для IBM.

Пример

     const MyLongInt = $FFFF0000;
     ...
     MyWord := LoWord(MyLongInt);

     MyWord будет присвоено значение $0000.

Смотрите также

     HiWord                       SwapWord

MakeInteger
──────────────────────────────────────────────────────────────
Объявление

     function MakeInteger( H, L : Byte) : Integer;

Функция

     Конструирует из двух байт целое значение.

Описание

     Помещает H в старший байт результата, а L в младший байт.
Реализация идентична MakeWord.

Пример

     MakeInteger(1,2);

     Возвращает 258 ($0102).

     MakeInteger(255,0);

     Возвращает -256 ($FF00).

Смотрите также

     MakeLongInt                  MakeWord

MakeLongInt
──────────────────────────────────────────────────────────────
Объявление

     function MakeLongInt( H, L : Word) : LongInt;

Функция

     Конструирует из двух слов длинное целое значение.

Описание

     Помещает H в старшее слово результата, а L в младшее сло-
во.

Пример

     MakeLongInt(1,2);

     Возвращает 65538($00010002).

     MakeLongInt(65535,0);

     Возвращает -65535 ($FFFF0000).

Смотрите также

     MakeInteger

MakeWord
──────────────────────────────────────────────────────────────
Объявление

     function MakeWord( H, L : Byte) : Word;

Функция

     Конструирует из двух байт слово.

Описание

     Помещает H в старший байт результата, а L в младший байт.
Реализация идентична MakeInteger.

Пример

     MakeWord(1,2);

     Возвращает 258 ($0102).

     MakeWord(255,0);

     Возвращает 65280 ($FF00).

Смотрите также

     MakeInteger

MaxLong
──────────────────────────────────────────────────────────────
Объявление

     function MaxLong(A, B : LongInt) : LongInt;

Функция

     Возвращает большее из A, B.

Описание

     Это макрорасширение  выполняет знаковое сравнение A и B и
возвращает большее из них.

Пример

     MaxLong(MaxLongInt,0);

     Возвращает MaxLongInt.

     MaxLong(-1,-1000);

     Возвращает -1.

Смотрите также

     MinLong                      MaxWord

MaxWord
──────────────────────────────────────────────────────────────
Объявление

     function MaxWord(A, B : Word) : Word;

Функция

     Возвращает большее из A, B.

Описание

     Это макрорасширение  выполняет знаковое сравнение A и B и
возвращает большее из них.

Пример

     I := MaxWord(12,40000);

     I будет присвоено 40000.

Смотрите также

     MinWord                      MaxLong

MinLong
──────────────────────────────────────────────────────────────
Объявление

     function MinLong(A, B : LongInt) : LongInt;

Функция

     Возвращает меньшее из A, B.

Описание

     Это макрорасширение  выполняет знаковое сравнение A и B и
возвращает меньшее из них.

Пример

     L := MinLong(12,-400000);

     L будет присвоено -400000.

Смотрите также

     MaxLong

MinWord
──────────────────────────────────────────────────────────────
Объявление

     function MinWord(A, B : Word) : Word;

Функция

     Возвращает меньшее из A, B.

Описание

     Это макрорасширение  выполняет знаковое сравнение A и B и
возвращает меньшее из них.

Пример

     I := MinWord(12,40000);

     I будет присвоено 12.

NearCall
──────────────────────────────────────────────────────────────
Объявление

     procedure NearCall(ProcOfs : Word);

Функция

     ProcOfs - это смещение процедуры, вызываемой с помощью
ближнего вызова.

Описание

     Это макрорасширение позволяет вам вызывать  процедуры  из
текущего кодового сегмента,  если: 1) она не имеет параметров,
2) она была откомпилирована в модели NEAR (использовалась  ди-
ректва {$F-}),  и  3)  она не была вложена в другую процедуру.
Это макрорасширение может использоваться для реализации табли-
цы переходов.

Пример

     var MyJumpTable : array[1..10] of Word;
     ...
     NearCall(MyJumpTable[I]);

     Производит ближний вызов процедуры, чье смещение хранится
в таблице.

Смотрите также

     FarCall


Normalized
──────────────────────────────────────────────────────────────
Объявление

     function Normalized(P : Pointer) : Pointer;

Функция

     Возвращает нормализованный указатель P.

Описание

     Это макрорасширение  производит  нормализацию  указателя.
После нормализации значение  смещения  лежит  в  диапазоне  от
$0000 до $000F.

Пример

     P := Normalized(Ptr($0000,$410));

     P будет присвоено $0041:$0000.

     P := Normalized(Ptr($0040,$0113));

     P будет присвоено $0051:$0003.

PtrDiff
──────────────────────────────────────────────────────────────
Объявление

     function PtrDiff(P1,P2 : Pointer) : LongInt;

Функция

     Возвращает число байт, лежащих между P1^ и P2^.

Описание

     Эта процедура  преобразует два сегментных адреса к линей-
ным адресам ( с помощью PtrToLong) и возвращает абсолютное
значение их разности.

Пример

     P1 := Ptr($40,$10);
     P2 := Ptr($41,$01);
     L := PtrDiff(P1,P2);

     L будет присвоено 1 ($40:$10 = $41:$00);

     L := PtrDiff(P2,P1);

     L Будет присвоена 1. Порядок указания параметров не имеет
значения.

Смотрите также

     PtrToLong

PtrToLong
──────────────────────────────────────────────────────────────
Объявление

     function PtrToLong(P : Pointer) : LongInt;

Функция

     Преобразует указатель в диапазоне от $0:$0 до $FFFF:$000F
в длинное целое значение.

Описание

     Эта процедура  производит  преобразование сегментного ад-
реса (указателя) в линейный адрес (длинное целое).  Чаще всего
используется вместе с LongToPtr при выполнении арифметических
операций над указателями. Используется также PtrDiff для вы-
числения числа байт между двумя указателями.

     Линейный адрес вычисляется путем умножения адреса сегмен-
та на 16 ($10) и прибавления к результату смещения.

Пример

     P := Ptr($40,$10);
     L := PtrToLong(P);

     L будет присвоено значение $410.

Смотрите также

     LongToPtr                    PtrDif

Reboot
──────────────────────────────────────────────────────────────
Объявление

     procedure Reboot;

Функция

     Производит перезагрузку системы.

Описание

     Это макрорасширение производит перезагрузку системы.  Оно
сохраняет "магическое значение" - $1234 по  адресу  $40:$72  и
затем осуществляет  переход  по  адресу  $FFFF:$0000.  На всех
компьютерах, совместимых с IBM PC, по данному адресу располол-
жена команда  перехода на процедуры проверки оборудования и на
код начальной загрузки в ПЗУ.

SetByteFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure SetByteFlag(var Flags : Byte; FlagMask : Byte);

Функция

     Устанавливает в Flags бит(ы), определяемые FlagMask.

Описание

     Это макрорасширение устанавливает в Flags все биты, кото-
рые установлены в FlagMask. Заметим, что Flags должен быть пе-
ременным параметром типа Byte.

Пример

     SetByteFlag(BitFlags,$02);

     Устанавливает в Flags бит 1 ($02 = 00000010);

     SetByteFlag(BitFlags,$07);

     Устанавливает в Flags биты 2, 1 и 0 ($07 = 00000111);

Смотрите также

     ByteFlagIsSet                ClearByteFlag

SetFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure SetFlag(var Flags : Word; FlagMask : Word);

Функция

     Устанавливает в Flags бит(ы), определяемые FlagMask.

Описание

     Это макрорасширение устанавливает в Flags все биты, кото-
рые установлены в FlagMask. Заметим, что Flags должен быть пе-
ременным параметром типа Word.

Пример

     SetFlag(BitFlags,$0002);

     Сбрасывает в Flags бит 1 ($0002 = 0000000000000010);

     SetFlag(BitFlags,$0007);

     Сбрасывает в   Flags   биты   2,   1   и   0   ($0007   =
0000000000000111);

Смотрите также

     FlagIsSet                    ClearFlag

SetJump
──────────────────────────────────────────────────────────────
Объявление

     function SetJump(var JumpDest : JumpRecord) : Word;

Функция

     Сохраняет текущее  содержимое регистров SP,  BP и текущий
адрес.

Описание

     Это макрорасширение сохраняет данные о текущем  состоянии
стека и счетчика команд, эти данные в дальнейшем будут исполь-
зоваться для возврата к выполнению  инструкций  с  этой  точки
посредством LongJump.  Обычно  вызов  SetJump  выполняют перед
входом в основной цикл программы. После этого в любой момент,
например, при возникновении ошибки, вы можете вернуться в эту
точку с помощью LongJump.

     Когда в действительности вызывается SetJump,  она возвра-
щает 0 для указания того, что информация сохранена. Если возв-
ращаемое значение не равно 0, то это значение посылаемое в па-
раметре Result функции LongJump. Хотя вы можете игнорировать
результат функции, возможность различать исходный вызов
SetJump и последующие "вызовы" через LongJump довольно удобна,
т.к. позволяет LongJump посылать коды ошибок и другую информа-
цию процедуре, содержащей вызов SetJump.

     Хорошим примером  на использование SetJump и LongJump мо-
жет служить исходный код юниты OPBROWSE.

Пример

     var
        MyJumpRecord : JumpRecord;
        I : Word;
     ...
        I := SetJump(MyJumpRecord);
        if I <> 0 then
           WriteLn('Это JumpDest.JumpPt. Result = ',I);
        { ... некоторые действия ... }
        if I < 10 then
           LongJump(MyJumpRecord,I+1);

     Вызов LongJump  производит  повторное  выполнение с точки
"if I <> 0". При первом вызове SetJump I должно быть присвоено
0, и  оно  будет  увеличиваться после каждого вызова LongJump.
Эта последовательность будет выполняться, пока I будет меньше
10.

Смотрите также

     LongJump

SetLongFlag
──────────────────────────────────────────────────────────────
Объявление

     procedure SetLongFlag(var Flags : LongInt;
                             FlagMask : LongInt);

Функция

     Устанавливает в Flags бит(ы), определяемые FlagMask.

Описание

     Это макрорасширение устанавливает в Flags все биты, кото-
рые установлены в FlagMask. Заметим, что Flags должен быть пе-
ременным параметром типа LongInt.

Пример

     SetLongFlag(BitFlags,$00000002);

     Сбрасывает в Flags бит 1
     ($00000002 = 00000000000000000000000000000010);

     SetLongFlag(BitFlags,$00000007);

     Сбрасывает в Flags биты 2, 1 и 0
     ($00000007 = 00000000000000000000000000000111);

Смотрите также

     LongFlagIsSet                ClearLongFlag

SwapNibble
──────────────────────────────────────────────────────────────
Объявление

     function SwapNibble(B : Byte) : Byte;

Функция

     Меняет местами половинки байт.

Описание

     Эта процедура аналогична встроенной  процедуре  Swap,  но
вместо того,  чтобы  менять  местами старший и младший байты в
слове, она меняет местами старшую и  младшую  половинки  байта
(по 4 бита).

Пример

     SwapNibble($F0);

     Вернет $0F (00001111, $F0 = 11110000).

     SwapNibble($81);

     Вернет $18 (00011000, $81 = 10000001).

SwapWord
──────────────────────────────────────────────────────────────
Объявление

     function SwapWord(L : LongInt) : LongInt;

Функция

     Меняет местами  старшее  и  младшее слово длинного целого
значения.

Описание

     Эта процедура аналогична встроенной  процедуре  Swap,  но
меняет местами не старший и младший байт в слове,  а старшее и
младшее слово в длинном целом.

Пример

     SwapWord($FFFF0000);

     Возвращает $0000FFFF.

     SwapWord($12345678);

     Возвращает $56781234.
Смотрите также



        F. OPSORT: Процедура для сортировки в памяти.

     Сортировка часто   выполняется   различными  программами.
Используется для сортировки адресов в алфавитном порядке и для
сортировки наборов чисел для статистики.

    Object Professional  предоставляет вам быстрые и простые в
использовании процедуры сортировки.  С их  помощью  вы  можете
отсортировать до  65535  элементов данных любого типа.  Однако
все элементы должны  располагаться  в  обычной  памяти.  Юнита
OPSORT достаточно  компактна  и  использует меньше 2000 байт в
кодовом сегменте.  Она реализует нерекурсивный алгоритм сорти-
ровки, который также минимально использует стек.

     Если вы  видели систему сортировки DataBase ToolBox фирмы
Borland, то использование OPSORT не составит  для  вас  труда,
поскольку они организованы одинаково. OPSORT отличается только
по реализации.  Как мы уже упоминали, OPSORT не производит за-
полнение на диск, вместо этого вам предоставляется быстрая бо-
лее компактная функция, подходящая в большинстве случаев.
OPSORT имеет специальный режим для сортировки строк - вместо
выделения памяти для строк максимальной длины он выделяет па-
мять только по действительной длине строки. Использование ука-
зателей на процедуры делает процесс сортировки динамичным,
поскольку с помощью одного набора процедур OPSORT может произ-
водит сортировку данных различных типов в одной и той же прог-
рамме.

     OPSORT поддерживает  три  процедуры:  Sort,  PutElement и
GetElement. Первой ваша программа должна вызывать  Sort.  Sort
требует несколько параметров,  которые описаны ниже. Два пара-
метра сообщают OPSORT размер элемента данных и их максимальное
количество. Три  параметра определяют имена процедур,  которые
должны использоваться Sort во время выполнения сортировки. Од-
на из  них  загружает  элемент  данных во внутренние структуры
Sort, одна используется для сравнения двух элементов данных, и
третья используется  для  возврата отсортированных результатов
вашей программе.

     Процедуры для загрузки получения элементов  вызывают  две
другие процедуры OPSORT. Для сортировки элемента его необходи-
мо загрузить с помощью PutElement. Для получения отсортирован-
ного элемента нужно использовать GetElement.

     Ниже приведен пример программы, производящей сортировку
целых чисел:

     program Sorting  {EXSORT.PAS}
        { Сортировка случайного набора целых чисел }
     uses
        OpSort;
     const
        NumToSort = 1000;
     var
        Status : SortStatus;

     {$F+}
     procedure GetInts;
     { Загружает  структуры  данных  параметрами  сортируемого
        элемента. }
     var
        W : Word;
        Value : Integer;
     begin
        for N := 1 to NumToSort do begin
        Value := Random(MaxInt);
        if not PutElement(Value) then
           { ошибка. Чаще всего из-за недостатка памяти }
           Exit;
        end;
     end;

     function Less(var X,Y) : Boolean;
        { Сравнивает два целых значения }
     var
        X1 : Integer absolute X;
        Y1 : Integer absolute Y;
     begin
        Less := (X1 < Y1);
     end;

     procedure WriteInts;
        { Выводит отсортированные значения }
     var
        Value : Integer;
     begin
        while GetElement(Value) do
           WriteLn(Value);
     end;
     {$F-}

     begin
        Status := Sort(NumToSort,Sizeof(Integer),GetInts,
                       Less,WriteInts);
        case Status of
           SortSuccess : WriteLn('Отсортировано',ElementSorted,
                                 'элементов');
           SortOutOfMemory: WriteLn('Нехватает памяти');
           SortTooManyElements : WriteLn('Слишком много элементов');
        end;
     end.

     Смотрите следующие разделы.

          OPSORT и управление распределение памяти.

     Обычно OPSORT  использует специальную технику использова-
ния Mark/Reliase для быстрого освобождения памяти без разруше-
ния списка свободных областей системы управления распределени-
ем памяти Turbo.  Эта техника работает до тех пор, пока проце-
дуры, вызываемые OPSORT, не производят выделения или освобож-
дения памяти в "куче" во время выполнения сортировки. Если вам
это необходимо, то вам придется изменить исходный текст
OPSORT. Мы сделали так, чтобы это изменение было очень
простым. Все что вы должны сделать, это отменить определение
переменной времени трансляции FastDispose в юните
OPDEFINE.INC, и перекомпилировать OPSORT.

                            Типы.

     GetPutProc = procedure;

     Процедура используемая для загрузки и получения сортируе-
мых элементов.

     SortStatus =
        (SortSuccess,            { Успешная сортировка }
         SortOutOfMemory,        { Нехватает памяти }
         SortTooManyElements);   { Попытка сортировки большего
                                   числа элементов, чем указано }

     Функция Sort возвращает значение типа SortStatus. Вызыва-
ющая программа должна проверять результат для определения неу-
дачной попытки сортировки.

     UserLessFunc = function(var X,Y) : Boolean;

     Функция сравнения двух элементов.

                         Переменные.

     ElementsSorted : Word;

     После завершения сортировки в  переменную  ElementsSorted
заносится число, определяющее число отсортированных элементов.

GetElement
──────────────────────────────────────────────────────────────
Объявление

     function GetElement(var X) : Boolean;

Функция

     Получает следующий элемент из отсортированного массива.

Описание

     Для получения  каждого  элемента отсортированного массива
необходимо вызвать функцию GetElement после завершения сорти-
ровки. Ваша прикладная программа может вызывать GetElement из
процедуры получения отсортированных элементов, имя которой вы
передаете в качестве параметра функции Sort.

     Т.к. OPSORT  не знает тип ваших данных,  переменный пара-
метр функции GetElement не имеет типа.  Вы ответственны за пе-
редачу переменной  соответствующего  типа.  OPSORT  определяет
число байт, которое необходимо вернуть с помощью параметра,
передаваемого функции Sort.

     GetElement возвращает  True,  пока  имеются еще элементы.
Если она возвращает False, значит параметр X не определен.

Пример

     while GetElement(S) do
        WriteLn(S);

     В данном  примере  отсортированные  элементы просто выво-
дятся на экран.

Смотрите также

     Sort

PutElement
──────────────────────────────────────────────────────────────
Объявление

     function PutElement(var X) : Boolean;

Функция

     Помещает элемент в сортируемый массив.

Описание

     Вызов PutElement добавляет элемент к внутренней структуре
сортировки OPSORT.  Ваша прикладная программа должна использо-
вать PutElement в процедуре загрузки, имя которой вы посылаете
в качестве параметра функции Sort.

     Т.к. OPSORT не знает тип ваших данных, параметр передава-
емый PutElement не имеет типа. Поэтому вы не можете передавать
константу или выражение.  Однако, параметр может быть перемен-
ной любого типа: простой числовой элемент, указатель на другую
структуру, строка  переменной  длины,  в  общем  любого  типа.
OPSORT определяет длину элементра в байтах на основе исходного
вызова Sort.

     PutElement возвращает True, если элемент успешно добавлен
к сортируемому массиву. Если PutElement возвращает False,
прикладная программа должна прекратить добавлять элементы и
выйти из процедуры загрузки. PutElement возвращает False в
случае, если для нового элемента не хватает памяти, или если
номер элемента превышает число, которое было передано Sort.

Примеры

     while not Eof(F) do begin
        ReadLn(F,S);
        if not PutElement(S) then
           Exit;
     end;

     В данном примере из текстового файла считываются строки и
добавляются к сортируемому массиву. Если PutElement возвращает
False, выполнение процедуры занесения элементов прекращается.

     for I := 1 to NumPointers do
        if not PutElement(P[I]) then
           Exit;

     В этом примере P - это массив указателей на другую струк-
туру данных. В сортируемый массив добавляются указатели а не
сами записи, чтобы использовать меньше места. Функции сравне-
ния, написанные пользователем, могут произвести разрешение
ссылок и сравнивать сами элементы структур.

Смотрите также

     Sort

Sort
──────────────────────────────────────────────────────────────
Объявление

     function Sort(Elements,ElementSize : Word;
                   GetElements : GetPutProc;
                   LessFunc : UserLessFunc;
                   PutElements : GetPutProc) : SortStatus;

Функция

     Сортирует набор элементов.

Описание

     Sort - это основная процедура OPSORT. Прикладная програм-
ма должна вызвать Sort до вызова всех остальных процедур.

     Sort сделана таким образом, чтобы полностью настраиваться
во время выполнения. В пределах доступного объема памяти Sort
может производит сортировку массивов максимум из 65535 элемен-
тов любого типа путем вызова процедур написанных пользователем
для загрузки, выгрузки и сравнения элементов. Sort сохраняет
все элементы в памяти. Этим достигается большая скорость сор-
тировки, чем при использовании виртуальной сортировки, и этого
достаточно в большинстве случаев.

     Первые два  параметра Sort сообщают общее число элементов
и размер каждого элемента. Параметр Elements определяет макси-
мальное число элементов.  Если доступны несколько элементов, в
этом нет проблемы.  Если будет передано большее число, то воз-
никнет ошибка сортировки.

     Во всех, кроме одного особого случая, ElementSize опреде-
ляет число байт в каждом  сортируемом  элементе.  Этот  размер
лучше всего  получать  с  помощью  встроенного оператора Turbo
Pascal SizeOf.  Например  SizeOf(Pointer)  возвращает   4,   а
SizeOf(MyDataType) возвратит число байт, занимаемых переменной
данного типа.  Для строк используется особый случай.  Если  вы
укажете ElementSize равным 0, то Sort будет рассматривать каж-
дый элемент как строку в формате Turbo Pascal и будет выделять
место под  каждую  строку  в  зависимости от ее действительной
длины.

     Программы, использующие OPSORT,  должны быть особым обра-
зом структурированы,  как  показано в примере в начале данного
раздела. В прикладной программе  должны  быть  определены  три
процедуры, имена которых передаются функции Sort.

     {$F+}
     procedure GetSortElements;
        { Загружает элементы в процедуру Sort }
     begin
        ...
        if not PutElement(X) then
           Exit;
        ...
     end;

     procedure PutSortElements;
        { Получает отсортированные элементы }
     begin
        ...
        while GetElement(X) do
           { Использовать элемент X }
        ...
     end;

     function Less(var X,Y) : Boolean;
     begin
        { Возвращает результат  X < Y }
     end;
     {$F-}

     Заметим, что и процедуры и функция должны  быть  того  же
типа и получать те же параметры, как и те, что приведены выше.
(Имена процедур не важны).  Они должны быть глобальными - т.е.
не должны быть вложены в другие процедуры, и должны компилиро-
ваться в модели FAR. Для данного примера Sort должна быть выз-
вана следующим образом:

     Status := Sort(Elements,ElementSize,GetSortElements,Less,
                    PutSortElements);

     После инициализации и проверки некоторых ошибок Sort  вы-
зовет вашу  функцию  GetSortElements.  GetSortElements  в свою
очередь занесет все элементы во внутренние структуры OPSORT  с
помощью функции PutElement. После завершения GetSortElements
Sort производит саму сортировку. При необходимости Sort срав-
нить два элемента она использует вашу функцию Less. Less про-
изводит сравнение элементов любого типа и возвращает True,
если первый элемент X меньше, чем второй элемент Y. После за-
вершения сортировки Sort вызывает вашу функцию
PutSortElements, которая вызывая GetElement получает отсорти-
рованные элементы. После завершения PutSortElements Sort осво-
бождает захваченную память и возвращает статус вызывающей
программе. Коды, возвращаемые Sort, вы найдете в описании
SortStatus.

Пример

     Смотрите пример программы в начале данного раздела.


                       15. Приложения.

      A. Что нового появилось в Object Professional 1.0.

     Этот раздел    предназначен    для    владельцев    Turbo
Professional и содержит обзор отличий между ним и Object
Professional. Если вы не являетесь владельцем Turbo
Professional, вы можете пропустить данный раздел. При написа-
нии данного раздела мы ориентировались на различия между
Object Professional и Turbo Professional 5.0, однако пользова-
тели Turbo Professional 4.0 также найдут здесь для себя много
интересного.

     Полный список новых возможностей Object Professional  мо-
жет занять несколько страниц, однако мы отметим основные:

     - базовые классы:  стеки, очереди, связные списки, наборы
       бит, словари строк;
     - объектно-ориентированный ввод/вывод на диск;
     - произвольный доступ к библиотекам классов;
     - большие массивы,  использующие ОЗУб диск или EMS, в за-
       висимости от наличия памяти;
     - программа  управления подкачиваемыми резидентными прог-
       раммами, занимающими в памяти только 6К;
     - подкачиваемая функция Exec;
     - низко и высокоуровневое управление принтером;
     - настраиваемые печатаемые отчеты;
     - окна,  которые можно двигать, можно изменять их размер,
       и восстанавливать к исходному;
     - очень мощная поддержка мыши;
     - просмотр текстовых и двоичных файлов;
     - полное оконное редактирование файлов (перенос слов, по-
       иск/замена, блоковые операции);
     - списки маршрутов;
     - служебная программа типа MAKEMENU, для разработки экра-
       нов ввода данных;

     В данном списке приведены только основные расширения, од-
нако имеется  очень много мелких,  особенно в юнитах,  относя-
щихся к управлению выводом на экран (том 1) и  к  вводу/выводу
данных (том 2).

     Перед тем,  как  мы перейдем к рассмотрению новых или из-
менненных юнит, мы приводим список юнит, которые или вообще
остались неизменными, или были минимально изменены:

     OP8087
     OPASCIIZ
     OPBCD
     OPCRT
     OPDATE
     OPDOS
     OPEMS
     OPENHKBD
     OPERRHAN
     OPEXTMEM
     OPINLINE
     OPINT
     OPMACED
     OPMACRO
     OPMOUSE
     OPSORT
     OPSTRDEV
     OPSTRING
     OPTSR

     Имена были изменены для сохранения стиля,  однако большая
часть этих юнит осталась той же,  что и в TPxxx аналогах,  или
содержит расширенный набор функций.  Имеется одно исключение в
OPCRT, т.к.   все   функции   вывода   в   окна    из    TPCRT
(FastWriteWindow, FastReadWindow,  и  т.д.)  теперь включены в
OPWINDOW.

     Следующие юниты Turbo Professional были исключены или по-
тому что они в Object Professional не нужны,  или если их воз-
можности были включены в другие юниты (показаны в скобках):

     TPCMDLIN
     TPEARRAY (OPLARRAY)
     TPINT24
     TPMEMCHK (OPROOT)
     TPRARRAY (OPLARRAY)
     TPSCREEN
     TPVARRAY (OPLARRAY)

     Так же были исключены несколько демонстрационных программ
Turbo Professional:

     BSORT
     DIFF
     PCALC
     PREF
     PTRPT
     REP
     TFIND
     VBROWSE
     WINEXMPL

     BSORT, DIFF, REP и TFIND были исключены, чтобы освободить
место для других программ,  иллюстрирующих  технологию  объек-
то-ориентированного программирования и/или использования новых
юнит. (Все эти четыре программы легко могут быть преобразованы
для Object Professional, однако для этого нет причин). Возмож-
ности PREF и PCALK включены в DESPOP.  PTIME была изменена для
исключения необходимости  в  PTRPT.  WINEXMPL  была  исключена
вместе с TPSCREEN.  И VBROWSE была заменена BROWSE.  Остальные
демонстрационные программы  Turbo Professional:  BEST,  ENTRY,
MAKEHELP, MAKEMENU,  MEMO,  PTIME,  SMACS и WINDOW остались  в
Object Professional в несколько измененном виде.

     Следующие юниты   базируются  на  соответствующих  юнитах
Turbo Professional,  однако  были  полностью  переписаны   для
использования объектов:

     OPCMD
     OPDIR
     OPEDIT
     OPENTRY
     OPHELP
     OPLARRAY
     OPMEMO
     OPMENU
     OPPICK
     OPWINDOW

     OPLARRAY комбинирует в себе функции из TPEARRAY, TPRARRAY
и TPVARRAY.  OPCMD  базируется  на TPCMD,  недокументированной
юните, которая секретно используется в нескольких юнитах Turbo
Professional. OPMEMO базируется на TPMEMO, которая была введе-
на в Turbo Professional 5.02.

     Ниже приведены большей частью новые юниты:

     OPABSFLD
     OPBROWSE
     OPCLONE
     OPCOLOR
     OPDEVICE
     OPEDITOR
     OPEXEC
     OPFEDIT
     OPFIELD
     OPFORM
     OPFRAME
     OPPRINT
     OPPRNLOW
     OPREPLAY
     OPROOT
     OPSEDIT
     OPSELECT
     OPSWAP
     OPSWAP1

     OPABSFLD, OPFEDIT,  OPFIELD,  OPSELECT и OPSEDIT содержат
элементы из TPENTRY и/или TPEDIT.  OPFRAME базируется на части
кода TPWINDOW.  OPROOT содержит часть кода из TPMEMCHK, однако
все остальное в данной юните новое. OPREPLAY - это просто об-
резанная копия OPMACRO, которая в основном идентична TPMACRO.
OPCLONE в основном базируется на TPCLONE, юните находящейся на
диске BONUS Turbo Professional. OPCOLOR сравнима с COLORDEF,
другой юнитой с диска BONUM (написана не нами). OPBROWSE и
OPEXEC базируются на юните из Turbo Analyst (EXECSWAP и
BROWSE). Остальные юниты написаны с самого начала.

     И ниже приведены новые демонстрационные программы:

     BROWSE
     DESKPOP
     DPINST
     EDITOR
     FORMTEST
     POPHELP
     PSCREEN
     MAKESCRN

     POPHELP базируется на GUIDE - встроенной программе выдачи
справочной информации, которая была добавлена к Turbo
Professional 5.07. Однако в отличие от GUIDE, POPHELP постав-
ляется с исходными кодами и может рассматриваться как де-
монстрационная программа. PSCREEN - это измененная программа с
тем же именем, которую вы можете найти на диске BONUS. За иск-
лючением некоторых частей DESKPOP все остальные программы но-
вые.

     Это наиболее заметные изменения в пакете,  однако если вы
просмотрите справочные разделы руководства, вы обнаружите мно-
жество новых вещей. И пожалуйста на пропускайте обзоры в нача-
ле каждой главы. В некоторых случаях документация практически
не изменилась, однако в некоторых местах приводится новая и
важная информация, касающаяся использования определенных юнит.



                B. Зависимости между юнитами.

     Ниже приведен   список   всех   юнит   библиотеки  Object
Professional и низкоуровневых юнит, от которых они зависят
(если такие есть). Юниты, которые могут использоваться в воер-
леях оверлейной системы Turbo Pascal, помечены символом звез-
дочка ('*'). Значение чисел, которые сопровождают некоторые
юниты приведено в разделе Legend. Список файлов с исходными
текстами каждой юниты вы найдете в разделе зависимостей в фай-
ле OPRO.MAK.

     OP8087
        нет зависимостей

     OPABSFLD *
        DOS, OPINLINE, OPSTRING, OPROOT, OPDATE (3), OPBCD (4)

     OPASCIIZ *
        OPSTRING

     OPBCD *
        нет зависимостей

     OPBROWSE *
        DOS, OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2),
        OPCMD, OPDOS, OPFRAME, OPWINDOW

     OPCLONE *
        DOS, OPINLINE, OPSTRING, OPROOT

     OPCMD
        OPINLINE, OPCRT, OPMOUSE (2), OPROOT

     OPCOLOR
        нет зависимостей

     OPCRT
        DOS, CRT (1), OPINLINE

     OPDATE *
        DOS, OPINLINE, OPSTRING

     OPDEVICE *
        DOS, OPINLINE, OPSTRING, OPROOT, OPDOS, OPPRNLOW,
        OPPRINT

     OPDIR *
        DOS, OPINLINE, OPSTRING, OPDOS, OPROOT, OPCRT,
        OPMOUSE (2),  OPDATE (3),  OPCMD,  OPFRAME,  OPWINDOW,
        OPPICK

     OPDOS *
        DOS, OPSTRING

     OPEDIT *
        OPINLINE, OPSTRING, OPROOT, OPSRT, OPMOUSE (2), OPCMD,
        OPDATE (3), OPBCD (4), OPABSFLD, OPFEDIT, OPFIELD

     OPEDITOE *
        DOS, OPINLINE, OPSTRING, OPDOS, OPROOT, OPMOUSE (2),
        OPCMD, OPFRAME, OPWINDOW, OPMEMO

     OPEMS
        нет зависимостей

     OPENHKBD
        нет зависимостей

     OPENTRY *
        OPINLINE, OPCTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD,
        OPDATE (3), OPBCD (4), OPASSFLD, OPFEDIT, OPFIELD,
        OPFRAME, OPWINDOW, OPPICK (5), OPSELECT

     OPERRHAN
        DOS

     OPEXEC
        DOS

     OPEXTMEM *
        нет зависимостей

     OPFEDIT *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2),
        OPDATE (3), OPBCD (4), OPCMD, OPABSFLD, OPFIELD (6)

     OPFIELD *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2),
        OPDATE (3), OPBCD (4), OPCMD, OPFEDIT (6)

     OPFORM *
        DOS, OPINLINE, OPSTRING, OPROOT, OPDOS, OPDATE (3),
        OPBCD, OPABSFLD, OPPRNLOW, OPDEVICE, OPPRINT

     OPFRAME *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD

     OPHELP *
        DOS, OPINLINE, OPSTRING, OPROOT, OPDOS, OPCRT, OPCMD,
        OPFRAME, OPWINDOW, OPMOUSE (2), OPPICK

     OPINLINE
        нет зависимостей

     OPINT
        DOS

     OPLARRAY *
        DOS, OPINLINE, OPSTRING, OPDOS, OPROOT, OPEMS

     OPMACED *
        DOS, OPINLINE, OPCRT, OPMOUSE (2), OPROOT, OPCMD,
        OPINT, OPMACRO

     OPMACRO
        DOS, OPINT

     OPMEMO *
        DOS, OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2),
        OPCMD, OPFRAME, OPWINDOW

     OPMENU *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD,
        OPFRAME, OPWINDOW

     OPMOUSE
        OPCRT

     OPPICK *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD,
        OPFRAME, OPWINDOW

     OPPRINT *
        DOS, OPINLINE, OPSTRING, OPROOT, OPDOS, OPPRNLOW

     OPPRNLOW
        DOS, OPINLINE, OPROOT, OPDOS

     OPREPLAY
        нет зависимостей

     OPROOT
        DOS, OPINLINE, OPSTRING

     OPSEDIT *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD

     OPSELECT
        DOS, OPINLINE, OPSRING, OPROOT, OPCRT, OPMOUSE (2),
        OPCMD, OPASSFLD, OPFIELD, OPFRAME, OPWINDOW

     OPSORT *
        нет зависимостей

     OPSTRDEV
        нет зависимостей

     OPSTRING
        нет зависимостей

     OPSWAP
        OPSWAP1

     OPSWAP1
        DOS, OPINLINE

     OPTSR
        DOS, OPINLINE, OPINT

     OPWINDOW *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD,
        OPFRAME

     Премиальные юниты:

     OPCAL *
        OPINLINE, OPSTRING, OPROOT, OPCRT, OPMOUSE (2), OPCMD,
        OPFRAME, OPWINDOW, OPPICK, OPDATE

     OPCAALC *
        DOS, OPBCD, OPINLINE, OPSTRING, OPROOT, OPCRT, OPCMD,
        OPMOUSE (2), OPFRAME, OPWINDOW

     OPQKREF
        DOS, OPSTRING, OPINLINE, OPROOT, OPCRT, OPMOUSE (2),
        OPCMD, OPFRAME, OPWINDOW

     Legend

     1. {$IFDEF UseCrt}
     2. {$IFDEF UseMouse}
     3. {$IFDEF UseDates}
     4. {$IFDEF UseBCD}
     5. {$IFDEF PickListFields}
     6. Циклическая зависимость



                    C. Иерархия объектов.

     Ниже приведен  список объектов библиотеки объектов Object
Professional, а также производные от них объекты.  Только  два
объекта вообще  не  имеют  родителей  -  ColorSet и Root.  Все
остальные объекты являются производными от Root. Сдвиг опреде-
ляет, что  данный  объект является непосредственно производным
объектом от первого объекта, расположенного выше и имеющего на
один уровень сдвига меньше. В правой колонке приводится юнита,
в которой объявляется каждый объект. Занчения чисел, сопровож-
дающих некоторые  имена  объектов,  приведены в разделе Legend
ниже.

     Объекты, помеченные символом звездочка ('*'), предназна-
чены для внутреннего использования и не описаны в деталях.
Доступ к ним осуществляется через методы объектов более высо-
кого уровня. Объекты для работы с полями
(StringField..TimeField, StringPrintField..LineField) описаны
по группам в соответствующих юнитах.

     ColorSet                            OPCRT
     Root                                OPROOT
        PointerStack                     "
           WindowSrack                   OPWINDOW
        ByteStack*                       OPPRINT
        StatusQueue                      OPROOT
        SingleListNode                   OPROOT
           TextField                     OPFIELD
           PrintMode                     OPPRINT
           FielListNode*                 OPFORM
           PrintBlock                    "
           PrintPage                     "
           PrintedForm                   "
        DoubleListNode                   OPROOT
           HeaderNode*                   OPFRAME
           ShadowNode* (1)               "
           HotNode* (2)                  "
           MenuItemNode                  OPMENU
           AbstractField                 OPABSFLD
              SelectField                OPFIELD
              StringField                "
              ArrayField                 "
              CharField                  "
              BooleanField               "
              YesNoField                 "
              LongIntField               "
              WordField                  "
              IntegerField               "
              ByteField                  "
              ShortIntField              "
              RealField                  "
              BcdField (4)               "
              ExtendedField (5)          "
              DoubleField (5)            "
              SingleField (5)            "
              CompField (5)              "
              DateField (6)              "
              DateStField (6)            "
              TimeField (6)              "
              ChoiceField*               "
              NestedField*               "
              MultyLineField*            "
              PickField* (7)             OPENTRY
           PrintField                    OPFORM
              StringPrintField           "
              CharPrintField             "
              WordPrintField             "
              BooleanPrintField          "
              YesNoPrintField            "
              LongPrintField             "
              IntPrintField              "
              BytePrintField             "
              ShortPrintField            "
              RealPrintField             "
              BCDPrintField (4)          "
              ExtPrintField (5)          "
              DblPrintField (5)          "
              SglPrintField (5)          "
              CompPrintField (5)         "
              DatePrintField (6)         "
              TimePrintField (6)         "
              LineField                  "
                 ShadedField             "
        SingleList                       OPROOT
        DoubleList                       OPROOT
           CircularList                  "
              MenuItemList*              OPMENU
        BitSet                           OPROOT
           LargeBitSet                   "
        StringDict                       "
           StringSet                     "
        StringArray                      "
        AbstractArray                    OPLARRAY
           RamArray                      "
              RamRCArray                 "
           EmsArray                      "
              EmsRCArray                 "
           VirtualArray                  "
              PrimitiveArray             "
              VirtualRCArray             "
           OpArray                       "
        DirEntry                         OPROOT
        IdStream                         "
           DosIdStream                   "
              BufIdStream                "
                 Library                 "
           MemIdStream                   "
              MemLibrary                 "
        CommandProcessor                 OPCMD
        CommandPacker                    "
        Cloner                           OPCLONE
        ScrollBar* (3)                   OPFRAME
        ScreenRect                       "
        LoadableColorSet                 OPWINDOW
        PackedWindow                     "
        VirtScreen                       "
        LineEditor                       OPEDIT
        SimpleLineEditor                 OPSEDIT
        AbstractFrame*                   OPFRAME
           Frame                         "
        AbstractWindow*                  OPWINDOW
           RawWindow                     "
        SubMenu*                         OPMENU
        StackWindow                      OPWINDOW
           CommandWindow                 "
              Browser                    OPBROWSE
              Memo                       OPMEMO
                 MemoFile                "
                    TextEditor           OPEDITOR
              Menu                       OPMENU
              PickList                   OPPICK
                 DirList                 OPDIR
                 PathList                "
                 AbstractHelpWindow      OPHELP
                    PagedHelpWindow      "
                    ScrollingHelpWindow  "
              AbstractSelector           OPSELECT
                 Selector                "
                    ScrollingSelector    "
                 EntryScreen             OPENTRY
                    ScrollingEntryScreen "
        BasePrinter                      OPPRNLOW
           DosPrinter                    "
           FlexiblePrinter               "
              BiosPrinter                "
        Printer                          OPPRINT
        Report                           OPFORM

     Legend

     Соответствующие объекты объявлены,  только если следующие
определения активизированы.

     1. {$IFDEF UseShadows}
     2. {$IFDEF UseHotSpots}
     3. {$IFDEFUseScrollBars}
     4. {$IFDEF UseBCD}
     5. {$IFOPT N+}
     6. {$IFDEF UseDates}
     7. {$IFDEF PickListFields}


     5>







                       D. Коды ошибок.

     Object Professional во всех библиотеках использует после-
довательный набор правил для определения и возврата кодов оши-
бок. Полное описание данной системы сопровождает OPROOT (Глава
8, раздел В.8), где объявлены связанные с кодами константы:

     Коды ошибок хранятся в переменной типа Word.  Каждый  код
вычисляется как  сумма двух частей:  префикса ошибки,  который
обычно умножается на 10000,  и  кода  ошибки,  который  всегда
меньше 10000. Тип ошибки определяется как префикс ошибки деле-
ный на 10000. Таким образом, по коду ошибки вы можете опреде-
лить ее тип и код, используя следующие операторы:

     ErrorType   := Code div 10000;
     ErrorNumber := Code mod 10000;

     или составить код ошибки обратно:

     Code := (10000 *ErrorType) + ErrorNumber;

     Тип ошибки используется программой для определения  реак-
ции на возникшие обстоятельства,  т.е.  нужно ли завершать вы-
полнение программы,  запросить команду, вывести предупреждение
и повторить и т.д.  Смотрите главу 8, раздел В.8. Имеется пять
типов ошибок и префиксов:

     { Тип ошибки }
     etFatal       = 0;    { Неисправимая ошибка }
     etNonFatal    = 1;    { Исправимая ошибка ввода/вывода }
     etWarning     = 2;    { Сообщения, ошибка пользователя ...}
     etMessage     = 3;    { Просто сообщение }
     etNoError     = 4;    { Не ошибка }

     { Префиксы }
     epFatal       = etFatal    * 10000;
     epNonFatal    = etNonFatal * 10000;
     epWarning     = etWarning  * 10000;
     epMessage     = etMessage  * 10000;

     Номера ошибок  предоставляют  более  точную информацию об
ошибке и обычно ее достаточно для определения причины возник-
новения ошибки. Младшие номера ошибок в диапазоне от 2 (Не
найден файл) до 162 (сбой), аналогичны номерам ошибок ввода
вывода Turbo Pascal. Остальные ошибки сведены в блоки по 1000
кодов, каждый блок представляет определенную категорию ошибок:

     0000-0999     Ошибки Dos, Turbo Pascal, Критические ошиб-
                   ки DOS
     1000-1999     Остальные ошибки ввода/вывода, включая от-
                   носящиеся к потокам
     2000-2999     Ошибки среды или недостаток места
     7000-7999     Предупреждения, ошибки пользователя
     8000-8999     Программные ошибки
     9000-9999     Сообщения

     Ниже приведен полный список кодов ошибок. Если вы получи-
те один из этих номеров после вызова метода определенного объ-
екта, внимательно просмотрите описание данного метода. Мы
настоятельно рекомендуем использовать коды ошибок по именам а
не по кодам.

      Ошибки DOS, Turbo Pascal, критические ошибки DOS.

     { Ошибки DOS }
     ecFileNotFound    = 00002;  { Не найден файл }
     ecPathNotFound    = 00003;  { Не найден маршрут }
     ecTooManyFiles    = 00004;  { Слишком много открытых файлов }
     ecAccessDenied    = 00005;  { Запрещен доступ к файлу }
     ecInvalidHandle   = 00006;  { Неверный номер файла }
     ecOutOfMemory     = 00008;  { Нехватает памяти }
     ecInvalidDrive    = 00015;  { Неверный дисковод }
     ecNoMoreFiles     = 00018;  { Нет больше файлов }

     { Ошибки ввода/вывода Turbo Pascal }
     ecDiskRead        = 00100;  { Попытка чтения за концом
                                   файла }
     ecDiskFull        = 00101;  { Нет места на диске }
     ecNotAssigned     = 00102;  { Файл не связан (Assign) }
     ecNotOpen         = 00103;  { Файл не открыт }
     ecNotOpenInput    = 00104;  { Файл не открыт для ввода }
     ecNotOpenOutput   = 00105;  { Файл не открыт для вывода }
     ecInvalidFormat   = 00106;  { Неверный формат для упаковки
                                   окна }

     { Критические ошибки DOS }
     ecWriteProtected  = 00150;  { Диск защищен от записи }
     ecUnknownUnit     = 00151;  { Неизвестное дисковое устр-во }
     ecDriveNotReady   = 00152;  { Дисковод не готов }
     ecUnknownCommand  = 00153;  { Неизвестная команда }
     ecCrcError        = 00154;  { Ошибка данных }
     ecBadStructLen    = 00155;  { Неверная длина требуемой
                                   структуры }
     ecSeekError       = 00156;  { Ошибка поиска }
     ecUncnownMedia    = 00157;  { Неизвестный тип носителя }
     ecSectorNotFound  = 00158;  { Не найден сектор на диске }
     ecOutOfPaper      = 00159;  { В принтере нет бумаги }
     ecDeviceWrite     = 00160;  { Ошибка записи устройства }
     ecDeviceRead      = 00161;  { Ошибка чтения устройства }
     ecHardwareFailure = 00162;  { Сбой устройства }

      Остальные ошибки ввода/вывода, включая потоковые.

     { Возвращает OPBROWSE и OPEDITOR }
     ecFilesEmpty      = 01000;  { Файл пуст }

     { Возвращает OPROOT.IdStream }
     ecIdUnknown       = 01101;  { Чтение из потока объекта с
                                   неизвестным идентификатором }
     ecLoadFiled       = 01102;  { Ошибка в конструкторе Load,
                                   при вызове Get или GetPtr }
     ecInvalidData     = 01103;  { Попытка чтения/записи не-
                                   верных данных }

     { Возвращает OPROOT.Library }
     ecNameBlank       = 01200;  { Не могу добавить элемент с
                                   пустым именем }
     ecPackFailed      = 01201;  { Ошибка упаковки библиотеки }
     ecBadSignature    = 01202;  { Неверная сигнатура в директо-
                                   рии }

              Ошибки среды или недостаток места.

     { Возвращает OPROOT.StaticQueue }
     ecQueueFull       = 02000;  { Очередь заполнена. Новый
                                   элемент отвергается }
     ecQueueEmpty      = 02001;  { Очередь пуста. Элемент не
                                   возвращается }

     { Возвращает OPROOT.Library }
     ecDirectoryFull   = 02020;  { Директория заполнена, не
                                   могу добавить элемент }

     { Возвращает OPCMD }
     ecPartialMatch    = 02050;  { Не могу добавить команду
                                   из-за частичного совпадения }
     ecKeyTableFull    = 02051;  { Не могу добавить команду, т.к.
                                   таблица полностью заполнена }

     { Возвращает OPLARRAY }
     ecInsuffisientEms = 02100;  { Не хватает для выделения
                                   памяти EMS }
     ecEmsAllocation   = 02101;  { Ошибка при выделении страницы
                                   памяти EMS }
     ecNoEms           = 02102;  { Нет EMS }
     ecEmsPageMapping  = 02103;  { Ошибка отображения страниц
                                   EMS }
     ecCantFreeEms     = 02104;  { Не могу освободить дескриптор
                                   EMS }

     { Возвращает OPDIR }
     ecDirTooBig       = 02200;  { Слишком много файлов, чтобы
                                 поместиться в буфер директории }

               Сообщения и ошибки пользователя.

     { Возвращают OPFIELD, OPSELECT, OPENTRY }
     ecFieldRequired   = 07000;  { Требуется поле }
     ecBadFormat       = 07001;  { Неверный формат число/время/
                                   /дата и т.д. }
     ecOutOfRange      = 07002;  { Введенное значение выходит
                                   из диапазона }
     ecBlanksInField   = 07003;  { Поле содержит пробелы }
     ecPartialEntry    = 07004;  { Поле содержит часть элемента }
     ecBadCharacter    = 07005;  { Поле содержит недопустимый
                                   символ }

     { Возвращают OPMEMO, OPEDITOR, OPBROWSE }
     ecStringNotFound  = 07100;  { Искомая строка не найдена }
     ecNotToScreen     = 07101;  { Не могу произвести вывод на
                                   экран }
     ecInvalidNumber   = 07102;  { Введено неверное число }

     { Возвращают OPMEMO, OPEDITOR }
     ecBufferFull      = 07110;  { Буфер редактора полон }
     ecLineTooLong     = 07111;  { Слишком длинная строка.
                                   Вставляется CRLF }
     ecTooManyLines    = 07112;  { Будет превышено ограничение на
                                   число строк }
     ecOverLineLimit   = 07113;  { Превышено ограничение на
                                   число строк }
     ecFileTruncated   = 07114;  { Файл обрезан }
     ecFileTooLarge    = 07115;  { Файл не помещается в буфер }
     ecNoBlock         = 07116;  { Блок не выделен или скрыт }

     { Возвращает OPCALC }
     ecDivideByZero    = 07200;  { Переполнение при делении }
     ecUndefinedNum    = 07201;  { Ошибка, возвращаемая 8087 }

     { Возвращает OPDIR }
     ecNoPickSelection = 07300;  { Выбора произведено не было }

     { Возвращает OPROOT.Library }
     ecDuplicateName   = 07400;  { Такое имя уже используется }
     ecEntryNotFound   = 07401;  { Не найден элемент библиотеки }

                     Ошибки программиста.

     { Возвращает OPROOT.StringSet }
     ecDupString       = 08000;  { Такая строка уже есть }

     { Возвращает OPROOT.IdStream }
     ecIdNotRegistered = 08010;  { Объект пользователя не за-
                                   регистрирован в потоке }
     ecIdRegisteredDup =  08011; { Попытка регистрации дубли-
                                   рующего идентификатора
                                   объекта }

     { Возвращает OPLARRAY }
     ecElSizeIsZero    = 08050;  { Нулевой размер элемента }
     ecIncorrectSize   = 08051;  { Неправильная размерность
                                   файла }
     ecRowOutOfRange   = 08052;  { Указанная строка выходит из
                                   диапазона }
     ecColOutOfRange   = 08053;  { Указанная колонка выходит
                                   из диапазона }
     ecNotLArrayFile   = 08054;  { Указанный файл не является
                                   файлом OpLarray }
     ecElementTooBig   = 08055;  { Слишком большой элемент }
     ecBadDimensions   = 08056;  { Указаны неверные размерности }
     ecLessThenOnePage = 08057;  { В ОЗУ меньше чем одна стра-
                                   ница }
     ecFlashError      = 08058;  { Ошибка при сбросе файла
                                   Larray }

     { Возвращает OPWINDOW и другие }
     ecWinCoordsBad    = 08100;  { Для окна указаны неверные
                                   координаты }
     ecWinNotActive    = 08101;  { Данная операция может выпол-
                                   няться только с активным
                                   окном }
     ecWinNotCurrent   = 08102;  { Данная операция может выпол-
                                   няться только с текущим
                                   окном }
     ecWinIsActive     = 08103;  { Данная операция может выпол-
                                   няться только с неактивным
                                   окном }
     ecWinInaccessible = 08104;  { Стековое окно недоступно }
     ecWinIsZoomed     = 08105;  { Нельзя распахнуть, уже
                                   распахнутое окно }
     ecWinBadIndex     = 08106;  { Неверный заголовок или
                                   индекс панели активизации }
     ecWinNotSizeable  = 08107;  { Для выполнения данной операции
                                   окно должно быть способно
                                   изменять размер }
     ecNoProcessor     = 08108;  { Недоступен процессор команд }

     { Возвращает OPPICK }
     ecNoPickItems     = 08200;  { Попытка отметить в пустом
                                   списке }
     ecBadPickOrient   = 08201;  { Неверная ориентация списка }
     ecBadPickHandler  = 08202;  { Неверный обработчик команд }

     { Возвращает OPHELP }
     ecHelpInvalid     = 08220;  { Неверный формат help-файла }
     ecNoHelpForTopic  = 08221;  { Нет информации по указанной
                                   ссылке }
     ecNoBoundHelp     = 08222;  { Не зарегистрирован указатель
                                   на ограниченный help }

     { Возвращает OPSELECT, OPENTRY }
     ecTooManyFields   = 08300;  { На экране выбора/ввода слишком
                                   много полей }
     ecBadCoordinates  = 08301;  { Недопустимые координаты поля }
     ecNotScrollable   = 08302;  { Не выделен виртуальный экран }
     ecNoFields        = 08303;  { Экран выбора/ввода не имеет
                                   полей }
     ecFieldNotFound   = 08305;  { Попытка позиционирования кур-
                                   сора на несуществующее поле }

     { Возвращает OPPRINT }
     ecInvalidPrinter  = 08400;  { Указан неверный тип принтера }
     ecPosOutOfRange   = 08401;  { Позиция принтера выходит из
                                   допустимого диапазона }
     ecNoPositionPrim  = 08402;  { Не указана процедура пози-
                                   ционирования принтера }
     ecFontStkOverflow = 08403;  { Переполнение стека шрифтов }
     ecFontStackError  = 08404;  { Исчезновение стека шрифтов }
     ecByteStkOverflow = 08405;  { Переполнение байтового стека }
     ecNoPrnDriver     = 08406;  { Для Printer не указан
                                   BasePrinterPtr }

     { Возвращает OPFORM }
     ecNoFieldsOnPage  = 08420;  { Печатаемая страница не имеет
                                   активных полей }
     ecNoBlockDefined  = 08421;  { Попытка добавления поля при
                                   неопределенном блоке }
     ecNoSuchField     = 08422;  { Идентификатор поля определяет
                                   несуществующее поле }
     ecDiagNotAllowed  = 08423;  { Недопустимы диагональные
                                   строки }

     { Возвращают различные юниты }
     ecNilPointer      = 08500;  { Нулевой указатель в данном
                                   случае недопустим }
     ecBadParam        = 08501;  { Неверный параметр процедуры }

                    Сообщения (не ошибки).

     mcLineNumber      = 09000;  { Запрос номера строки }
     mcOptionString    = 09001;  { Запрос параметров поиска }
     mcBlockWrite      = 09002;  { Запрос имени файла, куда
                                   должен быть записан выделен-
                                   ный блок }
     mcBlockRead       = 09003;  { Запрос имени файла, откуда
                                   должен быть считан выделен-
                                   ный блок }
     mcNewFile         = 09004;  { Запрос имени нового файла }
     mcRightMargin     = 09005;  { Запрос правой границы }
     mcIndentLevel     = 09006;  { Запрос сдвига }
     mcTabSize         = 09007;  { Запрос шага табуляции }
     mcFileModifaed    = 09008;  { Запрос: Файл был изменен!
                                   Сохранить? }
     mcSaveAs          = 09009;  { Новое имя для файла }
     mcSearchFor       = 09010;  { Запрос строки для поиска }
     mcReplaceWith     = 09011;  { Запрос строки замены }
     mcReplaceYesNo    = 09012;  { Запрос подтверждения замены }



       E. Использование оверлеев с Object Professional.

     При написании оверлейных программ с использованием Object
Professional имеется несколько важный вещей, которые не нужно
забывать. Первая и основная, что не все юниты Object
Professional могут использоваться в оверлейных программах. Ни-
же приведен список юнит, которые могут использоваться:

     OPABSFLD
     OPASCIIZ
     OPBCD
     OPBROWSE *
     OPCAL *
     OPCALC *
     OPCLONE
     OPDATE *
     OPDEVICE
     OPDIR
     OPDOS
     OPEDIT *
     OPEDITOR *
     OPENTRY *
     OPEXTMEM *
     OPFEDIT
     OPFIELD
     OPFORM
     OPFRAME
     OPHELP *
     OPLARRAY *
     OPMACED *
     OPMENU *
     OPPICK *
     OPPRINT *
     OPQKREF *
     OPSEDIT *
     OPSELECT *
     OPSORT
     OPWINDOW

     Звездочка за именем юниты говорит о том,  что юнита имеет
блок инициализации. Если вы используете в оверлее одну из этих
юнит, ваша программа должна инициализировать систему  управле-
ния оверлеями до запуска кодов инициализации данных юнит.  Это
описано в "Справочном руководстве по Turbo  Pascal",  страница
178, раздел  "Секции  инициализации  в юнитах,  используемых в
оверлеях".

     Не забывайте, однако, что по умолчанию все юниты Object
Professional имеют блоки инициализации, а не только помеченные
звездочками. Но эти блоки в действительности не выполняют ни-
какой работы поскольку они пустые, если определена переменная
времени компиляции InitAllUnits в файле OPDEFINE.INC. Обсужде-
ние того, как данная переменная объявлена по умолчанию, смот-
рите в главе 2 - "Принципы организации".

     Однако имеется даже более  важное  замечание,  касающееся
характеристик. Многие  приведенные  выше юниты зависят одна от
другой, и вы должны быть осторожны, чтобы не создать ситуацию,
когда две юниты будут постоянно подкачиваться в и из памяти,
поскольку одна зависит от другой - это называется "Overlay
Thrashing". (Список зависимостей юнит приведен в приложении
А). В общем вы не должны помещать зависимые юниты в различные
оверлеи. Иногда это может привести к увеличению буфера оверле-
ев, но не всегда. В большинстве случаев лучше помещать в овер-
лее зависимые юниты, а не юниты, от которых они зависят.

     Последнее, что  нужно  помнить,  относится  к  стеку окон
(смотрите документацию  по  OPWINDOW).  Рассмотрим  случай   с
DESKPOP. Если  попробовали работать с ней,  то вас должно быть
удивило, как мы не используем оверлеи для уменьшения занимае-
мой памяти и освобождения места в "куче". Ответ дает использо-
вание стека окон. Если в стеке находятся несколько окон раз-
личного типа, то система управления окнами периодически вызы-
вает метод UpdateContents для их перерисовки. Если у вас име-
ется 6 объектов окон различного типа и все методы
UpdateContents находятся в оверлеях, то какая либо простая
вроде бы операция может привести к перезагрузке с диска 6
юнит. В результате изменения на экране будут происходить очень
медленно. DESKPOP это конечно крайний случай, однако тоже от-
носится и к небольшим прикладным программам, использующим
несколько окон.

     Все, что мы могли дать, мы рассказали в виде простых пра-
вил. Только экспериментирование позволит вам определить, какие
юниты в данной программе должны быть помещены в оверлеи, а ка-
кие нет. Когда программа становится слишком большой, многие
программисты бросаются к оверлеям. Однако редко когда это сра-
зу срабатывает. Перед тем, как преобразовать программу для
использования оверлеев, придется повозиться.

     Сформируйте полный список зависимостей ваших юнит и сге-
нерируйте MAP-файл для вашей программы (TPC filename.ext /GS)
для определения того, какие юниты используют больше памяти и
могут быть помещены в оверлеи. Используя эту информацию, соз-
дайте второй список наилучших кандидатов для помещения в овер-
леи. Затем потратьте немного времени и поэкспериментируйте с
различными комбинациями. Если вы экспериментируете с оверлея-
ми, сохраняемыми в EMS, а не все пользователи вашей программы
имеют машины с памятью EMS, то также поэкспериментируйте с
оверлеями, сохраняемыми на диске предпочтительно на машинах с
процессором 8088. Запуск для тестирования на машине с про-
цессором 80386 и с памятью EMS не даст вам почувствовать, как
она будет работать.

     Кроме всего вышесказанного,  будьте готовы  к  тому,  что
оверлеи могут  быть  не  лучшим решением проблем с недостатком
памяти. В некоторых  случаях  лучшим  решением  будет  разбить
большую программу   на  несколько  маленьких,  запускаемых  из
основного меню. Если вы предпочтете данное решение, мы совету-
ем вам  взглянуть  на функции ExecDos из OPDOS и ExecDosSwap в
OPEXEC. ExecDos удобна,  если основная программа  относительно
маленькая. ExecDosSwap лучше использовать, если основная прог-
рамма велика, или если необходимо оставить максимально возмож-
ный объем памяти, или если запускаемой программе требуется вся
память, которую она может получить.



  F. Преобразование   прикладных   программ,  написанных  с
              использованием Turbo Professional.

     Мы можем честно сказать в данном  разделе:  не  пытайтесь
преобразовать прикладные программы, которые написаны с большим
использованием возможностей Turbo Professional для организации
пользовательского интерфейса.  Если же в существующих приклад-
ных программах вы хотите воспользоваться  возможностями,  пре-
доставляемыми Object Professional,  вам придется переписать их
с самого низу. Механизм эмуляции не предоставляет все возмож-
ности объектно-ориентированного программирования или использо-
вания новых возможностей Object Professional.

     Сказав это, мы предложим вам некоторые основные правила
преобразования. Однако поймите, что это не будет преобразова-
ние типа замены одного ключевого слова другим, или совершение
этого небольшими шагами. Объектно-ориентированное программиро-
вание - это совершенно другая парадигма, для использования
всех ее возможностей вам придется изменить свою манеру мышле-
ния. Мы были удивлены большим количеством звонков, в которых
опять задавали вопросы: а совместим ли пакет Object
Professional по исходным кодам с Turbo Professional? Если у
вас возникает данный вопрос, то ответ таков: Если ваша прог-
рамма использует возможности пользовательского интерфейса, то
нет.

     Как мы  уже  сказали  в  приложении А,  многие не объект-
но-ориентированные юниты  в  Object  Professional  аналогичны,
если не идентичны, юнитам в Turbo Professional. Если ваша
прикладная программа использует только следующие юниты:
OP8087, OPASCIIZ, OPBCD, OPCRT, OPDATE, OPDOS, OPEMS,
OPENHKBD, OPEXTMEM, OPINLINE, OPINT, OPMACED, OPMACRO,
OPMOUSE, OPSORT, OPSTRDEV, OPSTRING, OPTSR, то вы можете
просто изменить оператор USES и перекомпилировать вашу прог-
рамму. Имеется только одно замечание: функция
TerminateAndStayReident из OPTSR стала процедурой и была пере-
именована в StayRes (Поскольку имела слишком длинное имя).

     Прикладные программы,  которые  используют  другие  юниты
Turbo Professional,  которые  были   переписаны   для   Object
Professional: OPDIR,  OPEDIT, OPENTRY, OPHELP, OPMEMO, OPMENU,
OPPICK, OPWINDOW придется довольно сильно переделывать.

     Как объектно-ориентированный язык Turbo Pascal 5.5  очень
прост в использовании. Вы можете смешивать объектно-ориентиро-
ванное программирование с  традиционным  структурным.  Объект-
но-ориентированное расширение  использует  синтаксис  записей,
которые вам знакомы.  Аналогично объектно-ориентированные биб-
лиотеки в  Object Professional просты для понимания,  особенно
для пользователей Turbo Professional.  Мы попытались  изменить
Turbo Professional  таким образом,  чтобы облегчить вам перет-
ранстляцию.

     - мы не изменили системно-ориентированные юниты;
     - мы  предоставляем  те  же  высокоуровневые  возможности
       (т.е. окна, списки, экраны ввода);
     - мы свели к минимуму неважные абстракции;
     - мы исключили архитектуру, основанную на событиях;

     Первые два замечания понятны. Третий связан, но несколько
отличается от них. Если вы знакомы с другими объектно-ориенти-
рованными языками или библиотеками классов, вы знаете, что не-
которые из  них  рассматриваются  как  абстрактные - это часто
несколько нижних элементов  в  иерархии  классов,  которые  не
только обслуживают неосновные цели, но и уменьшают эффектив-
ность базовых операций, таких, как операции сложения и вычита-
 ния. С другой стороны, мы можем увидеть удобства абстракции в
возможности расширения и повторного использования некоторых
объектов. Мы пытались найти золотую середину; абстрактные объ-
екты типа AbstractWindow, AbstractSelector и
AbstractHelpWindow были использованы только после очень про-
должительного обсуждения.

     И последнее ставит Object Professional против  операцион-
ных сред  типа  операционной  системы  Macintosh,  Windows или
Presentation Manager, все из которых обрабатывают происходящие
события. После рассмотрения таких систем мы остановились толь-
ко на циклах Process и на фоновых обработчиках задач.

     Если объектно-ориентированное  программирование  для  вас
внове, мы советуем вам начать с преобразования маленькой прик-
ладной программы.  Хорошим упражнением может быть преобразова-
ние WINWOW с Turbo Professional в Object Professional (и срав-
нить полученный  результат  с  имеющимся  примером  в   Object
Professional).

     Некоторые изменения  в Object Professional не относятся к
объектно-ориентированному программированию. Turbo Professional
прошел через  три основных этапа расширения,  и эти расширения
стали перевешивать исходные основания,  на которых он  базиро-
вался. Зная,  что переход к объектно-ориентированному програм-
мированию разрушит большинство  программ,  мы  воспользовались
возможностью восстановить  наши  собственные  основания.  Ниже
приведены цели, которые мы поставили:

     - уменьшить использование глобальных констант для опреде-
       ления поведения юнит (в основном TPPICK и TPEDIT);
     - определить всеобъемлющий набор видеоатрибутов, который
       может использоваться во всей прикладной программе;
     - рассматривать все типы окон  одинаково  (окна,  списки,
       меню, экраны ввода и т. д.);
     - подразумевать,  что весь вывод может осуществляться  на
       виртуальном экране так же, как на физическом экране

     Оставшуюся часть  данного  раздела  мы  посвятили  юнитам
Turbo Professional, которые требуют наибольшего труда при пре-
образовании. Для   краткости   мы  будет  ссылаться  на  Turbo
Professional как на TPRO,  а на  Object  Professional  как  на
OPRO.

                        TPCRT -> OPCRT

     OPCRT в основном идентична TPCRT. Единственное отличие,
состоит в том, что все функции вывода в окно из TPCRT
(FastWriteWindow, FastReadWindow, и т.д.) включены теперь в
юниту OPWINDOW.

     Объект ColorSet,  определенный  в OPCRT,  используется во
всех объектах OPRO, взаимодействующих с пользователем для оп-
ределения цветов. В TPRO управление цветами не столь логично:
некоторые процедуры требовали набор атрибутов как параметры,
другие получали в качестве параметров массив атрибутов, другие
требовали изменения глобальных переменных, и т.п. Одной из
первых задач при модификации пакета было преобразование всех
ваших цветов в один (или может быть больше) ColorSet.

                        TPCMD -> OPCMD

     Это преобразование требуется, если вы используете возмож-
ности описанные  в приложении C руководства по TPRO "Обработка
клавиатуры в Turbo Professional".  Для преобразования подходят
следующие методы CommandProcessor:

Раздел                     TPRO                OPRO
──────────────────────────────────────────────────────────────
Устанавливаемые ловушки    AddEditCommands,    AddCommand
клавиатуры                 и т.п.
Ловушки фоновых задач      EditKeyPtr, и т.п.  SetGetKeyProc
Контекстные ловушки help   EditHelpPtr, и т.п. SetHelpProc


                OPWINDOW -> OPFRAME, OPWINDOW

     Понимание отличия  OPWINDOW от TPWINDOW является основным
в использовании OPRO.  Поскольку большинство оставшихся объек-
тов взаимодействия  с  пользователем  являются производными от
RawWindow из OPRO,  то все,  что вам известно о RawWindow  от-
носится также ко всем остальным объектам.

     Для того,  чтобы  спокойно использовать новые возможности
оконной системы OPRO:  несколько заголовков, тени, наследуемые
строки прокрутки  в  любом месте рамки и т.п.  - простой вызов
MakeWindow из TPRO должен быть заменен  на  последовательность
вызовов различных методов из OPWINDOW и OPFRAME. Ниже в табли-
це приведены соответствующие методы:

TPRO параметры MakeWindow      Эквивалентные в OPRO
──────────────────────────────────────────────────────────────
var W:WindowPtr                RawWindow,StackWindow, и т.д.
                               переменные экземпляра Xlow,Ylow,
                               XHigh,YHigh:Byte координаты
                               Init и InitCustom
DrawFrame:Boolean              параметр wBordered InitCustom или
                               wOptinsOn
ClearWindow:Boolean            wClear "
SaveWindow:Boolean             wSaveContents "
WindowAttr:Byte                поля TextColor и TextMono в
                               ColorSet
FrameAttr:Byte                 FrameColor,FrameMono "
HeaderAttr:Byte                HeaderColor, HeaderMono "
Header:string                  Frame.AddHeader и зависимые методы
TPRO TPWINDOW Константы        эквивалентны
Shadow:Boolean                 Frame.AddShadow и зависимые методы
ShadowMode:ShadowType          параметр DrawType в AddShadow
ShadowAttr:Byte                поля ShadowColor и ShadowMono в
                               ColorSet
Explode:Boolean                RawWindow.EnableExplosions
ExplodeDelay:Word              параметр StageDelay в EnableExplosions
SoundFlagW:Boolean             wSoundEffects в InitCustom или
                               wOptionsOn

     * OPRO  всегда  использует координаты активного окна,  не
считая рамки, тогда как координаты в TPRO включают рамку.

     Мы рекомендуем заменить переменные WindowPtr экземплярами
переменных типа WindowPtr OPRO.  Этим ваши оконные объекты бу-
дут указывать на StackWindow,  что обеспечит вам прямой доступ
ко всем  окнам на экране.  Ниже приведены тексты для создания,
вывода, вывода и удаления окна размером с экран, имеющего рам-
ку, для OPRO и TPRO.

     program TPROexample;
     uses TpCrt,TpWindow;
     var W:WindowPtr;
     begin
        Shadow := True;
        if not MakeWindow(W,1,1,ScreenWigth,ScreenHeight,
                          True,True,True,$07,$0F,$0F,
                          'Окно во весь экран') then Halt;
        if not DisplayWindow(W) then Halt;
        FastWriteWindow('верхний левый угол активного окна',
                         1,1,$07);
        ReadLn;
        DisposeWindow(EraseTopWindow);
     end.

     program OPROexample;
     uses OpCrt, OpRoot, OpFrame, OpWindow;
     var W:WindowPtr;
     begin
        New(W,InitCustom(2,2,ScreenWigth-1,ScreenHeight-1,
                         DefaultColorSet,wBordered+wClear+
                         wSaveContents));
        if W = nil then
           Halt;
        W^.wFrame.AddHeader('Окно во весь экран',heTC);
        W^.wFrame.AddShadow(shBR,shSeeThru);
        W^.EnableExplositions(15);
        W^.Draw;
        W^.FastWrite('Верхний левый угол активного окна',1,1,$07);
        ReadLn;
        W^.Erase;
        W^.Done;
     end.

                       TPMENU -> OPMENU

     За исключением некоторых отличий, связанных с синтаксисом
OOP и изменений в некоторых именах,  OPMENU аналогичен TPMENU.
Нижеприведенная таблица демонстрирует прямое соответствие меж-
ду процедурами в системе построения меню:

     TPRO                        OPRO
     NewMenu                     Init или InitCustom
     SubMenu                     AddSubMenu или AddFrameSubMenu
     PopSubLevel                 ItemsDone
     MenuItem                    AddItem или AddItemHelp
     MenuItemPtr                 AddItemPtr или AddItemHelpPtr

     Многие процедуры  TPMENU  для  настройки  системы  меню -
MenuWigth, MenuHeight,  MenuMode,  и т.д.  не  нужны  в  OPRO,
поскольку эти свойства наследуются от оконных объектов.

     Для преобразования  существующих  систем меню лучше всего
использовать MAKEMENU,  ввести их заново и  получить  исходный
код.

     Другое отличие состоит в том, каким образом OPRO получает
выбранный пользователем элемент. Ниже приведена программа для
каждой системы:

     program TPROexample;
     uses TpCrt, TpWindow, TpMenu;
     var
        Ch:Char;
        Main:Menu;
        Key:MenuKey;
        procedure InitMenu(var M : Menu);
        begin
           ...
        end;
     begin
        InitMenu(Main);
        Key := MenuChoice(Main,Ch);
        if MenuCmdNum = MKSSekekt then
           case Key of
              1 : { обработка первого элемента }
              { ... других элементов ... }
           end;
     end.

     program OPROexample;
     uses OpCrt, OpRoot, OpCmd, OpFrame, OpWindow, OpMenu;
     var Main : Menu;
     function InitMenu(var M:Menu) : Word;
     begin
        ...
     end;
     begin
        if InitMenu(Main)<> 0 then
           Halt;
        Main.Process;
        if Main.GetLastCommand = ccSelect then
           case Main.MenuChoice of
           1 : { обработка первого элемента }
           { ... остальные элементы меню ...}
           end;
     end.

                 TPEDIT -> OPSEDIT или OPEDIT

     Вызов TPEDIT.ReadString может быть преобразован в исполь-
зовании одного из объектов:  SampleLineEditor в  OPSEDIT,  или
LineEditor в  OPEDIT.  Метод  ReadString.SimpleLineEditor пол-
ностью совпадает с процедурой TPEDIT и занимает в  выполняемом
файле меньше  места,  чем OPEDIT.  OPEDIT предоставляет больше
возможностей, включая редактирование маски картинки.

     Вызовы процедур TPEDIT типа ReadInteger,  ReadCharacter и
YesOrNo могут  быть  преобразованы  только  при  использовании
LineEditor из OPEDIT,  т.к.  в  SimpleLineEditor  не  содержит
соответствующих методов.   Аналогично,   если  вы  используете
систему экранов ввода (OPENTRY),  вы можете также использовать
OPEDIT, т.к.  они  разделяют  много  одинаковых низкоуровневых
подпрограмм (в OPABSFLD, OPFEDIT и OPFIELD).

     OPEDIT и OPSEDIT следуют основному правилу OPRO об исклю-
чении глобальных констант для определения поведения. Ниже при-
ведены программы, поясняющие, что мы хотели сказать:

     {$V-}
     program TPROexample;
     uses
        TpCrt,TpEdit;
     var
        S : String[80];
        Escaped : Boolean;
     begin
        ForceUpper := True;
        WindowRelative := True;
        EditSize := 10;
        ReadString('Введите строку',1,1,80,$0F,$70,$70,
                   Escaped,S);
        if not Escaped then
           WriteLn(^M^J'Вы ввели',S);
     end.

     {$V-}
     program OPROexample;
     uses
        OpCrt,OpCmd,OpSEdit;
     var
        SE:SimpleLineEditor;
        S:String[80];
     begin
        SE.Init(DefaultColorSet);
        SE.seOptionsOn(seForceUpper+seWindowRelative);
        S := '';
        SE.ReadString('Введите строку',1,1,80,10,S);
        if SE.GetLastCommand = ccSelect then
           WriteLn(^M^J'Вы ввели ',S);
     end.

                       TPHELP -> OPHELP

     Текстовые файлы со справочной информацией совместимы сни-
зу вверх от TPRO  до  OPRO.  Просто  используйте  версию  OPRO
MAKEHELP для  перекомпиляции текстовых файлов в новый двоичный
файл. Дополнительные требования к  преобразованию  обусловлены
различиями в  лежащих в основе оконной системе и системе обра-
ботке команд.  Следующие примеры используют файл со справочной
информацией для демонстрационной программы ENTRY:

     program TPROexample;
     uses
        TpCrt,TpHelp;
     const
        HelpColors : HelpColorArray = ($07,$07,$0F,$70,$09,$70,
                                       $0F,$01);
     var
        Help:HelpPtr;
        Topic:Word;
     begin
        if OpenHelpFile('ENTRY.HLP',8,7,19,2,HelpColors,Help) <> 0
           then Halt;
        repeat
           Topic := PickHelp(Help,2,2,10,1);
           if Topic <> 0 then
              if not ShowHelp(Help,Topic) then
                  WriteLn('Ошибка');
        until Topic = 0;
        CloseHelp(Help);
     end.

     program OPROexample;
     uses
        OpCrt,OpCmd,OpFrame,OpWindow,OpPick,OpHelp;
     var
        Help : PageHelpWindow;
        Topic : Word;
     begin
        if not Help.InitCustom(9,8,72,18,DefaultColorSet,
                               DefWindowOptions or wBordered,
                               'ENTRY.HLP',PickVertical)
                               then Halt;
     Help.AddTopicHeader(1,60,heTC);
     Help.AddMoreHeader(' || for more, heBR, #24,#25,'',2,3,0);
     Help.AddMoreHelpHeader(' PgUp/PgDn ',heBR, 'PgUp','PgDn',
                            '/',2,7,6);
     repeat
        Help.SetTopic(PickTopic);
        Help.Process;
        if Help.GetLastCommand = ccSelect then
           Topic := Help.GetTopicChoice
        else
           Topic := 0;
        if Topic <> 0 then begin
           Help.SetTopic(Topic);
           Help.Process;
           if Help.GetLastCommand = ccError then
              WriteLn('Error showing help');
        end;
     until Topic = 0;
     Help.Done;
     end.

                       TPPICK -> OPPICK

     Как и в случае с TPHELP,  преобразования,  требуемые  для
TPPICK ограничиваются различиями в системах обработки команд и
системе поддержки окон. Однако OPPICK предоставляет вам больше
возможностей в  генерации собственных типов объектов,  которые
будут наследовать базовые свойства, и мы были бы рады, если вы
воспользуетесь данными возможностями. На дополнительной диске-
те в качестве примера дана юнита OPCAL,  в главе OPPICK содер-
жатся остальные примеры.

                        TPDIR -> OPDIR

     OPDIR предоставляет больше программных ловушек по сравне-
нию с TPDIR, в объекте PickList, поскольку содержит объекты,
производные от него. Аналогично, если вы поняли отличия систе-
мы управления окнами и обработки команд OPRO, то вам не соста-
вит труда их изменить.

                      TPENTRY -> OPENTRY

     OPENTRY поддерживает  все возможности TPENTRY - множество
типов полей, прокрутка экрана ввода, ловушки до и после редак-
тирования, процедуры проверки допустимости,  защищенные поля и
т.д. Мы рекомендуем использовать программу MAKESCRN для созда-
ния новых  экранов ввода и генерации исходного текста.  Затем,
если вы хотите использовать возможности пользовательских лову-
шек, которые MAKESCRN не может для вас сделать, заполните обо-
лочки процедур,  которые сгенерирует для вас MAKESCRN.  Причем
эти тексты будут очень похожи на тексты, которые вы писали при
использовании TPRO.

     Лучшим источником информации по преобразованию TPENTRY  в
OPENTRY может служить демонстрационная программа ENTRY. Версии
OPRO и TPRO выполняют идентичные функции и  обе  демонстрируют
основные возможности системы ввода данных.

     Необходимо отметить,   что  система  OPENTRY  насчитывает
больше юнит, чем TPENTRY:

     TPENTRY
     uses
        TpInline, TpMemChk, TpCrt,
        {$IFDEF UseMouse) TpMouse, {$ENDIF}
        {$IFDEF UseBcd) TpBcd, {$ENDIF}
        TpCmd, TpString, TpWindow, TpDate;

     OPENTRY
     uses
        OpInline, OpString, OpRoot, OpCrt,
        {$IFDEF UseMouse) OpMouse, {$ENDIF}
        {$IFDEF UseBCD) OpBcd, {$ENDIF}
        {$IFDEF UseDates) OpDate, {$ENDIF}
        OpCmd, OpAbsFld, OpFEdit, OpField, OpFrame, OpWindow,
        {$IFDEF PickListField) OpPick, {$ENDIF}
        OpSelect;

     Некоторые из    этих    дополнительных   юнит   появились
вследствии того,  что  EntryScreen  является  производным   от
CommandWindow. Чаще всего об TPENTRY спрашивают "как сохранить
и восстановить содержимое экрана под экраном ввода?" Ответы на
вопросы, относящиеся к окнам, рамкам, заголовкам и т.п. авто-
матически появляются, поскольку EntryScreen наследует все
свойства CommandWindow.

     Вторая причина увеличения числа юнит состоит в унификации
системы полей ввода. Теперь OPEDIT (LineEditor) разделяет
строчный редактор с OPENTRY через OPABSFLD, OPFEDIT, и
OPFIELD. OPFORM (объект PrintedForm) разделяют интерпретаторы
картинки с OPENTRY через юниту OPABSFLD.



             G. Компилирование больших программ.

     Одна из  наиболее расстраивающих ошибок,  появляющаяся во
время компиляции, "Error 1: Out of Memory". Она обычно означа-
ет прекращение процесса разработки и необходимость изменения
окружения и/или вашей программы. В лучшем случае это неудобно,
в худшем может привести к переосмыслению структуры прикладной
программы.

     При использовании  возможностей,  предоставляемых  Object
Professional, некоторые из ваших больших программ могут перей-
ти этот порог. Т.к. это общий вопрос технической поддержки, мы
приводим список некоторых стандартных действий, которые вы мо-
жете предпринять для увеличения памяти Turbo Pascal. Некоторые
из них  приведены в руководстве по Turbo Pascal,  другие явля-
ются результатом наших (и не только наших) экспериментов.

     1. В Интегрированной Среде Разработки (TURBO.EXE), уста-
новите компиляцию на диск, а не в память
(Compile-Destination-Disk).

     2. Установите на диск буфер связи компилятора. В IDE
установите Options-Compiler-Link-Disk. При использовании ком-
пилятора из командной строки укажите ключ /L.

     3. Если возможно, выключите проверку диапазонов и пере-
полнения стека (для этого поместите в начало программ и юнит
директивы $R-,S-). Однако помните, что после этого функции
библиотеки времени выполнения больше не будут отслеживать эти
ошибки (ваша программа при этом может переписывать некоторые
области памяти. При разработке программы вы, возможно, захоти-
те оставить эти проверки включенными. Никогда не компилируйте
юниты Object Professional с включенными данными проверками.

     4. При отладке включите отладочную информацию (с помощью
$D+ и $L+) только в те юниты, которые вы отлаживаете. После
окончания отладки юниты не забудьте перекомпилировать ее с
выключенной отладочной информацией.

     5. Запустите компиляцию с максимально возможным объемом
памяти, удалив не нужные резидентные программы и драйверы.

     6. Вместо TURBO.EXE используйте TPC.EXE.

     7. Выделите из TURBO.TPL все юниты, за исключением
PRINTER, создав вместо этого SYSTEM.TPU, DOS.TPU и т.д.).
Т.к. компилятор держит в памяти весь TURBO.TPL, этим вы осво-
бодите часть памяти. Вы можете полностью исключить TURBO.TPL
(пока для всех системных юнит вы имеете файлы TPU), компилятор
при этом выдаст вам предупреждение.

     8. Делайте основную программу минимально возможного раз-
мера. По минимуму она должна состоять из одной строки - вызова
другой юниты, содержащей настоящую основную процедуру. Напри-
мер:

     program BigProg;    {файл BIGPROG.PAS}
     uses
        BPMain;
     begin
        Main;
     end.

     unit BPMain;        {файл BPMAIN.PAS}
     interface
     uses {.....};
        procedure Main;
           { Основная процедура BigProg }

     implementation
        procedure Main;
        begin
           {...}
        end;
     end.

     Здесь основная программа использует только одну юниту и
один выполняемый оператор - вызов настоящей основной процедуры
в юните BPMain. Т.к. компилятор во время компиляции держит
основной блок в памяти, этим вы уменьшаете требования к объему
памяти.

     9. Переместите максимально возможное число объявлений из
раздела "interface" в раздел "implementation". Этим вы умень-
шаете объем символьной информации, которая необходима компиля-
тору на всем протяжении компиляции. Если обратиться к парагра-
фу 8, то все глобальные объявления, размещенные в основной
программе, могут быть перенесены в раздел "implementation" в
юните BPMain.

     Порядок, в котором расположены эти предложения, не опре-
деляет последовательность их применения. Все зависит от окру-
жения и от того, что вы сочтете наиболее удобным.

     Если вы используете все приведенные выше возможности, а
программа все равно не будет помещаться в память, то значит
пришло время разбить ее на несколько отдельных EXE-файлов. Эти
файлы могут передавать друг другу управление с помощью функции
DOS Exec. (Заметим, что система управления оверлеями Turbo
Pascal позволяет сократить требования к памяти в период выпол-
нения, однако это не поможет вам при компиляции большой прог-
раммы.) Юнита OPEXEC предоставляет вам подкачиваемую функцию
Exec, которая позволяет вызываемой программе использовать
большую часть памяти, занятой вызвавшей ее программой.



                    H. Что читать дальше.

     Если вы  хотите,  или  если  вам  необходима информация о
внутренней работе PC,  MS-DOS,  и/или IBM BIOS, мы рекомендуем
следующие книги:

     1. Peter  Norton.  "Programmer's  Guide  to  the  IBM PC"
(MicroSoft Press). Хороший справочник по всем трем темам.

     2. Ray Duncan.  "Advanced MS-DOS" (MicroSoft Press). Луч-
ший справочник по DOS и по функциям DOS.

     3. Terry R.  Deymann.  "DOS Programmers Reference" (Que).
Малоизвестная прекрасная книга. Кроме обсуждения большей части
вопросов, которые затрагивают Dunvcan и Norton, в ней обсужда-
ются недокументированные вызовы DOS и другие  необычные  темы,
как, например, программирование мыши. Настоятельно рекоменду-
ем.

     4. Robert Jourdain.  "Programmer's Problem Solver for IBM
PC, XT и AT." (Brady Books).  Не справочник, но содержит много
низкоуровневой информации.

     5. Richard  Wilton.  "Programmer's  Guide  to PC and PS/2
Video Systems." (MicroSoft Press). Содержит детальную информа-
цию по различным видеоадаптерам.

     Материалы по  объектно-ориентированному  программированию
поставляемые с Turbo Pascal 5.5, в настоящее время недостаточ-
ны. Еще  не  напечатана книга,  которая могла бы стать класси-
ческой и занять место в вышеприведенном  списке.  Не  забудьте
прочесть Guide  for  OOP  Pascal 5.5,  которая является на наш
взгляд наиболее простым введением  в  объектно-ориентированное
программирование. Вы  можете так же рассмотреть следующие кни-
ги:

     1. Brad   J.   Cox.   "Object-Oriented   Programming   An
Evolutionary Approach" (Addison-Wesley).  Очень удобное введе-
ние в объектно-ориентированное программирование,  использующее
в качестве базового язык Objective-C.

     2. Bertrand      Meyer.     "Object-Oriented     Software
Construction" (Prentice-Hill).  Объектно-ориентированное прог-
раммирование, где основное внимание, уделенно фундаментальным
принципам. Использует в качестве базового язык Eiffel (создан-
ный Meyer'ом).

     3. Kurt  J.  Schmucker.  "Object-Oriented Programming for
the Macintosh" (Hayden Books). Базируется на объектном Паскале
Apple, который  похож  на Turbo Pascal 5.5,  но все же отлича-
ется. Книга также описывает специфические особенности, относя-
щиеся к операционной системе Macintosh.

     4. Tom Swan. "Mastering Turbo Pascal 5.5" (Hauden Books).
Новая редакция хорошо известного справочника по Turbo  Pascal.
К версии 5.5 относится специальная глава (60 страниц),  специ-
ально посвященная  объектно-ориентированному  программироанию.
Глава хорошо написана и включает хорошее обсуждение потоков.

     Если вам  встретятся книги,  которые достойны быть в этом
списке, пожалуйста дайте нам знать.
