Динамически подгружаемые библиотеки
Желаю странного...
Хочется использовать подгружаемые библиотеки для формирования новых возможностей внутри проекта. Т.е. основная мысль такая: пишется ядро системы, которое умеет подгружать BPL через LoadPackage. Внутри LoadPackage вызывается Initialization, который умеет делать, например:
НО!!!
Получается очень нехорошая вещь, когда пишешь ядро и делаешь статическую линковку bpl, то все ОК (классы, функции и пр. видны в fsGlobalUnit), а когда подгружаешь через LoadPackage - то для каждой подружаемой bpl создается свой fsGlobalUnit. Господа-разработчики FS, поясните: это так задумано, или дело в моих руках?
Вот код тестового приложения:
EXE
Хочется использовать подгружаемые библиотеки для формирования новых возможностей внутри проекта. Т.е. основная мысль такая: пишется ядро системы, которое умеет подгружать BPL через LoadPackage. Внутри LoadPackage вызывается Initialization, который умеет делать, например:
initialization
Functions := TFunctions.Create;
где, в свою очередь, делается:
constructor TFunctions.Create;
begin
with fsGlobalUnit do
begin
AddedBy := Self;
with AddClass(TCommonDialog, 'TComponent') do
AddMethod('function Execute: Boolean', CallMethod);
AddClass(TOpenDialog, 'TCommonDialog');
AddClass(TSaveDialog, 'TCommonDialog');
AddClass(TColorDialog, 'TCommonDialog');
AddClass(TFontDialog, 'TCommonDialog');
AddedBy := nil;
end;
end;
Таким образом хочется написать ядро, и больше его не исправлять (компилировать, переустанавливать и т.д.), а дописывать библиотеки.НО!!!
Получается очень нехорошая вещь, когда пишешь ядро и делаешь статическую линковку bpl, то все ОК (классы, функции и пр. видны в fsGlobalUnit), а когда подгружаешь через LoadPackage - то для каждой подружаемой bpl создается свой fsGlobalUnit. Господа-разработчики FS, поясните: это так задумано, или дело в моих руках?
Вот код тестового приложения:
EXE
program fstst;
uses
Forms,
mfstst in 'mfstst.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit mfstst;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, fs_tree;
type
TForm1 = class(TForm)
fsTree1: TfsTree;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
LoadPackage('C:\Program Files\Borland\Delphi6\Projects\Bpl\fstst_pkg.bpl');
fsTree1.UpdateItems;
end;
end.
dfm
object Form1: TForm1
Left = 192
Top = 107
Width = 783
Height = 540
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object fsTree1: TfsTree
Left = 0
Top = 0
Width = 775
Height = 513
Align = alClient
BevelOuter = bvNone
Caption = 'fsTree1'
TabOrder = 0
ShowClasses = True
ShowFunctions = True
ShowTypes = True
ShowVariables = True
Expanded = True
ExpandLevel = 2
end
end
и соотвественно bpl:
package fstst_pkg;
{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$RUNONLY}
{$IMPLICITBUILD OFF}
requires
rtl,
vcl,
fs6;
contains
fs_tstrtti in 'fs_tstrtti.pas';
end.
unit fs_tstrtti;
interface
{$i fs.inc}
uses
SysUtils, Classes, fs_iinterpreter, fs_iclassesrtti, dialogs;
type
TfsTstRTTI = class(TComponent); // fake component
implementation
type
TFunctions = class(TObject)
private
function CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; var Params: Variant): Variant;
public
constructor Create;
destructor Destroy; override;
end;
var
Functions: TFunctions;
{ TFunctions }
constructor TFunctions.Create;
begin
with fsGlobalUnit do
begin
AddedBy := Self;
with AddClass(TCommonDialog, 'TComponent') do
AddMethod('function Execute: Boolean', CallMethod);
AddClass(TOpenDialog, 'TCommonDialog');
AddClass(TSaveDialog, 'TCommonDialog');
AddClass(TColorDialog, 'TCommonDialog');
AddClass(TFontDialog, 'TCommonDialog');
AddedBy := nil;
end;
end;
destructor TFunctions.Destroy;
begin
if fsGlobalUnit <> nil then
fsGlobalUnit.RemoveItems(Self);
inherited;
end;
function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; var Params: Variant): Variant;
var
s: String;
begin
Result := 0;
end;
initialization
Functions := TFunctions.Create;
finalization
Functions.Free;
end.
Комментарии
Я пример написал для Delphi, хотя живое, большое приложение живет в CBuilder ессно с packages. Я пробовал различные варианты - даже передачу указателя fsGlobalUnit в подгружаемый BPL, все равно получается какая-то фигня. Если у кого нибудь есть работающий пример киньте им в меня на m_a_o@mail.ru