Dev/Docu/ru/Linker.odc

DevLinker

DevLinker - это компоновщик BlackBox. Он используется для упаковки вместе нескольких файлов BlackBox в один исполняемый файл (.dll или .exe). Это может быть использовано для создания независимых версий приложений, основанных на BlackBox Component Framework. Также это можно использовать для создания исполняемых файлов, написанных на Компонентном Паскале, которые не относятся к среде BlackBox или используют только несколько модулей BlackBox, подобных Kernel.

Компоновщик может быть запущен одной из команд, описанных ниже. Каждая из команд нуждается в текстовых параметрах с синтаксисом:

<destFile> := {<module> {option}} {idNumber <resourceFile>}.

destFile - это имя исполняемого файла, который будет создан.
module - это модуль Компонентного Паскаля, кодовый файл загружается из соответствующей директории.
option - это один из следующих символов:
	$ главный модуль: тело этого модуля вызывается при запуске программы.
	+ идентифицирует ядро. Ядро должно быть представлено, если в каком-либо из модулей используется стандартная функция NEW. Ядро должно экспортировать процедуры NewRec и NewArr.
	# модуль интерфейса: экспортируемые процедуры этого модуля будут добавлены в список экспорта.
	См. описания отдельных команд, где приведены списки допустимых настроек.
resourceFile - это имя файла ресурсов. В настоящий момент поддерживаются значки (.ico), курсоры (.cur), растры (.bmp), файлы ресурсов Windows (.res) и библиотеки типов (.tlb). Файлы ресурсов загружаются из директорий Rsrc или Win/Rsrc.
idNumber - это целое число, используемое при обращении к ресурсу из программы.

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


DevLinker.Link
Компонует набор модулей, содержащий динамический загрузчик модулей, в exe-файл.
При запуске вызывается тело главного модуля.
Инициализация и прерывание всех остальных модулей не выполняется загрузчиком, это должно быть сделано подсистемой времени выполнения (обычно динамическим загрузчиком).
Сам BlackBox компонуется этой командой.
Допустимые настройки: $ +

DevLinker.LinkExe
Компонует нерасширяемый набор модулей в exe-файл (то есть, загрузчик не включается).
При запуске тела всех модулей вызываются в правильном порядке.
Когда последнее тело завершается, окончания (секции CLOSE) всех модулей вызываются в обратном порядке.
Никакой подсистемы времени выполнения не требуется для инициализации и завершения.
Допустимые настройки: +

DevLinker.LinkDll
Компонует нерасширяемый набор модулей в dll-файл.
Когда dll подключается к процессу, тела всех модулей вызываются в правильном порядке.
Когда dll освобождается процессом, окончания (секции CLOSE) всех модулей вызываются в обратном порядке.
Никакой подсистемы времени выполнения не требуется для инициализации и завершения.
Допустимые настройки: + #

DevLinker.LinkDynDll
(редко используется, представлено для полноты)
Компонует набор модулей, включающий динамический загрузчик модулей, в dll-файл.
Когда dll подключается к процессу, вызывается тело главного модуля.
Когда dll освобождается процессом, вызывается окончание (секция CLOSE) главного модуля.
Инициализация и прерывание всех остальных модулей должны выполняться подсистемой времени выполнения.
Допустимые настройки: $ + #

Причина различных команд для статических и динамических систем заключается в том, что отсутсвует статически определенная последовательность инициализации в системах, которые содержат динамический загрузчик. В BlackBox Kernel (который является самым низким модулем в иерархии) определен как главный модуль. Тело ядра затем динамически вызывает тела всех связанных модулей в правильном порядке. Если в телах модулей нет вызовов к динамическому загрузчику (через Dialog.Call), модули инициализируются в том порядке, в каком они присутсвуют в тексте параметров.


Примеры

Стандартный BlackBox:

DevLinker.Link
BlackBox.exe := Kernel$+ Files HostFiles StdLoader
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

Полностью скомпонованная часть BlackBox, доступная для распространения:

DevLinker.Link MyBlackBox.exe :=
Kernel$+ Files HostFiles StdLoader Math Strings Dates Meta Dialog Services
Fonts Ports Stores Log Converters Sequencers Models Printers Views
Controllers Properties Printing Mechanisms Containers
Documents Windows StdCFrames Controls StdDialog StdApi 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 In Out XYplane Init
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

Простое независимое приложение:

DevLinker.LinkExe
Simple.exe := Simple 1 applogo.Ico ~

Простая DLL:

DevLinker.LinkDll
Mydll.dll := Mydll# ~


MODULE Simple;
(* простое приложение Windows *)

	IMPORT S := SYSTEM, WinApi;

	CONST
		message = "Hello World";
		iconId = 1;

	VAR
		instance: WinApi.HINSTANCE;
		mainWnd: WinApi.HWND;

	PROCEDURE WndHandler (wnd, msg, wParam, lParam: INTEGER): INTEGER;
		VAR res: INTEGER; ps: WinApi.PAINTSTRUCT; dc: WinApi.HDC;
	BEGIN
		IF msg = WinApi.WM_DESTROY THEN
			WinApi.PostQuitMessage(0)
		ELSIF msg = WinApi.WM_PAINT THEN
			dc := WinApi.BeginPaint(wnd, ps);
			res := WinApi.TextOut(dc, 50, 50, message, LEN(message));
			res := WinApi.EndPaint(wnd, ps)
		ELSIF msg = WinApi.WM_CHAR THEN
			res := WinApi.Beep(800, 200)
		ELSE
			RETURN WinApi.DefWindowProc(wnd, msg, wParam, lParam)
		END;
		RETURN 0
	END WndHandler;

	PROCEDURE OpenWindow;
		VAR class: WinApi.WNDCLASS; res: INTEGER;
	BEGIN
		class.hCursor := WinApi.LoadCursor(0, S.VAL(WinApi.PtrSTR,
																			WinApi.IDC_ARROW));
		class.hIcon := WinApi.LoadIcon(instance, S.VAL(WinApi.PtrSTR, iconId));
		class.lpszMenuName := NIL;
		class.lpszClassName := "Simple";
		class.hbrBackground := WinApi.GetStockObject(WinApi.WHITE_BRUSH);
		class.style := WinApi.CS_VREDRAW + WinApi.CS_HREDRAW
						(* + WinApi.CS_OWNDC + WinApi.CS_PARENTDC *);
		class.hInstance := instance;
		class.lpfnWndProc := WndHandler;
		class.cbClsExtra := 0;
		class.cbWndExtra := 0;
		res := WinApi.RegisterClass(class);
		mainWnd := WinApi.CreateWindowEx({}, "Simple", "Simple Application",
														WinApi.WS_OVERLAPPEDWINDOW,
														WinApi.CW_USEDEFAULT, WinApi.CW_USEDEFAULT,
														WinApi.CW_USEDEFAULT, WinApi.CW_USEDEFAULT,
														0, 0, instance, 0);
		res := WinApi.ShowWindow(mainWnd, WinApi.SW_SHOWDEFAULT);
		res := WinApi.UpdateWindow(mainWnd);
	END OpenWindow;

	PROCEDURE MainLoop;
		VAR msg: WinApi.MSG; res: INTEGER;
	BEGIN
		WHILE WinApi.GetMessage(msg, 0, 0, 0) # 0 DO
			res := WinApi.TranslateMessage(msg);
			res := WinApi.DispatchMessage(msg);
		END;
		WinApi.ExitProcess(msg.wParam)
	END MainLoop;

BEGIN
	instance := WinApi.GetModuleHandle(NIL);
	OpenWindow;
	MainLoop
END Simple.


MODULE Mydll;
(* простой модуль, компонуемый в dll *)

	PROCEDURE Gcd* (a, b: INTEGER): INTEGER;
	BEGIN
		WHILE a # b DO
			IF a > b THEN a := a - b ELSE b := b - a END
		END;
		RETURN a
	END Gcd;
	
	PROCEDURE Lcm* (a, b: INTEGER): INTEGER;
	BEGIN
		RETURN a * b DIV Gcd(a, b)
	END Lcm;
	
END Mydll.