Dev/Docu/ru/P-S-I.odc

Особенности, зависящие от платформы (Windows)
ENGLISH

МодульSYSTEM
ИспользованиеDLLвмодуляхсистемыБлэкбокс
ИспользованиеCOMбезспециальногокомпилятораDirect-To-COM
ПрограммныеинтерфейсыWindows
АвтоматизацияOLE
Информация,специфичнаядляWindows,всистемеБлэкбокс
ОтличиямеждуразнымиверсиямиWindows
КомпоновщиксистемыБлэкбокс
КомпоновкаприложенийсистемыБлэкбокс
ПроцессзагрузкисистемыБлэкбокс


Модуль SYSTEM

Модуль SYSTEM содержит некоторые процедуры, которые необходимы для реализации низкоуровневых операций. Настойчиво рекомендуется ограничить использование этих средств специфичными низкоуровневыми модулями, так как такие модули по сути не переносимы и обычно небезопасны. SYSTEM не считается частью языка Компонентный Паскаль.
Процедуры модуля SYSTEM перечислены в следующей таблице. v обозначает переменную. x, y и n обозначают выражения. T обозначает тип. P обозначает процедуру. M[a] обозначает значение памяти по адресу a.
Процедуры-функции
	Имя	Типы аргументов	Тип результата	Описание
	ADR(v)	любой	INTEGER	адрес переменной v
	ADR(P)	P: PROCEDURE	INTEGER	адрес процедуры P
	ADR(T)	T: записевый тип	INTEGER	адрес дескриптора T
	LSH(x, n)	x, n: целый тип*	тип x	логический сдвиг 
				(n > 0: влево, n < 0: вправо)
	ROT(x, n)	x, n: целый тип*	тип x	вращение (n > 0: влево, n < 0: вправо)
	TYP(v)	записевый тип	INTEGER	тег записевого типа переменной v
	VAL(T, x)	T, x: любой тип	T	значение x интерпретируется как 
				имеющее тип T
	* целые типы кроме LONGINT

Процедуры
	Имя	Типы аргументов	Описание
	GET(a, v)	a: INTEGER; v: любой элементарный, 	v := M[a]
		указательный или процедурный тип
	PUT(a, x)	a: INTEGER; x: любой элементарный,	M[a] := x
		указательный или процедурный тип
	GETREG(n, v)	n: целая константа, v: любой элементарный,	v := регистр n
		указательный или процедурный тип
	PUTREG(n, x)	n: целая константа , x: любой элементарный,	Register n := x
		указательный или процедурный тип
	MOVE(a0, a1, n)	a0, a1: INTEGER; n: целый тип	M[a1..a1+n-1] :=
			M[a0..a0+n-1]

Номера регистров для PUTREG и GETREG таковы:
0: EAX, 1: ECX, 2: EDX, 3: EBX, 4: ESP, 5: EBP, 6: ESI, 7: EDI.

Внимание
При неправильном использовании VAL, PUT, PUTREG и MOVE могут вызвать крах системы Блэкбокс и/или Windows.
Никогда не используйте VAL (или PUT, или MOVE), чтобы присвоить значение указателю в системе Блэкбокс. Это может нарушить работу сборщика мусора, с фатальными последствиями.
Системные флаги
Импорт модуля SYSTEM позволяет изменять некоторые аспекты поведения компилятора с помощью системных флагов. Системные флаги используются для настройки объявлений процедур или типов. Расширенный синтаксис приведен ниже.

Type 	=	Qualident
		| ARRAY ["[" SysFlag "]"] [ConstExpr {"," ConstExpr}]
			OF Type 
		| RECORD ["[" SysFlag "]"] ["("Qualident")"] FieldList
			{";" FieldList} END
		| POINTER ["[" SysFlag "]"] TO Type
		| PROCEDURE [FormalPars].
ProcDecl	=	PROCEDURE ["[" SysFlag "]"] [Receiver] IdentDef
			[FormalPars] ";"
		DeclSeq [BEGIN StatementSeq] END ident.
FPSection	=	[VAR ["[" SysFlag "]"]] ident {"," ident} ":" Type.
SysFlag	=	ConstExpr | ident.

Для системных флагов может использоваться либо имя, либо соответствующее численное значение.

Системные флаги для записевых типов
Имя	Значение	Описание
untagged	1	Тег и дескриптор типа не будут размещаться.
 (без тега)		Сборщик мусора игнорирует переменные без тега.
		NEW не применимо к указателям на переменные без тега.
		С записью нельзя связать процедуры.
		Указатели на записевые типы без тегов или расширения этих
		записевых типов наследуют атрибут untagged.
		Смещения полей выравниваются по
		MIN(4-байта, size), где size - это размер поля.
		Размер записи и смещения полей 
		выравниваются по 32-битным границам.
noalign	3	То же, что untagged, но без выравнивания.
align2	4	То же, что untagged, но с
		выравниванием по MIN(2-байта, size). 
align8	6	То же, что untagged, но с
		выравниванием по MIN(8-байт, size). 
union	7	Запись без тега, у которой все поля имеют смещение 0.
		Размер записи равен размеру самого большого поля.
		Используется для эмуляции типов union языка Си.

Системные флаги для массивовых типов
Имя	Значение	Описание
untagged	1	Тег и дескриптор типа не будут размещаться.
		Сборщик мусора игнорирует переменные без тега.
		NEW не применимо к указателям на переменные без тега.
		Указатели на такой масивовый тип наследуют атрибут untagged.
		Допускаются только одномерные открытые массива без тега.
		Для открытых массивов без тега границы индексации
		не проверяются.
		
Системные флаги для указательных типов
Имя	Значение	Описание
untagged	1	Не отслеживается сборщиком мусора.
		С типом нельзя связать процедуры.
		Должен указывать на запись без тега.

Системные флаги для VAR-параметров
Имя	Значение	Описание
nil	1	NIL допускается в качестве фактического параметра.
		Используется в интерфейсах к функциям Си
		с параметрами указательных типов.

Системные флаги для процедур
Имя	Значение	Описание
code	1	Объявление процедуры в машинных кодах (см. далее).
ccall	-10	Процедура использует соглашение вызова CCall.

Процедуры в машинных кодах
Процедуры в машинных кодах позволяют использовать специальные последовательности машинных команд, которые не генерируются компилятором. Для их объявления используется следующий специальный синтаксис:
ProcDecl	=	PROCEDURE "[" SysFlag "]" IdentDef [FormalPars]
			[ConstExpr {"," ConstExpr}] ";".
Список констант, объявленный с процедурой, интерпретируется как строка байт и вставляется непосредственно в код (in-line), из которого вызвана процедура. Если присутствует список параметров, фактические параметры загружаются в стек справа налево. Однако первый параметр записывается в регистр. Если тип первого параметра REAL или SHORTREAL, то он записывается в верхний регистр для чисел с плавающей точкой. Иначе параметр (или в случае VAR/IN/OUT-параметра  его адрес) записывается в EAX. Для процедур-функций ожидается, что и результат сохраняется в верхнем регистре с плавающей точкой или в EAX, в зависимости от его типа. Будьте осторожны, когда используете регистры в кодовых процедурах. В общем, можно использовать регистры ECX, EDC, ESI и EDI. Параметры должны удаляться со стека процедурой.

Примеры
	PROCEDURE [code] Sqrt (x: REAL): REAL		(* Math.Sqrt *)
		0D9H, 0FAH;			(* FSQRT *)

	PROCEDURE [code] Erase (adr, words: INTEGER)	(* erase memory area *)
		089H, 0C7H,			(* MOV EDI, EAX *)
		031H, 0C0H,			(* XOR EAX, EAX *)
		059H,			(* POP ECX *)
		0F2H, 0ABH;			(* REP STOS *)

Использование DLL в модулях системы Блэкбокс

Любая 32-разрядная DLL может быть импортирована в Компонентный Паскаль подобно обычному модулю. Это справедливо как для системных модулей Windows (kernel, user, gdi, ...) так и для любой другой DLL, написанной на любом языке программирования. Следует помнить, что свойства безопасности программ на Компонентном Паскале (отсутствие висячих ссылок, строгая проверка типов и т.п.) теряются, если вы подключаетесь к DLL, написанной на другом языке программирования.

Модули интерфейсов
Информация о типах объектов, импортируемых из DLL, должна быть представлена в символьном файле, чтобы компилятор мог правильно работать. Такие специальные символьные файлы могут быть сгенерированы из так называемых интерфейсных модулей. Интерфейсный модуль является модулем Компонентного Паскаля, помеченным специальным системным флагом после имени модуля. Такой системный флаг состоит из имени соответствующей DLL, заключенного в квадратные скобки. Модуль интерфейса может содержать лишь объявления констант, типов и заголовков процедур. При компиляции интерфейсного модуля кодовый файл не создается.

Совмещение имен (aliasing)
Имя в Компонентном Паскале для объекта, импортированного из DLL, может отличаться от соответствующего имени в таблице экспорта библиотеки. Для этого к имени в Компонентном Паскале нужно добавить библиотечное имя как системный флаг. Кроме того, в системном флаге может быть указана другая библиотека DLL, чем та, которая объявлена в заголовке модуля. Это позволяет использовать один интерфейсный модуль для целого набора связанных DLL. Но можно иметь несколько интерфейсных модулей, ссылающихся на одну DLL. Интерфейсные процедуры не могут иметь ни тела, ни части END идентификатор, они являются лишь сигнатурами.
Расширенный синтаксис для интерфейсных модулей дан ниже:
Module 	=	MODULE ident ["[" SysString "]"] ";"
		[ImportList] DeclSeq  [BEGIN StatementSeq] END ident ".".
ProcDecl	=	PROCEDURE ["[" SysFlag "]"] [Receiver]
		IdentDef ["[" [SysString ","] SysString "]"] [FormalPars] ";"
		DeclSeq [[BEGIN StatementSeq] END ident].
SysString	=	string.
Совмещения имен нет для типов и констант, поскольку они не представлены в списках экспорта и поэтому могут иметь произвольные имена.
Следующий пример демонстрирует возможности совмещения:
MODULE MyInterface ["MyDll"];
	PROCEDURE Proc1*;	(* Proc1 из MyDll *)
	PROCEDURE Proc2* ["BlaBla"];	(* BlaBla из MyDll *)
	PROCEDURE Proc3* ["OtherDll", ""];	(* Proc3 из OtherDll *)
	PROCEDURE Proc4* ["OtherDll", "DoIt"];	(* DoIt из OtherDll *)
END MyInterface.
SysString для DLL не может содержать имени пути. Это должно быть просто имя DLL, без суффикса ".dll". Используются следующие правила поиска:
- папка BlackBox
- папка Windows\System
- папка Windows

Типы данных в интерфейсных модулях
Всегда используйте записи без тега (untagged records) в качестве аналогов структур Си, чтобы избежать размещения тега типа для сборщика мусора. Системный флаг [untagged] помечает тип как безтеговый (никакой информации о типе во время выполнения не будет доступно) со стандартными правилами выравнивания (2-байтовые поля будут выровнены по 2-байтовым границам, 4-байтовые или большие поля - по 4-байтовым границам). Системные флаги [noalign], [align2] и [align8] также описывают типы как безтеговые, но с различным выравниванием для полей записи.
Как и для всех системных флагов, для использования untagged нужно импортировать модуль SYSTEM.

Пример:
	RECORD [noalign]		(* без тега, размер = 7 байт *)
		c: SHORTCHAR;	(* смещение 0, размер = 1 byte *)
		x: INTEGER;	(* смещение 1 , размер = 4 bytes *)
		i: SHORTINT	(* смещение 5, размер = 2 bytes *)
	END
Процедуры
Вызовы процедур Компонентного Паскаля следуют соглашениям вызова StdCall (параметры загружаются в стек справа налево, и удаляются вызываемой процедурой). Если какие-то процедуры DLL используют соглашение CCall (параметры удаляются вызывающей процедурой), то соответствующие объявления процедур в интерфейсном модуле должны быть сделаны с системным флагом [ccall].
Процедуры обратного вызова (callback) особого объявления не требуют.
Для параметров типа POINTER TO T часто лучше использовать параметр-переменную типа T, нежели объявлять соответствующий тип указателя. Объявляйте VAR-параметр с системным флагом [nil], если NIL является допустимым фактическим параметром. 
Пример:
Си:
	BOOL MoveToEx(HDC hdc, int X, int Y, LPPOINT lpPoint)
Компонентный Паскаль:
	PROCEDURE MoveToEx* (dc: Handle; x, y: INTEGER; VAR [nil] old: Point): Bool
Соответствие между типами данным Компонентного Паскаля и Си
unsigned char	= SHORTCHAR	(1 байт)
WCHAR	= CHAR	(2 байта)
signed char	= BYTE	(1 байт)
short	= SHORTINT	(2 байта)
int	= INTEGER	(4 байта)
long	= INTEGER	(4 байта)
LARGE_INTEGER	= LONGINT	(8 байт)
float	= SHORTREAL	(4 байта)
double	= REAL	(8 байт)
Заметим, что Bool не является типом данных в C, поскольку он определен как целое (= INTEGER). Для присваивания значений FALSE и TRUE нужно использовать 0 и 1, а в условных операторах нужно использовать сравнение с 0 (IF b # 0 THEN ... END вместо IF b THEN ... END).
Заметим также, что выгрузить DLL из Блэкбокса невозможно. Чтобы избежать многократных выходов и перезапусков среды, удобно запустить второй экземпляр системы Блэкбокс и оттуда тестировать DLL, которую вы разрабатываете.
<На самом деле можно динамически загружать-выгружать DLL, причем находящиеся где угодно. Примеры можно найти через здесь прим. ред.> 
Использование COM без специального Direct-To-COM-компилятора
Microsoft Component Object Model (COM) поддерживается специальным компилятором для Компонентного Паскаля, который доступен как добавочный продукт к BlackBox. Этот компилятор делает использование COM безопаснее и удобнее. Однако для эпизодического использования COM можно использовать подход, описанный в данном разделе. Для этого не требуется специальной версии компилятора. Для создания таблиц методов в стиле COM ("vtbl") используются обычные записи без тегов и процедурные переменные. Следующий пример показывает, как это работает:

MODULE Ddraw ["DDRAW.DLL"];

TYPE
  GUID = ARRAY 4 OF INTEGER;

  PtrIUnknown = POINTER TO RECORD [untagged]
    vtbl: POINTER TO RECORD [untagged]
      QueryInterface: PROCEDURE (this: PtrIUnknown; IN iid: GUID; OUT obj: PtrIUnknown): INTEGER;
      AddRef: PROCEDURE (this: PtrIUnknown): INTEGER;
      Release: PROCEDURE (this: PtrIUnknown): INTEGER;
    END
  END;

  PtrDirectDraw = POINTER TO RECORD [untagged]
    vtbl: POINTER TO RECORD [untagged]
      QueryInterface: PROCEDURE (this: PtrDirectDraw; IN iid: GUID; OUT obj: PtrIUnknown): INTEGER;
      AddRef: PROCEDURE (this: PtrDirectDraw): INTEGER;
      Release: PROCEDURE (this: PtrDirectDraw): INTEGER;
      Compact: PROCEDURE (this: PtrDirectDraw): INTEGER;
      ...
      SetCooperativeLevel: PROCEDURE (this: PtrDirectDraw; w, x: INTEGER): INTEGER;
      ...
    END
  END;

PROCEDURE DirectDrawCreate* (IN guid: GUID; OUT PDD: PtrDirectDraw; outer: PtrIUnknown) : INTEGER;

END Ddraw.


MODULE Directone;

IMPORT Type, Util, Out, Ddraw, KERNEL32, SYSTEM;

CONST
  ModuleName  = "Directone";
  DDSCL_EXCLUSIVE = 00000010H;
  DDSCL_FULLSCREEN = 00000001H;

PROCEDURE Initialize;
VAR 
  Handle, Addr, Res: INTEGER;
  PDD: PtrDirectDraw;
  nul: GUID;
BEGIN
  PDD := NIL;
  nul[0] := 0; nul[1] := 0; nul[2] := 0; nul[3] := 0;
  Res := Ddraw.DirectDrawCreate( nul, PDD, 0 );
  Out.String( "Res" );  Out.Int( Res, 8 );  Out.Ln();
  Res := SYSTEM.VAL( INTEGER, PDD );
  Out.String( "Res" );  Out.Int( Res, 8 );  Out.Ln();
  Res := PDD.vtbl.SetCooperativeLevel( PDD, 0, DDSCL_EXCLUSIVE + DDSCL_FULLSCREEN );
  Out.String( "Res" );  Out.Int( Res, 8 );  Out.Ln();
  Res := PDD.Release()
END Initialize;

BEGIN
  Initialize
END Directone.

Несколько необходимых замечаний:
 COM GUIDs представляют собой 128-битные сущности, а не целые.
 НЕ ИСПОЛЬЗУЙТЕ ANYPTR или другие указатели Блэкбокса для указателей на интерфейсы COM. (Указатели Блэкбокса обрабатываются сборщиком мусора, указатели COM  счетчиком ссылок.)
 Вместо этого используйте указатели на записи с атрибутом [untagged] или целые.

Будьте внимательны: объявляйте все методы в таблице методов в правильном порядке с правильными списками параметров.


Программные интерфейсы Windows

См. документацию ПрограммныеинтерфейсыWindows.


Автоматизация OLE

См. документацию ДиспетчерАвтоматизацииOLE.


Информация, специфичная для Windows, в системе Блэкбокс

Курсоры, специфичные для Windows 
Модуль HostPorts экспортирует константы для Windows-курсоров, которые могут быть использованы наряду со стандартными курсорами, определенными в модуле Ports:
	CONST
		resizeHCursor = 16;	(* курсоры для изменения размера *)
		resizeVCursor = 17;
		resizeLCursor = 18;
		resizeRCursor = 19;
		resizeCursor = 20;
		busyCursor = 21;	(* курсор занятости *)
		stopCursor = 22;	(* курсоры перетаскивания *)
		moveCursor = 23;
		copyCursor = 24;
		linkCursor = 25;
		pickCursor = 26;	(* курсор перетаскивания с указанием *)
Модификаторы мыши и клавиатуры, специфичные для Windows 
Наборы модификаторов используются в процедурах Controllers.TrackMsg, Controllers.EditMsg и Ports.Frame.Input. В дополнение к независящим от платформы модификаторам Controllers.doubleClick, Controllers.extend и Controllers.modify они содержат специфичные для платформы модификаторы, определенные в модуле HostPorts:
	CONST
		left = 16;	(* нажата левая кнопка мыши *)
		middle = 17;	(* нажата средняя кнопка мыши *)
		right = 18;	(* нажата правая кнопка мыши *)
		shift = 24;	(* нажат клавиша Shift *)
		ctrl = 25;	(* нажата клавиша Control *)
		alt = 28;	(* нажата клавиша Alt *)
Контексты окон и устройств
Многие функции в Windows API ссылаются на контексты окна или устройства. В реализации Блэкбокса для Windows, и те, и другие хранятся в записях HostPorts.Port:
	TYPE
		Port = POINTER TO RECORD (Ports.PortDesc)
			dc: WinApi.Handle;
			wnd: WinApi.Handle
		END;
В обычном случае, когда дан фрейм (Ports.Frame или Views.Frame), контексты могут быть получены одним из следующих селекторов:
		frame.rider(HostPorts.Rider).port.dc
		или
		frame.rider(HostPorts.Rider).port.wnd
Если контекст окна нулевой, то порт является портом принтера.
Примеры
Следующее определение простой DLL является подмножеством стандартной библиотеки Windows GDI32:

MODULE GDI ["GDI32"];

	CONST
		WhiteBrush* = 0; BlackBrush* = 4; NullBrush* = 5;
		WhitePen* = 6; BlackPen* = 7; NullPen* = 8;
		PSSolid* = 0; PSDash* = 1; PSDot* = 2;

	TYPE
		Bool* = INTEGER;
		Handle* = INTEGER;
		ColorRef* = INTEGER;
		Point* = RECORD [untagged] x*, y*: INTEGER END;
		Rect* = RECORD [untagged] left*, top*, right*, bottom*: INTEGER END;

	PROCEDURE CreatePen* (style, width: INTEGER; color: ColorRef): Handle;
	PROCEDURE CreateSolidBrush* (color: ColorRef): Handle;
	PROCEDURE GetStockObject* (object: INTEGER): Handle;
	PROCEDURE SelectObject* (dc, obj: Handle): Handle;
	PROCEDURE DeleteObject* (obj: Handle): Bool;
	PROCEDURE Rectangle* (dc: Handle; left, top, right, bottom: INTEGER): Bool;
	PROCEDURE SelectClipRgn* (dc, rgn: Handle): INTEGER;
	PROCEDURE IntersectClipRect* (dc: Handle; left, top, right, bottom: INTEGER): INTEGER;
	PROCEDURE SaveDC* (dc: Handle): INTEGER;
	PROCEDURE RestoreDC* (dc: Handle; saved: INTEGER): Bool;

END GDI.

Следующий пример - это упрощенная версия стандартного средства Блэкбокса DrawRect, реализованного в Ports и HostPorts. Здесь используется интерфейс GDI, представленный выше.

MODULE Ex;

	IMPORT Ports, HostPorts, GDI;

	PROCEDURE DrawRect (f: Ports.Frame; l, t, r, b, s: INTEGER; col: Ports.Color);
		VAR res, h, rl, rt, rr, rb: INTEGER; p: HostPorts.Port; dc, oldb, oldp: GDI.Handle;
	BEGIN
		(* преобразование локальных универсальных координат в пиксельные оконные координаты *)		
		l := (f.gx + l) DIV f.unit; t := (f.gy + t) DIV f.unit;
		r := (f.gx + r) DIV f.unit; b := (f.gy + b) DIV f.unit;
		s := s DIV f.unit;
		(* получение контекста устройства *)		
		p := f.rider(HostPorts.Rider).port; dc := p.dc;
		(* установка области отсечения *)
		IF p.wnd = 0 THEN res := GDI.SaveDC(dc)
		ELSE res := GDI.SelectClipRgn(dc, 0)
		END;
		f.rider.GetRect(rl, rt, rr, rb);
		res := GDI.IntersectClipRect(dc, rl, rt, rr, rb);
		(* по умолчанию используется черный цвет *)
		IF col = Ports.defaultColor THEN col := Ports.black END;
		IF s = 0 THEN s := 1 END;
		IF (s < 0) OR (r-l < 2*s) OR (b-t < 2*s) THEN	(* закрашенный прямоугольник *)
			INC(r); INC(b);
			oldb := GDI.SelectObject(dc, GDI.CreateSolidBrush(col));
			oldp := GDI.SelectObject(dc, GDI.GetStockObject(GDI.NullPen));
			res := GDI.Rectangle(dc, l, t, r, b);
			res := GDI.DeleteObject(GDI.SelectObject(dc, oldb));
			res := GDI.SelectObject(dc, oldp)
		ELSE	(* каркасный прямоугольник *)
			h := s DIV 2; INC(l, h); INC(t, h); h := (s-1) DIV 2; DEC(r, h); DEC(b, h);
			oldb := GDI.SelectObject(dc, GDI.GetStockObject(GDI.NullBrush));
			oldp := GDI.SelectObject(dc, GDI.CreatePen(GDI.PSSolid, s, col));
			res := GDI.Rectangle(dc, l, t, r, b);
			res := GDI.SelectObject(dc, oldb);
			res := GDI.DeleteObject(GDI.SelectObject(dc, oldp))
		END;
		IF p.wnd = 0 THEN res := GDI.RestoreDC(dc, -1) END
	END DrawRect;

END Ex.
Система типов времени выполнения
Все динамически размещаемые записи Компонентного Паскаля содержат скрытое поле, которое называется тегом типа. Тег типа указывает на описатель типа, который содержит всю иформацию о типе, необходимую во время выполнения. Вызовы связанных с типом процедур, проверки типов и сборка мусора используют информацию, которая хранится в описателе типа. Описатель типа размещается только один раз для каждого записевого типа в системе.
Динамаически размещаемые массивы используют описатель размера для проверки границ индексов. Описатель размера также содержит тег для типа элементов. Отдельный описатель размера нужен для каждого динамического массива.
Различия между разными версиями Windows
Элементы управления дерево в Windows NT выглядят по-иному, чем в других версиях Windows. В Windows NT процедура рисования фона таких элементов содержит ошибку. Поэтому Блэкбокс при работе под WindowsNT не изменяет цвет фона для отключенных деревьев или доступных только для чтения, хотя под другими версиями Windows в этих случаях фон становится серым.
Компоновщик системы Блэкбокс
См. документацию DevLinker.
Компоновка приложений в системе Блэкбокс
Если нужно распространять приложение, созданное в Блэкбоксе, то может возникнуть желание скомпоновать все модули для распространения в один файл. В этом случае вместе с приложением нужно скомпоновать среду. Чтобы показать необходимые действия, приведем пример. Сначала сделайте в Проводнике копию всей системы Блэкбокс и переменуйте ее соответственно, в нашем случае  Patterns. Подправьте модуль Config под свои нужды, например, удалите вызов, который автоматически открывает рабочий журнал. Затем скомпонуйте среду вместе с вашими модулями в новое приложение. Вам может понадобиться распространять вместе с приложением некоторые дополнительные файлы, такие как формы и тексты меню.

MODULE Config;

	IMPORT Dialog;

	PROCEDURE Setup*;
		VAR res: INTEGER;
	BEGIN
		Dialog.Call("ObxPatterns.Deposit; StdCmds.Open", "", res)
	END Setup;

END Config.

DevLinker.Link Patterns.exe :=
Kernel$+ Files HostFiles StdLoader Math Sub Strings Dates Meta Dialog Services
Fonts Ports Stores Converters Sequencers Models Printers Views
Controllers Properties Printing Mechanisms Containers
Documents Windows StdCFrames Controls StdDialog StdCmds StdInterpreter
HostRegistry HostFonts HostPorts OleData HostMechanisms HostWindows 
HostPrinters HostClipboard HostCFrames HostDialog HostCmds
HostMenus HostPictures TextModels TextRulers TextSetters TextViews
TextControllers TextMappers StdLog TextCmds
FormModels FormViews FormControllers FormGen FormCmds
StdFolds StdLinks StdDebug HostTextConv HostMail
StdMenuTool StdClocks StdStamps StdLogos StdCoder StdScrollers
OleStorage OleServer OleClient StdETHConv Init ObxPatterns Config
1 applogo.Ico 2 doclogo.Ico 3 SFLogo.ico 4 CFLogo.ico 5 DtyLogo.ico
1 Move.cur 2 Copy.cur 3 Link.cur 4 Pick.cur 5 Stop.cur 6 Hand.cur 7 Table.cur ~


Процесс загрузки системы Блэкбокс
Запуск Блэкбокса происходит в несколько шагов.
Шаг 1: Операционная система загружает приложение
Блэкбокс состоит из одного маленького скомпонованного приложения и множества нескомпонованных кодовых файлов (по одному на каждый модуль). Скомпонованное приложение состоит по крайней мере из модуля Kernel. Когда операционная система загружает BlackBox, она передает управление телу модуля Kernel.
Шаг 2: Ядро загружает все прикомпонованные модули
Ядро инициализирует свои структуры данных, в частности, для управления памятью и обработки исключений. Затем оно выполняет тела других модулей, которые скомпонованы в приложении, в правильном порядке. Обычно среди прикомпонованных модулей есть StdLoader и несколько модулей, необходимых ему, в частности, Files и HostFiles. Модуль StdLoader реализует динамический загрузчик, который динамически связывает и загружает кодовые файлы модулей.
Шаг 3: Init загружает библиотеку Блэкбокса и ядро среды
Стандартная реализация модуля StdLoader вызывает из своего тела модуль Init. Если Init не прикомпонован, загрузчик пытается загрузить кодовый файл System/Code/Init. Если загрузка возможна, сначала загружаются модули, импортируемые из Init, а затем инициализируется собственно Init, то есть выполняется тело модуля.
Стандартная реализация Init импортирует все модули ядра среды и их стандартные реализации, но не подсистемы расширения, такие как Text или Form. Эти модули загружаются перед тем, как тело Init выполнит следующие действия:
 Пытается вызвать Startup.Setup.
Обычно модуль Startup не существует. Он может быть использован для установки некоторых служб до того, как откроется главное окно и загрузятся текстовая и другие подсистемы.
 Пытается загрузить модуль DevDebug.
DevDebug представляет собой более удобную замену для рудиментарных возможностей ядра по обработке исключений. Заметим, что стандартная реализация DevDebug использует текстовую подсистему, которая поэтому тоже загружается. Если загрузить DevDebug не удается, делается попытка загрузить модуль StdDebug. Это усеченная версия модуля DevDebug, которая может распространяться вместе с приложением.
 Регистрирует конвертер файлов документов (импортер/экспортер).
Это позволяет Блэкбоксу открывать и сохранять стандартные документы в формате системы Блэкбокс.
 Пытается вызвать StdMenuTool.UpdateAllMenus.
Эта команда читает и интерпретирует текст System/Rsrc/Menus и строит соответствующие меню. Заметим, что стандартная реализация StdMenuTool использует текстовую подсистему.

 Пытается вызвать Config.Setup.
Это обычный способ настроить BlackBox. Стандартная реализация Config.Setup устанавливает стандартные файловые и OLE конверторы и открывает окно рабочего журнала.

 Запускается главный цикл обработки событий (HostMenus.Run).
После завершения главного цикла (когда пользователь хочет выйти из приложения),  ядро вызывается для очистки перед тем, как приложение будет выгружено полностью.
Использование NEW и сборщика мусора в ваших приложениях
Если в приложении вызывается NEW и тем самым неявно предполагается использование сборщика мусора, то нужно связать Kernel с приложением. Процедура NEW реализована в ядре, и компилятор генерирует соответствующий код для вызова этой процедуры. Таким образом, каждый модуль, использующий NEW, производит скрытый импорт ядра.
Если импортировано ядро, не вызывайте WinApi.ExitProcess напрямую, вместо этого вызывайте Kernel.Quit с параметром 0, чтобы гарантировать, что все занятые системные ресурсы будут правильно освобождены перед остановкой приложения.
Программам нет нужды вызывать сборщик мусора напрямую. Если процедура NEW не может удовлетворить запрос на выделение памяти в куче, она сама вызовет сборщик мусора перед тем, как запросить новый блок кучи у Диспетчера памяти Windows. Сборщик мусора учитывает указатели в процедурных фреймах на стеке и способен работать в любой момент.
Сборщик мусора очищает все объекты кучи (динамические записи или переменные-массивы), которые больше не используются. Не используются означает, что объект не доступен ни напрямую из некоторого корневого указателя, ни косвенно через цепочку указателей, начинающуюся с корневого указателя. Любая глобальная переменная, содержащая указатель, является таким корнем. Если корневой указатель не NIL, тогда он является якорем для структуры данных. Объект в куче, который уже не имеет якоря, будет в конце концов зачищен сборщиком мусора.
Чтобы позволить сборщику мусора отслеживать цепочки указателей, должна присутствовать некоторая информация о просматриваемых объектах в куче. В частности, должно быть известно, где есть указатели на объект, если они есть. Все объекты одного типа имеют один общий описатель типа, который создается, когда загружается модуль, в котором этот тип определен.
Все динамически размещаемые записи Компонентного Паскаля содержат скрытое поле, которое называется тегом типа. Тег типа указывает на описатель типа, который содержит всю иформацию о типе, необходимую во время выполнения. Вызовы связанных с типом процедур, проверки типов и сборка мусора используют информацию, которая хранится в описателе типа. Описатель типа размещается только один раз для каждого записевого типа в системе.
Динамаически размещаемые массивы используют описатель размера для проверки границ индексов. Описатель размера также содержит тег для типа элементов. Для каждого динамического массива необходим свой описатель размера.
Дополнительная память, нужная для тегов объектов, делает их (объектов) расположение в памяти отличным от записей без тега, предоставляемых операционной системой или какими-либо разделяемыми библиотеками процедур. Наличие тегов типа критично; они не должны повреждаться, иначе сборщик мусора в какой-то момент времени обрушит систему.