-
Данная информация не претендует на оригинальность и правильность, тем не менее всё было испытано на Delphi 7 и проблем выявлено не было.
Конечно с переходом на Win были у меня непонятки, вообще, мягко говоря, Win осью не считаю (так же как и использование динамических библиотек, сторонник того, что бинарник должен носить всё свое с собой, за исключением, естественно, системных функций, libc рулит), тем не менее поиграться с компилятором Дельфи очень интересно и выявлять разные фичи. Только очень прошу не писать сообщения вида "и так все знали, открыл Америку". Искал по форумам, информации не находил... Так что делюсь некоторыми наработками.
Использование плагинов оказалось удобной вещью, отключение ненужного кода облегчается простым удалением ненужной в данной момент библиотеки (или более мягким - выгрузкой программно). Проще сконцентрировать внимание на оснастке. Из недостатков - курирование уже нескольких модулей, написание интерфейса для плагинов, да и при использовании объектов KOL - необходимо чтобы всегда совпадали флаги компиляции и использовалась единая версия библиотеки.
Стало быть тоже был очарован эффектами GRush контролов, но проблема заключалась в том, что код этих контролов при использовании в исполнительном модуле и в библиотеках всё время дублировался, что не есть хорошо. Размер невелик, всего лишь ~20-30Кб, но если таких плагинов 20? Уже 500Кб побочного кода. Тода-то и подумалось об smart-linked, не будет он цеплять код, если он мог быть продублирован в другом месте, а в рабочем приложении останутся только определения. Так и поступил с GRush: создал отдельную библиотеку.
grush.dpr +++++++++++ library grush;
uses KOLGRushControls;
exports NewGRushButton, NewGRushPanel, NewGRushCheckBox, NewGRushRadioBox, NewGRushSplitter, NewGRushProgressBar;
begin end. +++++++++++
Далее надо указать что эти функции у нас внешние:
+++++++++++ function NewGRushButton(AParent: PControl; Caption: String):PGRushControl; external 'grush.dll'; function NewGRushPanel(AParent: PControl):PGRushControl; external 'grush.dll'; function NewGRushCheckBox(AParent: PControl; Caption: String):PGRushControl; external 'grush.dll'; function NewGRushRadioBox(AParent: PControl; Caption: String):PGRushControl; external 'grush.dll'; function NewGRushSplitter(AParent: PControl; MinSizePrev, MinSizeNext: Integer):PGRushControl; external 'grush.dll'; function NewGRushProgressBar(AParent: PControl):PGRushControl; external 'grush.dll'; +++++++++++
Экономия на лицо. Можем пойти еще дальше - линковать эти фукции и подгружать библиотеку самим. Для этого переопределяим их как свои функции, в случае использования MCK так:
+++++++++++ unit sample;
interface
<..> procedure _init_grush; function NewGRushButton(AParent: PControl; Caption: String):PGRushControl; function NewGRushPanel(AParent: PControl):PGRushControl; function NewGRushCheckBox(AParent: PControl; Caption: String):PGRushControl; function NewGRushRadioBox(AParent: PControl; Caption: String):PGRushControl; function NewGRushProgressBar(AParent: PControl):PGRushControl;
var _NewGRushButton: function (AParent: PControl; Caption: String):PGRushControl; _NewGRushPanel: function (AParent: PControl):PGRushControl; _NewGRushCheckBox: function (AParent: PControl; Caption: String):PGRushControl; _NewGRushRadioBox: function (AParent: PControl; Caption: String):PGRushControl; _NewGRushProgressBar: function (AParent: PControl):PGRushControl; enGrush: boolean = false;
implementation <..> procedure _init_grush; var hdll : thandle; begin hdll := LoadLibrary('grush.dll'); if hdll = 0 then exit; _NewGRushButton := GetProcAddress(hdll, 'NewGRushButton'); _NewGRushPanel := GetProcAddress(hdll, 'NewGRushPanel'); _NewGRushCheckBox := GetProcAddress(hdll, 'NewGRushCheckBox'); _NewGRushRadioBox := GetProcAddress(hdll, 'NewGRushRadioBox'); _NewGRushProgressBar := GetProcAddress(hdll, 'NewGRushProgressBar');
if Assigned(_NewGRushButton) and Assigned(_NewGRushPanel) and Assigned(_NewGRushCheckBox) and Assigned(_NewGRushProgressBar)
then enGrush := true else FreeLibrary(hdll); end;
function NewGRushButton(AParent: PControl; Caption: String):PGRushControl; begin if enGrush then Result := _NewGRushButton(AParent, Caption) else Result := PGRushControl(NewButton(Aparent, Caption)); end;
function NewGRushPanel(AParent: PControl):PGRushControl; begin if enGrush then Result := _NewGRushPanel(AParent) else Result := PGRushControl(NewPanel(AParent, esSolid)); end;
function NewGRushCheckBox(AParent: PControl; Caption: String):PGRushControl; begin if enGrush then Result := _NewGRushCheckBox(AParent, Caption) else Result := PGRushControl(NewCheckBox(Aparent, Caption)); end;
function NewGRushRadioBox(AParent: PControl; Caption: String):PGRushControl; begin if enGrush then Result := _NewGRushRadioBox(AParent, Caption) else Result := PGRushControl(NewRadioBox(Aparent, Caption)); end;
function NewGRushProgressBar(AParent: PControl):PGRushControl; begin if enGrush then Result := _NewGRushProgressBar(AParent) else Result := PGRushControl(NewProgressBar(Aparent)); end; <..> +++++++++++
Главное теперь не менять свойства этих контролов. По сути дела предок TGushControl является TControl, за сим все его свойства и методы будут открыты, нельзя в данном случае пользоваться специфичными для GRush методами. Или же программно ставить условие
if aButton.SubClassName = 'obj_GRUSH_BUTTON' or <..> then <..>
^по рекурсии дочерних контролов формы так делал стилизатор ;)
Но если случилась беда, и поменяли свойство - лезем в dfm-файло и удаляем все ненужные записи, относящиеся к GRush-контролам, чтобы MCK этот для нас "мусор" всё время не цеплял.
Задача упрощается, если не использовать MCK, тогда мы просто можем результ этих функций привести к PControl и тогда не сделаем ошибок в коде. Что уж говорить о "гигантах" в виде unzip60, zlib, JpegObj и тому подобное... всё делается аналогично. Функции будут вызываться дельфишным способом, с передачей параметров через регистры, соответственно скорость падать не будет (не имелось ввиду что и зацепка функций в обжектах через cdecl или stdcall, которая используется, например, в JpegObj). Надеюсь кому-нибудь будет это полезно.
Сан Саныч aka rednakse
|