Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Plugins: Datenaustausch zwischen DLL und Hauptprogramm (https://www.delphipraxis.net/142018-plugins-datenaustausch-zwischen-dll-und-hauptprogramm.html)

alleinherrscher 21. Okt 2009 15:22

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Zitat:

Zitat von himitsu
Delphi-Quellcode:
procedure TApp.AddStream(aStream: IDelphiStream); stdcall;
begin
  astream.position:=0;
  astream.SaveToFile('C:\test2.jpg');
end;

Das war auch mein erster Versuch. Aber da astream ja vom Typ IDelphiStream ist, besitzt er die Methode SavetoFile gar nicht... :gruebel:

//edit: ich mein...das is nicht sooo schlimm...Hauptsache der Stream kommt an...ich kann ihn ja per Tmemorystream.copyfrom in einen memorystream kopieren, denke ich mal...
//edit2: Naja, auch nicht wirklich, da sogesehen ja IDelphiStream keine Ableitung von TStream ist.
//edit3: Ich bin doof...sorry, dafür hattest du ja extra die auskommentierten Methoden eingefügt im Interface Idelphistream...D.h. da müsste ich dann noch sowas wie Copyfrom mit einbauen...

himitsu 21. Okt 2009 15:33

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
drum sagte ich ja, daß man diese eventuell noch implementieren muß
(hatte es vorhin nur nicht gemacht, da ich alles Vorhandene erstmal nur zusammenkopiert hatte und nichts direkt "neu" schrieb)

Delphi-Quellcode:
type
  IDelphiStreamIntern = interface
    {private}
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
    function GetSize: Int64;
  end;
  IDelphiStream = interface(IDelphiStreamIntern)
    ['{65805750-623E-4719-AD79-A30FF6FCA3CA}']
    procedure SetSize(NewSize: Longint);
    function Write(const Buffer; Count: Longint): Longint;
    function Read(var Buffer; Count: Longint): Longint;
    function Seek(Offset: Longint; Origin: Word): Longint;
    procedure Clear;
    procedure LoadFromStream(Stream: IDelphiStream);
    procedure SaveToStream(Stream: IDelphiStream);
    procedure LoadFromFile(const FileName: WideString);
    procedure SaveToFile(const FileName: WideString);
    property Position: Int64 read GetPosition write SetPosition;
    property Size: Int64 read GetSize write SetSize64;
  end;

  TInterfacedMemoryStream = class(TMemoryStream, IDelphiStream, IInterface)
  private
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
  protected
    FRefCount: Integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    class function NewInstance: TObject; override;
    property RefCount: Integer read FRefCount;

    procedure LoadFromStream(Stream: IDelphiStream); overload;
    procedure SaveToStream(Stream: IDelphiStream); overload;
    procedure LoadFromFile(const FileName: WideString); overload;
    procedure SaveToFile(const FileName: WideString); overload;
  end;

function TInterfacedMemoryStream.GetPosition: Int64;
begin
  Result := inherited Position;
end;

procedure TInterfacedMemoryStream.SetPosition(const Pos: Int64);
begin
  inherited Position := Pos;
end;

procedure TInterfacedMemoryStream.SetSize64(const NewSize: Int64);
begin
  inherited Size := NewSize;
end;

function TInterfacedMemoryStream.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TInterfacedMemoryStream._AddRef: Integer;
begin
  Result := InterlockedIncrement(FRefCount);
end;

function TInterfacedMemoryStream._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;

procedure TInterfacedMemoryStream.AfterConstruction;
begin
  InterlockedDecrement(FRefCount);
end;

procedure TInterfacedMemoryStream.BeforeDestruction;
begin
  if RefCount <> 0 then
    System.Error(reInvalidPtr);
end;

class function TInterfacedMemoryStream.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  TInterfacedMemoryStream(Result).FRefCount := 1;
end;

procedure TInterfacedMemoryStream.LoadFromStream(Stream: IDelphiStream);
var
  buf: array[0..65535] of Byte;
  i: Integer;
begin
  Clear;
  while true do
  begin
    i := Stream.Read(buf, Length(buf));
    if i = 0 then break;
    if Write(buf, i) <> i then System.Error(reOutOfMemory);
  end;
end;

procedure TInterfacedMemoryStream.SaveToStream(Stream: IDelphiStream);
var
  buf: array[0..65535] of Byte;
  i: Integer;
begin
  Stream.Clear;
  while true do
  begin
    i := Read(buf, Length(buf));
    if i = 0 then break;
    if Stream.Write(buf, i) <> i then System.Error(reOutOfMemory);
  end;
end;

procedure TInterfacedMemoryStream.LoadFromFile(const FileName: WideString);
begin
  inherited LoadFromFile(String(FileName));
end;

procedure TInterfacedMemoryStream.SaveToFile(const FileName: WideString);
begin
  inherited SaveToFile(String(FileName));
end;
LoadFromStream und SaveToStream arbeiten hier intern aber nur mit String, also bis Delphi 2007 mit AnsiString.
Wenn man auch da wirklich den WideString unterstüzen will, dann muß man sich einen Unicode-fähigen FileStream besorgen (also Unicode bei den Dateinamen).

Und direkt AnsiString/UnicodeString geht halt wegen der getrennten Speicherverwaltung nicht so einfach ... stickwort Hier im Forum suchenSharedMemoryManager

alleinherrscher 21. Okt 2009 15:43

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Klappt perfekt! Entschuldigung, dass ich im letzten Post nicht richtig aufgepasst habe, sonst hätte sich die Frage von selbst geklärt! Großartige Leistung! Ich bedanke mich recht herzlich! :cheers:

himitsu 21. Okt 2009 15:52

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
bitte bitte

und praktisch genauso, wie es jetzt mit den Stream ging,
macht man es jetzt mit den anderen Interfaces für Plugin und App
(nur daß man hier leicht direkt von TInterfacedObject erben kann und dann die Basis-Interface-Funktionen schon fertig hat)

also der Zugriff dann von außen immer nur über das jeweilige Interface

MyRealName 26. Nov 2009 15:31

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Sorry, wenn ich mich kurz einmische : Man kann sehr gut mit Klassen in DLLs arbeiten ohne die Probleme der verschiedenen RTTI etc zu haben, man muss nur wissen, wie :) Das Geheimnis sind Laufzeit-Pakete.

Ich habe eine grosse Demo mit Forms / Frames / Objects etc auf meiner Homepage. Die Demo umfasst 9 Plugins als DLL und einer Loader.exe

Einfach mal hier klicken, da gibt es das ganze als rein ausführbaren Code (Delphi2007, wers nicht hat, muss die FULL-version laden, ansonsten die Light) und als nur-source.

Um mit dem Source zu arbeiten, muss man die MAF Components runterladen und installieren, die verwalten unter anderem das ganze plugins-zeugs.

himitsu 26. Nov 2009 16:09

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Bei dieser Variante hat man dann natürlich nur eine RTTI, bezüglich dieser Komponenten ... also die in dem externen Package.

Das ist wie mit dem Speichermanager ... wenn man einen (externen) gemeinsamen Manager nutzt, dann klappt das auch, aber standardmäßig erstmal nicht.

MyRealName 26. Nov 2009 20:48

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Auch nur, weil die BPL variante uns von Anfang an zwingt, mit Laufzeit packages zu arbeiten. DLLs tun das nicht

Elvis 26. Nov 2009 22:35

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Zitat:

Zitat von MyRealName
Sorry, wenn ich mich kurz einmische : Man kann sehr gut mit Klassen in DLLs arbeiten ohne die Probleme der verschiedenen RTTI etc zu haben, man muss nur wissen, wie :) Das Geheimnis sind Laufzeit-Pakete.

Nein.
BPLs taugen eigentlich nur etwas für die IDE, da sie ja schon fest mit einer Version von Compiler, RTL und VCL verheiratet ist.
Für so ziemlich alles andere, bei dem BPLs sinnvoll wären, könnte man auch eine große Single-Exe nehmen ohne irgendwelche Flexibilität zu verlieren.
Warum? Weil BPLs so unflexibel sind, wie es entartete DLLs nur werden können ohne schon Teil der Exe zu sein.

BPLs vorauszusetzen schränkt die Schar von Autoren auf den winzigen Kreis ein, der mit exakt deiner Compiler/VCL/RTL-Version arbeitet und auch ja keine Units/Registrierte Komponentenamen mitbringt, die mit anderen Units/Komponentennamen in dem eng verwobenen Haufen BPLs kollidieren.
Kurz: Es ist fast ausgeschlossen, dass ein anderer aus dir selbst solch ein Plugin schreiben kann ohne zu riskieren, dass es irgendwann explodiert.
Zum Beispiel, weil jmd eine TntControls-Unit in einem seiner Packages hatte, anstatt EXAKT das gleiche Package zu nutzen wie alle anderen.
Aber halt: Niemand schrieb vor welche Version von Komponente XYZ genommen werden muss, weil sich die PlugIns wohl kaum alle gegenseitig die 3rd-Party-Komponenten absprechen können.

Long story short: BPLs sind die grauenvollste, instabilste und zeitverschwenderischte Art sich Flexibilität vorzutäuschen, die ich kenne.
Plugin-Systeme, die auf BPLs aufbauen sind wie Rauchen: Fange nicht damit an, wenn doch höre so schnell wie möglich auf.
Woher ich das weiß? Sagen wir's mal so: "Got the scars to prove it... :?
Siehe auch hier: http://stackoverflow.com/questions/1...705051#1705051

MyRealName 26. Nov 2009 23:12

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Ich weiss nicht, warum Du mir widersprichst, sagst doch nur etwas gegen BPLs und ich rede davon, wie man DLLs nutzen kann mit Klassen drin.
Ich bin kein Fan von BPLs und nutze sie nur für meine Komponenten selbst.
Will man allerdings wirklich modular mit Delphi programmieren, muss man mit Laufzeit-Packages arbeiten (also zumindest die Komponenten-BPLs dynamisch linken).


Das Problem mit den TNTControls kenn ich, hatte ich bei den MAF-Komponenten auch und leider hatte es mir keiner gesagt, so dass der ganze Download für ca. 4-5 Tage fürs Ar--- war, da die version nicht zu nutzen ging.
Ich hatte in meine Komponenten das package PNGComponents eingebunden, da es

1.) kostenlos von der Embarcadero Seite zu beziehen ist
und
2.) man heutzutage nicht mehr auf PNG (wegen Transparenz) in einer App verzichetn sollte/kann

hab dann leidlich durch einen Kunden rausfinden müssen, dass es wirklich nicht geht, dass man meine Komponenten mit einem selbst-erzeugtem PNGComponents package nutzen kann.
Lösung 1 wäre einfach die dcus und BPLs mitzugeben, aber wenn ich mich recht entsinne, ist das Embarcadero nicht so glücklich drüber. Also nahm ich lösung 2 und hab alles schön in Conditional Defines gekapselt, so dass man sie als source-Besizter selbst wieder reinnehmen kann und den nativen support nutzen (TPNGImageList Verwaltung, statt nur TImageList etc).

Allerdings sah ich auch durch mein Test-Programm, das sich neue Versionen von meinen Komponenten bauen konnte und meist auch ohne die Anwendung oder die DLLs zu kompilieren dann auch weiter nutzen. Man muss halt nur aufpassen, dass man keine published properties löscht ;) Oder Methoden umbenennt.

Allerdings ist zu empfehlen, vorhandene Projekte neu zu übersetzen, wenn man ein neues Package baut

Elvis 27. Nov 2009 05:52

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm
 
Zitat:

Zitat von MyRealName
Ich weiss nicht, warum Du mir widersprichst, sagst doch nur etwas gegen BPLs und ich rede davon, wie man DLLs nutzen kann mit Klassen drin.

Weil ein unschuldiger Mitleser sonst den falschen Eindruck bekäme, dass Pseudo-Modularisierug mit Packages wirkliche Flexibilität bringen würde und einem nicht 70% der Haarpracht kostet.
Zitat:

Will man allerdings wirklich modular mit Delphi programmieren, muss man mit Laufzeit-Packages arbeiten (also zumindest die Komponenten-BPLs dynamisch linken).
Eben nicht. Wirklich modular ist man, wenn die Module nicht so grauenvoll miteinander verzahnt sind sind. Und das heißt, man ist "wirklich modular" wenn man DLLs benutzt und sich in den exportierten Funktionn auf interoperable Typen wie WideString, Integer, double, Interfaces, OleVariant, etc. beschränkt.
Denn dann explodieren Module nicht stets und ständig, weil irgendein Plugin eine neue Unit nutzt, oder wenn man eine neue Delphiversion nutzen will. Ganz zu schweigen davon, dass man dann Plugins mit anderen Sprachen schreiben kann z.B.: FPC, C++, C#,...
Zitat:

Zitat von MyRealName
Allerdings sah ich auch durch mein Test-Programm, das sich neue Versionen von meinen Komponenten bauen konnte und meist auch ohne die Anwendung oder die DLLs zu kompilieren dann auch weiter nutzen. Man muss halt nur aufpassen, dass man keine published properties löscht ;) Oder Methoden umbenennt.

Allerdings ist zu empfehlen, vorhandene Projekte neu zu übersetzen, wenn man ein neues Package baut

Dann könnte man gleich eine Single-Exe nehmen ohne all die Zeit mit Package-Issues zu verschwenden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:09 Uhr.
Seite 2 von 3     12 3      

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