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 DLL Integration kürzen (https://www.delphipraxis.net/101360-dll-integration-kuerzen.html)

Ralf Kaiser 12. Okt 2007 17:53

Re: DLL Integration kürzen
 
Zitat:

Zitat von Bernhard Geyer
Zitat:

Zitat von Alfi001
Schon beim "Austausch" von simplen TObjects kann es gehörig knallen!

Kann ich nur zustimmen. Entweder Packages oder reine C-Kompatible Schnittstelle oder COM/Automation oder Pluginframework wie Hydra.

Was ich nie verstanden wirklich habe: Warum geht so etwas in manchen Fällen gut??? Knallt es erst wenn Teile des Speichers von Windows ausgelagert werden?

Wir hatten auf jeden Fall damals ziemlich seltsame Probleme die sich auch nicht immer reproduzieren liessen.

Apollonius 12. Okt 2007 18:08

Re: DLL Integration kürzen
 
Das würde mich auch mal interessieren, wo genau da die Knaller sind. Rein intuitiv hätte ich jetzt gesagt, dass außer beim Aufruf dees is-Operators (wie z.B. in Assign oder beim as-operator) und dem Freigeben von Objekten in Modulen, in denen sie nicht erzeugt wurden (GetMem/FreeMem) gar nichts schief gehen kann.

QuickAndDirty 14. Okt 2007 09:05

Re: DLL Integration kürzen
 
Zitat:

Zitat von Alfi001
Zitat:

Zitat von QuickAndDirty
Man kann Stringlisten hin und her übergaeben dank dem Sharemem.
Was nicht geht ist der Is operator also auch nicht assign, auf der falschen Seite.
Assign wäre mit zum Teil durch clear; AddStrings(bla); ersetzbar.

Also das geht definitiv nicht!

Die aufrufende Applikation und die DLL haben verwalten unterschiedliche Versionen der RTL! Das bedeutet Applikation.TStringList <> DLL.TStringList. Du weist ja selbst daruaf hin, dass der IS Operator nicht funktioniert (Warum ist das wohl so).

Wenn das bisher bei dir funktioniert hat dann hast du wahrscheinlich irgendwie Glück gehabt, dass sich im Speicher die VMTs nicht ins Gehege gekommen sind. Das kann aber irgendwann mal gewaltig knallen! (Also machs besser nicht)

Um Delphi-spezifische Klassen zwischen DLLs und Applikationen auszutauschen wurden extra die Packes erfunden! Das sind DLLs (die nur eine andere Endung haben) bei denen sichergestellt ist, dass Applikation und DLL die selbe Version der RTL verwenden.

Ciao,
Ralf

1. können sich die VMTs der DLL und des Programms nicht "ins gehege kommen" das ist einfach quatsch. Habs viele hundert mal so gemacht ist ein Absolut zuverlässiges verfahren wenn man einige Dinge beachtet. Die units die Objecte hin und her reichen müssen mit den selben Schaltern und Optionen kompiliert sein. Objekte die im Programm erschaffen werden sind auch dort zu zerstören und umgekehrt das selbe.
Der is operator geht aufgrund der unterschiedlichen Orte der RTTI nicht ("Tstringlist ist nicht vom Typ TStringlist" beim TPersistent.Assign). Dem könnte man aber Abhilfe verschaffen wenn man in der Stystem unit den is operator ändert so das er wie der von den InfoPower Komponenten genutzte wwIS funktioniert....

2. Bpl haben dll gegenüber einen gewaltigen Nachteil. Ich kann in einer BPL keine Programm unit mit einem anderen Schalter kompiliert verwenden so das ich BPL seitig ein anderes Kompilat verwende als in dem Programm. (Gleiche kompiler schalter braucht man bei DLLs ja nur für Objekte die die Seite wechseln, nicht für alles.)

Ralf Kaiser 14. Okt 2007 09:39

Re: DLL Integration kürzen
 
Zitat:

Zitat von QuickAndDirty
1. können sich die VMTs der DLL und des Programms nicht "ins gehege kommen" das ist einfach quatsch. Habs viele hundert mal so gemacht ist ein Absolut zuverlässiges verfahren wenn man einige Dinge beachtet. Die units die Objecte hin und her reichen müssen mit den selben Schaltern und Optionen kompiliert sein. Objekte die im Programm erschaffen werden sind auch dort zu zerstören und umgekehrt das selbe.

Das mit dem "ins Gehege kommen" war wohl etwas unglücklich formuliert. Es ist aber so, dass die Typeninformationen der beiden TStringlist-Versionen in unterschiedlichen Datensegmenten liegen. Und das kann bei manchen Operationen zu extremen Problemen führen.

Zitat:

Zitat von QuickAndDirty
Der is operator geht aufgrund der unterschiedlichen Orte der RTTI nicht ("Tstringlist ist nicht vom Typ TStringlist" beim TPersistent.Assign). Dem könnte man aber Abhilfe verschaffen wenn man in der Stystem unit den is operator ändert so das er wie der von den InfoPower Komponenten genutzte wwIS funktioniert....

Ähm, wir sprachen hier aber nicht von einer geänderten System Unit (wer macht denn so was???) sondern von normalem ungepatchten Delphi.

Zitat:

Zitat von QuickAndDirty
2. Bpl haben dll gegenüber einen gewaltigen Nachteil. Ich kann in einer BPL keine Programm unit mit einem anderen Schalter kompiliert verwenden so das ich BPL seitig ein anderes Kompilat verwende als in dem Programm. (Gleiche kompiler schalter braucht man bei DLLs ja nur für Objekte die die Seite wechseln, nicht für alles.)

Diese Behauotung verstehe ich nun absolut nicht. Wie willst du denn in der DLL andere Compilerschalter nur für die auszutauschenden Objekte verwenden? Die Einstellungen müssen, genau wie bei dem Package global übereinstimmen.

Also, zusammenfassend: mit DLLs funtioniert es nur dann wenn beide beteiligten, also die Applikation und die DLL, die selbe VCL verwenden. Das heisst, dass sie mit Runtime-Packages erzeugt werden müssen (sonst liegen im Speicher später 2 komplette Kopien der VCL rum!). Daraus folgt aber, dass die hier selben Einschränkungen gelten wie für Packages. Warum also nicht direkt Packages verwenden???

Nochmal ganz klar die Frage: Warum sollte jemand auf die Idee kommen für die Arbeit mit Delphi-Typen eine DLL statt einem Package zu verwenden? Man holt sich die Nachteile beider Varianten ohne einen der Vorteile zu haben.

Ciao,
Ralf

Elvis 14. Okt 2007 10:49

Re: DLL Integration kürzen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Quick&Dirty will wohl seinem Namen alle Ehre machen, hmm? :zwinker:

@Alf, Probleme kommen ganz einfach.
Du hast eine exportierte Funktion, die eine Referenz vom Typ TStrings nimmt und übergibst ihr natürlich eine Ableitung.
Hier kann es ganz schnell fies werden, da die übergebene Referenz ihre Methoden auf einer VMT abbildet, die nicht mit denen der DLL-Version dieser Klasse übereinstimmen.
Kurz: Du musst die gleiche Version der benutzten Units haben und die gleiche Version des Compilers. Ergo: Man landet wieder bei Packages, nur ohne die Sicherheit und Einfachheit, die Packages mitbringen.
Ein "passt scho'" akzeptiere ich hier nicht.
Da kann man gleich VB'ler werden, bei den Honks wäre das eine akzeptable Einstellung, aber deshalb sind diese Honks auch nur VB'ler und keine Entwickler. ;-)

Ich predige hier schon lange wiederholt eine einfache und sehr elegante Möglichkeit um Objekte in DLLs benutzen zu können, ohne sich sinnlos an eine RTL- oder Delphiversion zu fesseln: Interfaces.
Man kann sich eine einfache Verpackung für einebestehende TSTrings-Referenz bauen, die man problemlos als Interface an eine Delphi/FPC- -DLL schicken kann (auch C++, wenn WideString anstatt AnsiString benutzt wird).

Delphi-Quellcode:
type
  ISharedStringList = interface
  ['{3F5E3362-121A-4EC4-B399-9F8CD321FC34}']
    procedure Clear; stdcall;
    function GetCount : Integer; stdcall;

    function Add(const aValue : String) : Integer; stdcall;
    procedure Delete(aIndex : Integer); stdcall;
    procedure Exchange(aIndex1, aIndex2 : Integer); stdcall;
    function IndexOf(const aValue : string) : Integer; stdcall;
    procedure Insert(aIndex : Integer; const aValue : string); stdcall;

    function GetItem(aIndex : Integer) : String; stdcall;
    procedure SetItem(aIndex : Integer; const aValue : String); stdcall;

    property Item[aIndex : Integer] : String
      read GetItem
      write SetItem; default;
  end;
Delphi-Quellcode:
uses
  Classes,
  uSharedInterface;

type
  TSharedStringListWrapper = class(TInterfacedObject, ISharedStringList)
  private
    fInnerList: TStrings;
  protected
    function GetCount: Integer; stdcall;

    procedure Clear; stdcall;

    function Add(const aValue: String): Integer; stdcall;
    procedure Delete(aIndex : Integer); stdcall;
    procedure Exchange(aIndex1, aIndex2 : Integer); stdcall;
    function IndexOf(const aValue : String) : Integer; stdcall;
    procedure Insert(aIndex : Integer; const aValue : String); stdcall;

    function GetItem(aIndex: Integer): String; stdcall;
    procedure SetItem(aIndex: Integer; const aValue: String); stdcall;
  public
    property InnerList : TStrings read fInnerList;

    constructor Create(aInnerList : TStrings);

    class function Wrap(aInnerList : TStrings) : ISharedStringList;
  end;
implementation

{ TSharedStringListWrapper }

function TSharedStringListWrapper.Add(const aValue : String) : Integer;
begin
  result := InnerList.Add(aValue);
end;

procedure TSharedStringListWrapper.Clear;
begin
  InnerList.Clear();
end;

constructor TSharedStringListWrapper.Create(aInnerList : TStrings);
begin
  inherited Create();
  fInnerList := aInnerList;
end;

procedure TSharedStringListWrapper.Delete(aIndex : Integer);
begin
  InnerList.Delete(aIndex);
end;

procedure TSharedStringListWrapper.Exchange(aIndex1, aIndex2 : Integer);
begin
  InnerList.Exchange(aIndex1, aIndex2);
end;

function TSharedStringListWrapper.GetCount : Integer;
begin
  result := InnerList.Count;
end;

function TSharedStringListWrapper.GetItem(aIndex : Integer) : String;
begin
  result := InnerList[aIndex];
end;

function TSharedStringListWrapper.IndexOf(const aValue : String) : Integer;
begin
  result := InnerList.IndexOf(aValue);
end;

procedure TSharedStringListWrapper.Insert(aIndex : Integer;
  const aValue : String);
begin
  InnerList.Insert(aIndex, aValue);
end;

procedure TSharedStringListWrapper.SetItem(aIndex : Integer;
  const aValue : String);
begin
  InnerList[aIndex] := aValue;
end;

class function TSharedStringListWrapper.Wrap(aInnerList : TStrings) : ISharedStringList;
begin
  result := Create(aInnerList);
end;
Delphi-Quellcode:
uses
  ShareMem,
  uSharedInterface in '..\uSharedInterface.pas';

{$R *.res}

procedure AddToStringList(const aStringList : ISharedStringList; const aString : String); stdcall;
begin
  aStringList.Add(aString);
end;

exports
  AddToStringList;
Die kann man nun immer nehmen, wenn man irgendeine TStrings-Ableitung in einer DLL bearbeiten will.

Apollonius 14. Okt 2007 10:54

Re: DLL Integration kürzen
 
Zitat:

Hier kann es ganz schnell fies werden, da die übergebene Referenz ihre Methoden auf einer VMT abbildet, die nicht mit denen der DLL-Version dieser Klasse übereinstimmen.
Das verstehe ich jetzt nicht. Wichtig ist doch nur, dass das Format der VMTs identisch ist, und das ist doch gegeben. Dass die VMTs unterschiedlich sind, ist doch egal, solange immernoch an Offset x Methode y steht.

Elvis 14. Okt 2007 10:58

Re: DLL Integration kürzen
 
Zitat:

Zitat von Apollonius
Zitat:

Hier kann es ganz schnell fies werden, da die übergebene Referenz ihre Methoden auf einer VMT abbildet, die nicht mit denen der DLL-Version dieser Klasse übereinstimmen.
Das verstehe ich jetzt nicht. Wichtig ist doch nur, dass das Format der VMTs identisch ist, und das ist doch gegeben. Dass die VMTs unterschiedlich sind, ist doch egal, solange immernoch an Offset x Methode y steht.

Hatte ich wohl nur kurz angerissen...
Ja, solange du mit den gleichen Versionen von allen Units und RTL arbeitest.
Ansonsten liegt an an Position X plötzlich Methode z, während die DLL dort eine Methode y hat.
Und genau dieses Problem macht das ganze so absolut unnötig komplex.
Versteckte Komplexität wie solche schrecklich engen Abhängigkeiten zwischen Modulen müssen entweder ausführlich dokumentiert werden, oder man nimmt Packages, bei denen diese Abhängigkeit as-designed und somit allgemein bekannt ist.
Der Weg, den ich aufgezeigt habe, umgeht diese unnötig enge Kopplung...

Apollonius 14. Okt 2007 11:03

Re: DLL Integration kürzen
 
Gut, eigentlich ist deine Lösung ja fast identisch mit normalen virtuellen Methoden. Einziger Unterschied ist meiner Meinung nach, dass es bei dem Interface keine verschiedenen Versionen geben wird. Wenn dem aber so wäre, dann könnte selbiges Problem mit unterschiedlichen Methoden an gleichen Offsets auch auftreten.

Elvis 14. Okt 2007 11:11

Re: DLL Integration kürzen
 
Zitat:

Zitat von Apollonius
Gut, eigentlich ist deine Lösung ja fast identisch mit normalen virtuellen Methoden. Einziger Unterschied ist meiner Meinung nach, dass es bei dem Interface keine verschiedenen Versionen geben wird. Wenn dem aber so wäre, dann könnte selbiges Problem mit unterschiedlichen Methoden an gleichen Offsets auch auftreten.

Interfaces haben eine standardisierte Art um Methoden aufzurufen (Darauf basiert schließlich COM ;-).
Dadurch kann es das nicht geben, außer du verwendest 2 unterschiedliche Versionen eines Interfaces mit der gleichen GUID.
Das wäre ganz böse, bei Erweiterungen lieber vom alten Interface ableiten und ein neues mit neuer GUID deklarieren.
Die Implementierung implementiert dann einfach beide (ist ja kein Extraaufwand).
Dadurch bleiben DLLs kompatibel, auch wenn sie gegen eine ältere Version deiner PlugIn API gebaut wurden.

Apollonius 14. Okt 2007 11:17

Re: DLL Integration kürzen
 
Zitat:

Interfaces haben eine standardisierte Art um Methoden aufzurufen
??? Interfaces verwenden standardmäßig doch auch nur eine VMT (Variants mit Interfaces drin sind eine andere Geschichte).


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:33 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