Biblioteki DLL jako plugin - prośba o wypowiedź.

0

Ze względu na dość duży plik końcowy mojego programu postanowiłem część funkcji przenieść do biblioteki DLL i wykorzystywać je jako wtyczki do programu. Jako że mam bardzo małe doświadczenie w tym temacie (nigdy mi to nie było potrzebne) poniżej biblioteka DLL do obsługi jednej z firm kurierskich. Proszę o wypowiedź czy waszym zdaniem nie robię jakiegoś błędu.

Zastanawiałem się także aby rekordy pozamieniać na klasy oraz wszystkie stringi pozamieniać na PWideChar / PChar

library dpd;

(DPD_Type)

Type
  TReceiver = Packed Record
    Address: ShortString;
    City: ShortString;
    Company: ShortString;
    Name: ShortString;
    CountryCode: ShortString;
    Phone: ShortString;
    Code: ShortString;
  End;
(....)




uses
  DPD_Info in 'DPD_Info.pas',
  DPD_Proc in 'DPD_Proc.pas',
  DPD_Type, Windows;

const
  Version = '18.11.2015';

var
  DS: TDPDWebService;

{$R *.res}
  // ----------------------------------------------------------

Function DLLType: ShortString; stdcall;
begin
  Result := 'COURIER';
end;

Function DLLInfo: ShortString; stdcall;
begin
  Result := 'DPD';
end;

Function DLLVersion: ShortString; stdcall;
begin
  Result := Version;
end;

Procedure CloseDll(Reason: Integer);
begin
  if Reason = DLL_PROCESS_DETACH then
    DS.Free;
end;

// ----------------------------------------------------------

// DPDInfo

Function CodeToDescription(Code: PWideChar): ShortString; stdcall;
var
  DI: TDPDInfoWebService;
begin
  DI := TDPDInfoWebService.Create;
  Try
    Result := DI.CodeToDescription(Code);
  Finally
    DI.Free;
  End;
end;

Function GetStatusWaybill(Login, Password, WayBill: PWideChar): ShortString; stdcall;
var
  DI: TDPDInfoWebService;
begin
  DI := TDPDInfoWebService.Create;
  Try
    DI.Login := Login;
    DI.Password := Password;
    Result := DI.GetStatusWaybill(WayBill);
  Finally
    DI.Free;
  End;
end;

Function GetCodeWaybill(Login, Password, WayBill: PWideChar): ShortString; stdcall;
var
  DI: TDPDInfoWebService;
begin
  DI := TDPDInfoWebService.Create;
  Try
    DI.Login := Login;
    DI.Password := Password;
    Result := DI.GetCodeWaybill(WayBill);
  Finally
    DI.Free;
  End;
end;

// DPD Service

Procedure Authorization(Login, Password, FId: PWideChar); stdcall;
Begin
  DS.Login := Login;
  DS.Password := Password;
  DS.FId := FId;
End;

Procedure GenerateProtocol(ArrayPackageId: TArrayPackageID; FileName: PWideChar); stdcall;
Begin
  DS.GenerateProtocol(ArrayPackageId, FileName);
End;

procedure GenerateLabel(PackageId: Int64; FileName: String); stdcall;
begin
  DS.GenerateLabel(PackageId, FileName);
end;

function GetWayBill(Nr: Integer): ShortString; stdcall;
begin
  if Nr > High(DS.WayBill) then
    Exit('')
  else
    Exit(DS.WayBill[Nr])
end;

function CountWayBill: Integer; stdcall;
begin
  Result := High(DS.WayBill);
end;

Procedure NewPackage(const Sender: TSender;const Receiver: TReceiver;const PackInfo: TPackageInfo;const PackData: TArrayPackage); stdcall;
begin
  DS.NewPackage(Sender, Receiver, PackInfo, PackData);
end;


exports
  DLLType,
  DLLInfo,
  DLLVersion,
  CodeToDescription,
  GetStatusWaybill,
  GetCodeWaybill,
  Authorization,
  GetWayBill,
  CountWayBill,
  GenerateProtocol,
  GenerateLabel,
  NewPackage;

begin
  DS := TDPDWebService.Create;
  DLLProc := @CloseDll;
end.
1

Generalnie nie wygląda najgorzej, ale masz drobną niekonsekwencję w nazewnictwie:

  • raz tworzysz GetWaybill (przy okazji, pisane w taki sposób, a nie żadne WayBill!),
  • drugi raz NewPackage (czasownik vs rzeczownik z przymiotnikiem),
  • a potem jeszcze Authorization (czasownik vs rzeczownik z przymiotnikiem vs rzeczownik odczasownikowy, ale rozstrzał).

Trzymaj się jednej.
GetWaybill, CreatePackage, Authorize, GetWaybillCount - jest to bardzo istotne.

Przy okazji:
GetCodeWaybill - zwróć list przewozowy rodzaju kod (dosłownie tak to należy rozumieć, code jako przymiotnik do waybill, na pewno takie jest Twoje zamierzenie?)
GetWaybillCode - zwróć kod listu przewozowego

Nie rozumiem także, dlaczego tworzysz jedno TDPDWebService, ale już za każdym razem na nowo TDPDInfoWebService.

Zastanawiałem się także aby rekordy pozamieniać na klasy

Zdecydowanie nie.
Czasem klasy nie są przenośne między kompilatorami, a co dopiero różnymi językami.

1

Dodając do tego, co napisał kolega powyżej - rekordy są przenośne między kompilatorami i językami. Klasy, z założenia, są czarnymi skrzynkami i używając ich, nie powinieneś robić żadnych założeń co do tego, jak to faktycznie wygląda w środku. W wychodzącym niedługo FPC 3.0 napisano wprost:

Class field reordering: The compiler can now reorder instance fields in classes in order to minimize the amount of memory wasted due to alignment gaps.

3

Ze względu na dość duży plik końcowy mojego programu postanowiłem część funkcji przenieść do biblioteki DLL i wykorzystywać je jako wtyczki do programu.

Sam rozmiar exeka nie jest powodem by go dzielić na biblioteki.
Powodem może być pakiet kilku exeków które by używały wspólnej biblioteki, albo chęć zaimplementowania mechanizmu pluginów tak by ktoś mógł napisać własnego plugina do twojej aplikacji.

0
Azarien napisał(a):

Ze względu na dość duży plik końcowy mojego programu postanowiłem część funkcji przenieść do biblioteki DLL i wykorzystywać je jako wtyczki do programu.

Sam rozmiar exeka nie jest powodem by go dzielić na biblioteki.
Powodem może być pakiet kilku exeków które by używały wspólnej biblioteki, albo chęć zaimplementowania mechanizmu pluginów tak by ktoś mógł napisać własnego plugina do twojej aplikacji.

Poza tym, jakoś nikt nie wspomniał, podzielenie aplikacji na DLL nie zmniejszy tylko zwiększy (najczęściej) całkowity rozmiar aplikacji w plikach na dysku.
Powodem jest to, że każdy DLL będzie miał własną, wkompilowaną statycznie, część RTLa. Przekazywanie referencji na obiekty RTL/VCL pomiędzy Host a DLL to nie jest na pewno dobry pomysł, tylko raczej z tych fatalnych.
Żeby to zrobić dobrze, powinno się używać interfejsów zgodnych z COM. Wtedy na pewno wszystko będzie działało poprawnie bez względu na wersje kompilatora i wykorzystane kompilatory. Tylko to tak ze 100x więcej pisania...

1
wloochacz napisał(a):

Poza tym, jakoś nikt nie wspomniał, podzielenie aplikacji na DLL nie zmniejszy tylko zwiększy (najczęściej) całkowity rozmiar aplikacji w plikach na dysku.
Powodem jest to, że każdy DLL będzie miał własną, wkompilowaną statycznie, część RTLa. Przekazywanie referencji na obiekty RTL/VCL pomiędzy Host a DLL to nie jest na pewno dobry pomysł, tylko raczej z tych fatalnych.
Dlatego pisząc aplikację w VCL'u należałoby użyć dynamic RTL. Ale wtedy w katalogu aplikacji/systemowym powinny znaleźć się pliki *.bpl oraz kilka *.dll. Zmiany takiej dokonuje się w 2 miejscach w opcjach projektu. Pierwsza to "Use dynamic RTL" (zakładka Linker), druga "Link with runtime packages" (zakładka Packages).

Po takiej zmianie eksportuję klasy bezpośrednio. Z tym, że wszyscy w zespole muszą używać tych samych wersji Delphi/Buildera.

0
Mr.YaHooo napisał(a):
wloochacz napisał(a):

Poza tym, jakoś nikt nie wspomniał, podzielenie aplikacji na DLL nie zmniejszy tylko zwiększy (najczęściej) całkowity rozmiar aplikacji w plikach na dysku.
Powodem jest to, że każdy DLL będzie miał własną, wkompilowaną statycznie, część RTLa. Przekazywanie referencji na obiekty RTL/VCL pomiędzy Host a DLL to nie jest na pewno dobry pomysł, tylko raczej z tych fatalnych.
Dlatego pisząc aplikację w VCL'u należałoby użyć dynamic RTL. Ale wtedy w katalogu aplikacji/systemowym powinny znaleźć się pliki *.bpl oraz kilka *.dll. Zmiany takiej dokonuje się w 2 miejscach w opcjach projektu. Pierwsza to "Use dynamic RTL" (zakładka Linker), druga "Link with runtime packages" (zakładka Packages).

Po takiej zmianie eksportuję klasy bezpośrednio. Z tym, że wszyscy w zespole muszą używać tych samych wersji Delphi/Buildera.

Fajnie, tylko że nie ma takich opcji w Delphi, są dostępne dla C++ Builder. A tu rozmawiamy o Delphi, prawda?
No i nie jestem na 100% pewien (nie używam Buildera i po prostu nie mam doświadczeń na tym polu), czy to pozwoli na dynamiczne łączenie kodu w DLL z RTL. Z pakietami na pewno, ale czy z DLL - nie wiem.

0

A to nie wystarczy zaznaczyć w Delphi opcję Packages -> Build with runtime Packages? U mnie na RAD XE (mam triala, bo mam wykupioną licencję na samego C++ Buildera 2009) przed włączeniem opcji czysty exec z 1 formą waży 894kB i ma odwołania do samych systemowych dll'ek. Po zaznaczeniu tej opcji mam 106kB oraz odwołania do plików *.bpl.

Nie wiem jak w innych wersjach, ale niestety tu masz rację. W RAD 2009 jak użyjesz dynamicznego łączenia RTL to nie będziesz w stanie dynamicznie załadować takiego pliku dll. Pojawi się access violation. Ale z drugiej strony jeśli chcemy aby plik był dynamicznie ładowany, to wtedy zazwyczaj nie trzeba integrować wewnętrznych obiektów jak TApplication pliku exe oraz dll, i naturalnie wtedy udostępniamy funkcje które przyjmują jako parametry obiekty VCL.

Ogólnie to nie wyobrażam sobie pisać plugin do jakiegoś obcego programu jak np. Winamp i dostarczać w paczce również 20 plików bpl...

2
Mr.YaHooo napisał(a):

A to nie wystarczy zaznaczyć w Delphi opcję Packages -> Build with runtime Packages? U mnie na RAD XE (mam triala, bo mam wykupioną licencję na samego C++ Buildera 2009) przed włączeniem opcji czysty exec z 1 formą waży 894kB i ma odwołania do samych systemowych dll'ek. Po zaznaczeniu tej opcji mam 106kB oraz odwołania do plików *.bpl.

I tak to działa, ale tylko i wyłącznie dla projektu zbudowanego z runtime BPL. Nie DLL. To nie jest to samo i nigdy nie było.

Nie wiem jak w innych wersjach, ale niestety tu masz rację. W RAD 2009 jak użyjesz dynamicznego łączenia RTL to nie będziesz w stanie dynamicznie załadować takiego pliku dll. Pojawi się access violation. Ale z drugiej strony jeśli chcemy aby plik był dynamicznie ładowany, to wtedy zazwyczaj nie trzeba integrować wewnętrznych obiektów jak TApplication pliku exe oraz dll, i naturalnie wtedy udostępniamy funkcje które przyjmują jako parametry obiekty VCL.

Tylko co to za plugin, którego trzeba linkować statycznie?

Ogólnie to nie wyobrażam sobie pisać plugin do jakiegoś obcego programu jak np. Winamp i dostarczać w paczce również 20 plików bpl...

Bo to nie ten rodzaj pluginu i nie ten poziom abstrakcji.
Rasowe (czyli takie, które możesz zaimplementować we wszystkich językach, które wspierają COM) pluginy pisze się jako interfejsy COM. Koniec i kropka.
Ja nie mam takich potrzeb i piszę pluginy oparte jako BPL.

Natomiast sama różnica pomiędzy BPL i DLL w Delphi/Builder jest taka, że masz jedną kopię RTL i de facto jeden proces w przypadku BPL i wiele dla DLL (oczywiście jest shared memory manager itd. ale to i tak jest krzywe). Dlatego w przypadku BPL, w runtime nie ma różnicy, czy aplikacja składa się z jednego exe czy z jednego exe i 100 BPL. Działa dokładnie tak samo i możesz sobie bezpiecznie trzymać referencję obiektu w BPL utworzonego w innym BPL i przekazaniu go do EXE.

Ale jeśli cokolwiek wyrzucisz do DLL, to każdy DLL będzie miał własną kopię RTL. I tak jest w Delphi, a w Builder -nie jestem pewien na 100%.

0
wloochacz napisał(a):

I tak to działa, ale tylko i wyłącznie dla projektu zbudowanego z runtime BPL. Nie DLL. To nie jest to samo i nigdy nie było.
Racja, doczytałem co nie co na ten temat i wygląda na to, że Delphi pod tym względem jest bardziej ubogie niż C++ Buulder.

wloochacz napisał(a):

Tylko co to za plugin, którego trzeba linkować statycznie?
Niestety żaden. Ale też jak dla mnie plugin który wymaga 30+ plików to jest też słaby plugin. Dlatego ja pluginy piszę tak aby nawet nie było trzeba integrować wewnetrzych obiektów RTL i kompiluję dołączając RTL.

wloochacz napisał(a):

Bo to nie ten rodzaj pluginu i nie ten poziom abstrakcji.
Rasowe (czyli takie, które możesz zaimplementować we wszystkich językach, które wspierają COM) pluginy pisze się jako interfejsy COM. Koniec i kropka.
Ja nie mam takich potrzeb i piszę pluginy oparte jako BPL.
I to jest w sumie najlepsze rozwiązanie. Wtedy masz pewność, że wszystko zadziała.

wloochacz napisał(a):

Natomiast sama różnica pomiędzy BPL i DLL w Delphi/Builder jest taka, że masz jedną kopię RTL i de facto jeden proces w przypadku BPL i wiele dla DLL (oczywiście jest shared memory manager itd. ale to i tak jest krzywe). Dlatego w przypadku BPL, w runtime nie ma różnicy, czy aplikacja składa się z jednego exe czy z jednego exe i 100 BPL. Działa dokładnie tak samo i możesz sobie bezpiecznie trzymać referencję obiektu w BPL utworzonego w innym BPL i przekazaniu go do EXE.

Ale jeśli cokolwiek wyrzucisz do DLL, to każdy DLL będzie miał własną kopię RTL. I tak jest w Delphi, a w Builder -nie jestem pewien na 100%.
Właśnie rozeznałem się dokładniej o co biega. Żeby była jedna kopia RTL w Delphi musisz mieć pakiet (czy jak to się po Polsku nazywa?) Natomiast C++ Builder robi tak, że uzależnia to od tego jak linkujemy RTL, jeśli dynamicznie to wtedy dll oraz exe mają wspólny RTL oraz obiekty typu TApplication. Jeśli w pliku dll zlinkuję statycznie RTL (bez potrzeby dawania plików BPL Buildera klientom) to exe oraz dll mają swoje obiekty.

A to jak ma Builder mówię z praktyki. W pracy piszę w Builderze. Cały system podzielony jest na mniej więcej 20 plików dll. Moduły podzielone są ze względu na funkcjonalność. Plik exe to jest tylko tak naprawdę po to aby powołać do życia niezbędne klasy systemu oraz wywoływać z menu głównego okna które siedzą w dll'kach. Co więcej całość jest napisana w trybie MDI, od taka zachcianka klientów. Dynamiczne linkowanie RTL sprawia, że we wszystkich plikach dll mam dostęp do 1 wspólnego RTL oraz obiektów VCL. Okno MDIParent ładnie współpracuje z oknami MDIChild zawartymi w plikach dll. Tylko, że pliki dll są linkowane statycznie do exe. Ale w przypadku mojego systemu nie ma innej potrzeby. Pluginów mam parę i tam nie potrzebuje wspólnego RTL, bo one obsługują raczej urządzenia zewnętrzne.

Na koniec jeszcze chcę napisać, że zdziwiło mnie takie różne zachowanie Delphi/Buildera. Myślałem, że skoro VCL jest ten sam to poruszone tu zagadnienie jest rozwiązane identycznie w obu środowiskach. A tu taka niemiła niespodzianka...

0
Mr.YaHooo napisał(a):

Na koniec jeszcze chcę napisać, że zdziwiło mnie takie różne zachowanie Delphi/Buildera. Myślałem, że skoro VCL jest ten sam to poruszone tu zagadnienie jest rozwiązane identycznie w obu środowiskach. A tu taka niemiła niespodzianka...

O ile same biblioteki RTL i VCL a także IDE są podobne to kompilatory się różnią w C++ Builder jest więcej możliwości wspomniana opcja Link with Dynamic RTL oznacza że plik wynikowy do działania będzie wymagał zewnętrznej DLL cc32XX.dll czyli coś jak msvcrXX.dll z VC++ dlatego plik wynikowy EXE jest dużo mniejszy od Delphi które nigdy takiej opcji nie miało. W Delphi (oczywiście w C++ Builder też) można tylko Link with runtime packages wtedy trzeba dodać odpowiednie biblioteki BPL.

0
Mr.YaHooo napisał(a):
wloochacz napisał(a):

I tak to działa, ale tylko i wyłącznie dla projektu zbudowanego z runtime BPL. Nie DLL. To nie jest to samo i nigdy nie było.
Racja, doczytałem co nie co na ten temat i wygląda na to, że Delphi pod tym względem jest bardziej ubogie niż C++ Buulder.

wloochacz napisał(a):

Tylko co to za plugin, którego trzeba linkować statycznie?
Niestety żaden. Ale też jak dla mnie plugin który wymaga 30+ plików to jest też słaby plugin. Dlatego ja pluginy piszę tak aby nawet nie było trzeba integrować wewnetrzych obiektów RTL i kompiluję dołączając RTL.

To zależy co się robi i jakie są potrzeby danego pluginu. Mnie te 30 BPL zupełnie nie przeszkadza (tak naprawdę to mam 131 BPL runtime + 25 moich pluginów z których składa się framework + 12 pluginów stricte biznesowych). Plugin, w moim rozumieniu, to jest pewna konkretna funkcjonalność systemu. Np. mam osobny plugin, który zarządza obsługą okien, kreacją klas, obsługą gridów, obsługą DAL itd.
Do tego są pluginy, które niosą konkretną funkcjonalność biznesową (np. podsystem obsługi rozrachunków - aczkolwiek u mnie czegoś takiego nie ma, bo te nie ten rodzaj sytemu).
I na końcu są pluginy, które zmieniają (po prostu ładuję w locie inną implementację czegoś tam, ponieważ inny klient ma inne wymagania niż standard) lub rozszerzają istniejącą logikę biznesową.
Dlaczego tak? A dlaczego nie? :)
Dzięki temu, mam jeden core systemu i de-facto wiele różnych aplikacji.
Dzięki temu, mam na jednym core zbudowaną aplikację okienkową, REST Serwer, usługi, itd.
Czym ma być dana aplikacja i jak ma działać zależy od konfiguracji pluginów, a nie od kodu sensu stricte.

wloochacz napisał(a):

Bo to nie ten rodzaj pluginu i nie ten poziom abstrakcji.
Rasowe (czyli takie, które możesz zaimplementować we wszystkich językach, które wspierają COM) pluginy pisze się jako interfejsy COM. Koniec i kropka.
Ja nie mam takich potrzeb i piszę pluginy oparte jako BPL.
I to jest w sumie najlepsze rozwiązanie. Wtedy masz pewność, że wszystko zadziała.

Tak, to prawda. Ale ma swoje poważne wady. Mnie zależało na tym, abym mógł dodać lub zmienić dowolny kawałek systemu - to się da zrobić za pomocą COM, ale... nas jest na to za mało, żeby to napisać w rozsądnym czasie.
Dzięki BPLom mam rozwiązanie problemy z kompatybilnością, kosztem przywiązania się do jednego środowiska.
Ale za to rozwijanie aplikacji, to de-facto pisanie kodu biznesowego - resztę załatwiają pluginy framework'owe.

wloochacz napisał(a):

Natomiast sama różnica pomiędzy BPL i DLL w Delphi/Builder jest taka, że masz jedną kopię RTL i de facto jeden proces w przypadku BPL i wiele dla DLL (oczywiście jest shared memory manager itd. ale to i tak jest krzywe). Dlatego w przypadku BPL, w runtime nie ma różnicy, czy aplikacja składa się z jednego exe czy z jednego exe i 100 BPL. Działa dokładnie tak samo i możesz sobie bezpiecznie trzymać referencję obiektu w BPL utworzonego w innym BPL i przekazaniu go do EXE.

Ale jeśli cokolwiek wyrzucisz do DLL, to każdy DLL będzie miał własną kopię RTL. I tak jest w Delphi, a w Builder -nie jestem pewien na 100%.
Właśnie rozeznałem się dokładniej o co biega. Żeby była jedna kopia RTL w Delphi musisz mieć pakiet (czy jak to się po Polsku nazywa?) Natomiast C++ Builder robi tak, że uzależnia to od tego jak linkujemy RTL, jeśli dynamicznie to wtedy dll oraz exe mają wspólny RTL oraz obiekty typu TApplication. Jeśli w pliku dll zlinkuję statycznie RTL (bez potrzeby dawania plików BPL Buildera klientom) to exe oraz dll mają swoje obiekty.

OK, ale to jest praktycznie to samo, z tym że rozszerzenie pliku jest DLL a nie BPL. Zresztą, BPL to jest DLL tylko taki specjalny - Delphiowy ;-)

A to jak ma Builder mówię z praktyki. W pracy piszę w Builderze. Cały system podzielony jest na mniej więcej 20 plików dll. Moduły podzielone są ze względu na funkcjonalność. Plik exe to jest tylko tak naprawdę po to aby powołać do życia niezbędne klasy systemu oraz wywoływać z menu głównego okna które siedzą w dll'kach. Co więcej całość jest napisana w trybie MDI, od taka zachcianka klientów. Dynamiczne linkowanie RTL sprawia, że we wszystkich plikach dll mam dostęp do 1 wspólnego RTL oraz obiektów VCL. Okno MDIParent ładnie współpracuje z oknami MDIChild zawartymi w plikach dll. Tylko, że pliki dll są linkowane statycznie do exe. Ale w przypadku mojego systemu nie ma innej potrzeby. Pluginów mam parę i tam nie potrzebuje wspólnego RTL, bo one obsługują raczej urządzenia zewnętrzne.

Mam podobnie, z tym, że wszystko jest dynamiczne.
No i mam wrażenie, że u mnie jest większa separacja pomiędzy pluginami (pluginy biznesowe nie zależą od siebie, a po drugie - jeden o drugim nie ma pojęcia; a więc plugin A może nie wiedzieć, że jego logikę modyfikuje plugin B - IoC w czystej postaci) i być może większa elastyczność.

Na koniec jeszcze chcę napisać, że zdziwiło mnie takie różne zachowanie Delphi/Buildera. Myślałem, że skoro VCL jest ten sam to poruszone tu zagadnienie jest rozwiązane identycznie w obu środowiskach. A tu taka niemiła niespodzianka...

Miła czy niemiła, kwestia dyskusyjna...
De-facto rozwiązania są podobne.
Poza tym mało kto wie, że Delphi można zmusić aby nie robiła 100 BPL, tylko np. jeden. Ale trzeba naprawdę wiedzieć co się robi, a zysk jest tylko taki że nie będzie 100 plików.
Dla mnie to żaden zysk, to praca na którą szkoda prądu, zwłaszcza że można się tam pomylić i wszystko zacznie się pięknie sypać.

0
kAzek napisał(a):

O ile same biblioteki RTL i VCL a także IDE są podobne to kompilatory się różnią w C++ Builder jest więcej możliwości wspomniana opcja Link with Dynamic RTL oznacza że plik wynikowy do działania będzie wymagał zewnętrznej DLL cc32XX.dll czyli coś jak msvcrXX.dll z VC++ dlatego plik wynikowy EXE jest dużo mniejszy od Delphi które nigdy takiej opcji nie miało. W Delphi (oczywiście w C++ Builder też) można tylko Link with runtime packages wtedy trzeba dodać odpowiednie biblioteki BPL.
Tak jest. Szkoda, bo akurat takie możliwości jakich nie ma w Delphi jest po prostu wymagane w mojej pracy. Zupełnie nie rozumiem dlaczego nie ma tu tej opcji. Przecież to nie jest trudna sprawa do zrobienia tak naprawdę.

wloochacz napisał(a):

To zależy co się robi i jakie są potrzeby danego pluginu. Mnie te 30 BPL zupełnie nie przeszkadza (tak naprawdę to mam 131 BPL runtime + 25 moich pluginów z których składa się framework + 12 pluginów stricte biznesowych). Plugin, w moim rozumieniu, to jest pewna konkretna funkcjonalność systemu. Np. mam osobny plugin, który zarządza obsługą okien, kreacją klas, obsługą gridów, obsługą DAL itd.
Do tego są pluginy, które niosą konkretną funkcjonalność biznesową (np. podsystem obsługi rozrachunków - aczkolwiek u mnie czegoś takiego nie ma, bo te nie ten rodzaj sytemu).
To ja mam tak, że wszystkie funkcje typu obsługa grida, uprawnień, logowanie usera są wydzielone do oddzielnej dll'ki. W każdej pozostałej dllce siedzi sobie moduł odpowiadający np. za magazyn. Dodatkowo są pluginy typu obsługa jakiejś drukarki czy podobnego sprzętu.

wloochacz napisał(a):

I na końcu są pluginy, które zmieniają (po prostu ładuję w locie inną implementację czegoś tam, ponieważ inny klient ma inne wymagania niż standard) lub rozszerzają istniejącą logikę biznesową.
Dlaczego tak? A dlaczego nie? :)
Dzięki temu, mam jeden core systemu i de-facto wiele różnych aplikacji.
Dzięki temu, mam na jednym core zbudowaną aplikację okienkową, REST Serwer, usługi, itd.
Czym ma być dana aplikacja i jak ma działać zależy od konfiguracji pluginów, a nie od kodu sensu stricte.
Bardzo przyjemne rozwiązanie. U mnie z kolei zostało to zaprojektowane w ten sposób, że to co ma się różnić pomiędzy klientami jest po prostu parametryzowane. Tak więc tak naprawdę klient ma całość systemu wraz ze wszystkimi funkcjonalnościami. Kwestia ustawienia parametrów. Mi osobiście to się nie podoba. Ale cóż, kiedyś może ktoś mnie posłucha i postawi na większą elastyczność :)

wloochacz napisał(a):

Tak, to prawda. Ale ma swoje poważne wady. Mnie zależało na tym, abym mógł dodać lub zmienić dowolny kawałek systemu - to się da zrobić za pomocą COM, ale... nas jest na to za mało, żeby to napisać w rozsądnym czasie.
Dzięki BPLom mam rozwiązanie problemy z kompatybilnością, kosztem przywiązania się do jednego środowiska.
Ale za to rozwijanie aplikacji, to de-facto pisanie kodu biznesowego - resztę załatwiają pluginy framework'owe.
Pewnie u mnie też jest za mało ludzi aby pisać bardziej uniwersalny i modułowy system.

wloochacz napisał(a):

OK, ale to jest praktycznie to samo, z tym że rozszerzenie pliku jest DLL a nie BPL. Zresztą, BPL to jest DLL tylko taki specjalny - Delphiowy ;-)
Tak jest. Zastanawia mnie dlaczego takie rzeczy różnią się po prostu pomiędzy dwoma bliźniaczymi środowiskami. Dla mnie to niepojęte...

wloochacz napisał(a):

Mam podobnie, z tym, że wszystko jest dynamiczne.
No i mam wrażenie, że u mnie jest większa separacja pomiędzy pluginami (pluginy biznesowe nie zależą od siebie, a po drugie - jeden o drugim nie ma pojęcia; a więc plugin A może nie wiedzieć, że jego logikę modyfikuje plugin B - IoC w czystej postaci) i być może większa elastyczność.
No i macie lepiej to rozwiązane moim zdaniem. Kiedyś chciałem przeforsować rozwiązanie podobne do Twojego, ale okazało się że będzie za dużo roboty. Moduły po prostu są ze sobą za mocno powiązane i tyle.

wloochacz napisał(a):

Miła czy niemiła, kwestia dyskusyjna...
De-facto rozwiązania są podobne.
Poza tym mało kto wie, że Delphi można zmusić aby nie robiła 100 BPL, tylko np. jeden. Ale trzeba naprawdę wiedzieć co się robi, a zysk jest tylko taki że nie będzie 100 plików.
Dla mnie to żaden zysk, to praca na którą szkoda prądu, zwłaszcza że można się tam pomylić i wszystko zacznie się pięknie sypać.
Oczywiście. Pytanie tylko czy jest sens zabawy aby był 1 plik, a nie 100. Mi osobiście nie przeszkadza te około 150 plików w Program Files. W końcu i tak robi się instalator który odwala całą robotę podczas instalacji/aktualizacji.

0

btw mowiac juz o dll to czemu nie w oparciu o interface ?
Jesli juz nalezy przekazywac miedzy hostem a dll to nie klasy ale interface (klasa implementuje intrface).
Dana instancja interface zawsze ma ta sama strukture w pamieci bez wzgledu na jezyk czy wersje kompilatora(jest kompatybilna binarnie)

1 użytkowników online, w tym zalogowanych: 0, gości: 1