Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi bpl einbinden über Interface (https://www.delphipraxis.net/192677-bpl-einbinden-ueber-interface.html)

Lemmy 10. Mai 2017 09:30

Delphi-Version: 7

bpl einbinden über Interface
 
Hallo,
ich habe hier ein Delphi 7 Projekt, das nicht so schnell und einfach auf eine höhere Delphi-Version umgestellt werden kann (wobei wir dran arbeiten). Es gibt einen Funktionsbereich, der allerdings nicht sauber funktioniert und ich den gerne mit einer höheren Delphi-Version umsetzen würde, weil der Bereich damit problemlos geht.

Dazu habe ich 2 Optionen:
1. eigenständiges Programm
2. DLL / BPL

Da ich Daten zwischen den Bereichen austauschen muss, fällt 1 schon mal fast weg, obwohl über MemoryMappedFiles sicherlich Möglichkeiten da wären unstrukturierte Daten auszutauschen.

//Edit:
So Dinge wie Kommunikation über Http (sprich das externe Programm hat nen http-Server eingebaut mit dem ich dann kommuniziere) sowie COM fallen weg, da das ganze dann auch bei Kunden laufen muss, ohne dass ich ständig hinter her renne um lokal irgend welche seltsamen Firewall oder Systemkonfigurationen zu korrigieren //Edit

DLL: würde schon mehr Möglichkeiten bieten, brauch aber den Speichermanager von Borland.

BPL: da habe ich die Möglichkeit über Interfaces doch einfacher Dinge auszutauschen. Allerdings kenne ich da die Beispiele nur, wenn die "Hauptanwendung" und die bpl mit der selben Delphi-Version geschrieben sind.

Mal eben flux ein Beispiel aufgesetzt:

Interface:

Delphi-Quellcode:
type
  ITest = Interface
  ['{4BED69D1-E83F-4F85-8DA3-7E2F199F427C}']
    function GetName: Ansistring;
    procedure Test2(const AValue: AnsiString);

    property Name: AnsiString read GetName;
  end;
Das wird im Projekt XE4 in einer BPL abgebildet und implementiert

Delphi-Quellcode:
type
  TFoo = class(TInterfacedObject, ITest)
    FName: Ansistring;
  public
    function GetName: Ansistring;
    procedure Test2(const AValue: Ansistring);
  end;

implementation

{ TFoo }

function TFoo.GetName: Ansistring;
begin
  result := FName;
end;

procedure TFoo.Test2(const AValue: Ansistring);
begin
  FName := 'Hallo ' + AValue;
end;

und schließlich exportiert:

Delphi-Quellcode:
function InitFoo: ITest;


exports
   InitFoo;

implementation

uses Impl;

function InitFoo: ITest;
begin
  result := TFoo.Create;
end;

In Delphi 7 im "Hauptprogramm" dann dynamisch eingebunden:

Delphi-Quellcode:
type
  TInitProc = function (): ITest;

procedure TForm1.LoadBPL;
var
  createI: TInitProc;
begin
  FBplHandle := LoadPackage(PChar('x:\foo\PackageProj.bpl'));
  if FBplHandle <> 0 then begin
    createI := GetProcAddress(FBplHandle, 'InitFoo');
    FTest := createI();
  end
  else
  begin
    raise Exception.Create('BPL konnte nicht geladen werden.');
  end;
end;

und ich kann anschließend mit dem Interface arbeiten, d.h. Strings übergeben und auch Strings abrufen. Und das alles mit unterschiedlichen Delphi-Versionen und ohne böse Fehlermeldung. Ich war doch sehr überrascht wie schmerzlos das ganze geht.

Nun endlich die Fragen:
1. Warum brauche ich hier keinen extra Verweis auf den Speichermanager von Borland, der bei DLLs und Strings quasi Pflicht ist? Steckt der in der bpl schon grundsätzlich drin?
2. Wenn das Beispiel komplexer wird und ich in der bpl weitere Delphipackages (rtl, Soap) benötige, machen die mir ggf. dann irgend wann Probleme, weil im Hauptprogramm Packages/Units mit den selben Namen schon vorhanden sind?
3. Gibt es irgend etwas das ich in meiner Euphorie übersehe?

Grüße

Ghostwalker 10. Mai 2017 12:04

AW: bpl einbinden über Interface
 
Zu. 1:

Dll's werden vom BS gemanaget. Den Speichermanager von Borland brauchst du eben wegen der Strings, da die Stringverwaltung vom BS (Windows) ganz anders läuft, als die von Delphi. BPL's sind dagegen eine Erfindung von
Borland/Codegear/Emba und lassen sich auch nur mit deren Compiler/Linker nutzen. Damit ist quasi gegeben,
das BPL und Programm den gleichen Speichermanager nutzen :)

Zu 2:

Ja, insbesondere wenn die entsprechenden Packages mit unterschiedlichen Delphi-Versionen klarkommen müssen.

Zu 3:

Vermutlich. Ich habs jetzt noch nicht ausprobiert, aber ich fürchte das ein D7-Package mit XE-Programm nicht so wirklich funktionieren wird (umgekehrt wirds denk ich noch schlimmer...also ein D7-Programm mit einem XE-Package).

Viel hängt davon ab, wie groß der Delphi-Versions-Sprung wird.

Uwe Raabe 10. Mai 2017 13:23

AW: bpl einbinden über Interface
 
Bei der Verwendung von BPLs unterschiedlicher Delphi müssen zwingend die richtigen Delphi-BPLs verfügbar sein, da die BPLs gegen diese compiliert werden. So ist für eine mit XE4 compilierte BPL mindestens die rtl180.bpl nötig. Das solltest du bei der Verteilung beachten.

Grundsätzlich rate ich allerdings von der Verwendung von BPLs mit unterschiedlichen Delphi-Versionen ab, da das einfach nicht vorgesehen ist. Es mag bei den ersten Tests funktionieren, kann dir aber schnell auch um die Ohren fliegen, wenn realistische Szenarien ins Spiel kommen.

Der Ansatz über die DLL erscheint mir da erfolgversprechender und vermeidet auch den rtl180-Effekt. Faktisch kannst du die BPLs auch nur wie eine DLL nutzen, da die Vorteile einer BPL durch die unterschiedlichen Delphi-Versionen nicht ausgenutzt werden können.

himitsu 10. Mai 2017 14:33

AW: bpl einbinden über Interface
 
Genauso, wie Delphi das bei seinen BPLs inzwischen macht, kann man auch seine eigenen BPLs mit einer Versionsnummer versehen.
rtl180.bpl

Dann muß man zwar immernoch je Delphi-Version die passenden BPLs mitgeben, aber hat keine Namenskonflikte. :stupid:


DCUs sind Compilerabhängig, da ihr Format sich je nach Compiler unterscheiden kann. (nur D2006 und D2007 sind kompatibel, da sich dort rein garnichts am Compiler änderte)
BPLs sind ja gegen die BPLs vom Delphi compiliert und benötigen dort natürlich die selben Delphiversionen, was aber nicht am Compiler liegt, sondern an den Delphi-BPLs, wo sich mit jeder Version die Schnittstellen der RTL/VCL/... ändern.

Lemmy 10. Mai 2017 15:36

AW: bpl einbinden über Interface
 
Servus,

Danke für den zahlreichen Input.

Daran, dass ich für "meine" bpl die notwendigen Laufzeitpackages ausliefern muss habe ich gar nicht mehr gedacht, was die Verteilung natürlich erst mal deutlich erschwert.

Und Danke für den Hinweis, dass ich auch in DLLs Interfaces übergeben kann - das war mir so nicht bewusst! Das werde ich jetzt erst mal genauer untersuchen...

Grüße

himitsu 10. Mai 2017 16:34

AW: bpl einbinden über Interface
 
Einfache Typen ala Integer, Char, Byte und Records damit gehen immer.
ShortString ist ein Record
und PAnsiChar/PWideChar sowie WideString (das ist ein von Delphi gemappter String der OleAut32 > MSDN-Library durchsuchenSysAllocString)
und Pointer daauf gehen immer

Interfaces (also COM-Objekte ala IInterface)
und Variant
gehen auch

ohne SharedMemory, geht kein String/AnsiString/UnicodeString und dynamischen Arrays. (nur zwischen Delphi-EXE/DLL und Delphi-DLL)



Bei BPLs hat man von der Nutzung her garkeine Probleme und kann alles so machen, als wäre der Code der BPL und deren Units in der EXE drin.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz