Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Klasseninstanz an DLL-Funktion übergeben (TStrings) (https://www.delphipraxis.net/83363-klasseninstanz-dll-funktion-uebergeben-tstrings.html)

Sharky 1. Jan 2007 08:46


Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Hai ihr,

ich bin nun "gezwungen" mich endlich mit DLLs zu beschäftigen ;-)

Immer lese ich das es Probleme gibt wenn man einen Delphi-String an eine DLL übergibt bzw. zurück bekommen möchte.
Bei TStrings dürfte das aber doch kein Problem sein oder? Nicht das ich da jetzt etwas mache und auf einmal fliegt es mir um die Flossen.

Zum Beispiel habe ich diese Funktion in meiner Test-DLL
Delphi-Quellcode:
  function AddSLLines(sl: TStrings; const count: Integer): Integer; stdcall;
  var
    ndx: Integer;
    foo: Integer;
  begin
    foo := 0;
    for ndx := 1 to count do
    begin
      sl.Add(Format('Zeile %d', [ndx]));
      Inc(foo);
    end;
    Result := foo;
  end;
und rufe sie dann so in meinem Programm auf:
Delphi-Quellcode:
  TAddSLLines = function(sl: TStrings; count: Integer): Integer; stdcall;

  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  dllHandle: THandle = -1;
  AddSLLines: TAddSLLines = NIL;

procedure TForm1.Button1Click(Sender: TObject);
begin
  AddSLLines(ListBox1.Items, 10);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  pfad: string;
begin
  pfad := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0))) + 'test.dll';
  dllHandle := LoadLibrary(PAnsiChar(pfad));
  if dllHandle <> 0 then
  begin
    @AddSLLines := GetProcAddress(dllHandle, 'AddSLLines');
  end
  else
  begin
    ShowMessage('blubb');
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeLibrary(dllHandle);
end;
Ist das okay so oder habe ich da einen groben Fehler?

Reinhard Kern 1. Jan 2007 09:18

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Zitat:

Zitat von Sharky
Hai ihr,

ich bin nun "gezwungen" mich endlich mit DLLs zu beschäftigen ;-)

Immer lese ich das es Probleme gibt wenn man einen Delphi-String an eine DLL übergibt bzw. zurück bekommen möchte.
Bei TStrings dürfte das aber doch kein Problem sein oder? Nicht das ich da jetzt etwas mache und auf einmal fliegt es mir um die Flossen.
...

Ist das okay so oder habe ich da einen groben Fehler?

Hallo,

so allgemein für DLLs kann man das nicht sagen, aber Strings sind nun mal Pascal-spezifisch, in anderen Programmiersprachen, besonders die Cs, sind nullterminierte Zeichenfolgen üblich bzw. Pointer darauf. Die gibt es in Pascal als PChar auch schon lange, aber string und PChar sind getrennte Welten mit unterschiedlichen Funktionen.

Besonders das Win32 API benutzt ausschliesslich PChar, das hat auch technische Vorteile gegenüber der Übergabe von Pascal-Strings an/von DLLs. Du must eben immer umwandeln (der Compiler weist dich schon drauf hin), oder du schreibst dir "Wrapper" wie z.B.
Delphi-Quellcode:
function LoadLibrary_ss (LibPath : ShortString) : THandle;
var lparr : array [0..255] of char;
begin
StrPLCopy (lparr,LibPath,255);
Result := LoadLibrary (lparr);
end;
aber das lohnt sich nur, wenn du die Funktion oft brauchst.

Du hast etwas anders umgewandelt, aber das muss ebenfalls funktionieren. Je nach Aufgabe könnte man in Delphi auch ganz mit arrays und PChar programmieren, aber für Pascal-Strings gibt es mehr Funktionen.

Gruss Reinhard

mkinzler 1. Jan 2007 10:58

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Im Falle von TStrings muß er dann die einzelnen Strings der Stringliste als einen Array von PChars übergeben

Reinhard Kern 1. Jan 2007 14:03

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Zitat:

Zitat von mkinzler
Im Falle von TStrings muß er dann die einzelnen Strings der Stringliste als einen Array von PChars übergeben

Hallo,

korrigiere mich, wenn ich was Falsches sage:

Man kann schon eine Delphi-DLL erstellen, die als Parameter Delphi-Objekte verwendet - aber erstens muss man sich dann sehr sorgfältig überlegen, wann und wo Create und Destroy stattfinden, und ausserdem ist diese DLL natürlich mit keiner anderen Programmiersprache verwendbar, sondern kann nur von Delphi-Programmen aufgerufen werden. Das ist meistens nicht der Sinn einer DLL.

Andere Sprachen kennen Delphi-Objekte grundsätzlich nicht (kein einziges!), also kann man so etwas wie TStrings eben nicht als Parameter definieren und muss praktisch die Software so umbauen, dass zumindest an den Schnittstellen keine Objekte verwendet werden (gilt für andere OO-Sprachen genauso). TStrings als array of PChar zu übergeben, ist schon der richtige Rat, aber noch lang nicht alles; dieses array ist eben keineswegs ein TStrings-Objekt - das müsste man erst wieder zusammensetzen, oder man schreibt die Software eben um für die direkte Verwendung des arrays. Man muss also sozusagen die Objekte aufbrechen in einfache Datentypen, das Komplexeste ist ein Record.

Gruss Reinhard

Jürgen Thomas 1. Jan 2007 14:18

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Zunächst einmal Frohes Neues Jahr!

Ihr habt natürlich alle recht mit der Übergabe von Strings per DLL. Aber bei TStrings kann man es sich doch etwas einfacher machen:
Delphi-Quellcode:
var aListe: TStrings;
//  übergeben
pc := PChar(aListe.Text);
//  übernehmen
aListe.Text := StrPas(pc);
Gruß Jürgen

PS. Bitte nicht sauer sein, wenn es nicht ganz korrekt ist: Ich bin seit einem Jahr fast ausschließlich mit C# befasst; und wegen dieser Probleme habe ich auch vorher mich sehr bemüht, auf string-Übergabe an DLL zu verzichten.

Luckie 1. Jan 2007 14:23

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Will man mit Objekten in DLLs arbeiten, wären Laufzeitpackages die bessere Wahl.

bigg 1. Jan 2007 14:23

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Hi jürgen,

"TStrings.Text()" ruft die Methode der Klasse TStrings auf und erzeugt den "Gesamt-Text". Das mag zwar funktionieren ist allerdings deutlich langsamer.


Mfg Stefan

Bernhard Geyer 1. Jan 2007 14:24

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Zitat:

Zitat von Reinhard Kern
korrigiere mich, wenn ich was Falsches sage:

Man kann schon eine Delphi-DLL erstellen, die als Parameter Delphi-Objekte verwendet - aber erstens muss man sich dann sehr sorgfältig überlegen, wann und wo Create und Destroy stattfinden, und ausserdem ist diese DLL natürlich mit keiner anderen Programmiersprache verwendbar, sondern kann nur von Delphi-Programmen aufgerufen werden. Das ist meistens nicht der Sinn einer DLL.

Es gibt noch mehr Einschränkungen:
- Exe + DLL müssen mit der gleichen Delphi-Version erzeugt worden sein damit das Speicherlayout der Instanzen gleich ist
- Die Is/As-Operationen funktionieren nicht, da Exe und DLL (wenn keine Laufzeitpackages verwendet werden) unabhänige Klassenmodelle haben. (TObject Exe <> TObject DLL).

Zitat:

Zitat von Reinhard Kern
... und muss praktisch die Software so umbauen, dass zumindest an den Schnittstellen keine Objekte verwendet werden (gilt für andere OO-Sprachen genauso).

Deshalb hat ja z.B. MS mit COM eine Definition geschaffen die es ermöglich Objekte zwischen verschiedenen Sprachen austauschen zu können. Die konsequente Weiterentwicklung dieses Gedankens ist .NET wo viele Nachteile von COM (Registry, Admin-Rechte, ...) nicht mehr gegeben sind.

Zitat:

Zitat von Reinhard Kern
... oder man schreibt die Software eben um für die direkte Verwendung des arrays. Man muss also sozusagen die Objekte aufbrechen in einfache Datentypen, das Komplexeste ist ein Record.

Oder man Schreibt auf beiden Seiten diser DLL-Schnittstelle Schnittstellen-Objekte welche diese Umsetzung durchführen. Nach "oben" wird eine Objekt verwendet welche zur übertragung DLL serialisiert wird und in der DLL wieder zusammengesetzt wird.

Elvis 1. Jan 2007 19:36

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Ich habe gerade kein Delphi hier. (hier <> @home ;) )
Muss mir das also etwas aus den Fingern saugen.... :angle2:
Was Bernhard da angesprochen hat lässt sich auch ohne COM realisieren. Delphi Interfaces erfüllen die COM-Pflichten, sie sind also binär kompatibel zueinander. Auch wenn du sie in 2 Binaries kompilierst (Deine Echse und die DLL).
Du benutzt in der Methode oben eigentlich nur die Methode Add von TSTrings. Das Interface was man hier braucht müsste also nur die Methode Add besitzen:
Delphi-Quellcode:
type
  IStringList = interface(IUnknown)
  ['bli-bla-blubb'] //hier ctrl+g drücken ;)
    function Add(const aString : String) : Integer;
  end;
Solange Delphi mit Delphi in der gleichen Version "redet" kann man String benutzen, solange ShareMem/FastMM als erste Unit in der DLL und in der Echse verwendet wird.
Die StringList version, die du in der Echse benutzt, muss natürlich noch das Interface implementieren.
Da ich (hoffentlich) die gleiche Signatur der Methode in dem Interface habe, wie sie bereits in TStrings deklariert ist, sollte das ziemlich easy sein: ;)
Delphi-Quellcode:
type
  TMyStringlist = class(TStringList , IStringList)
  private
    fStringList : TStringList;
  protected
   // hier die Methoden von System.TInterfacedObject reinkopieren
  public
    constructor Create;
    destructor Destroy; override;
  end;
...
constructor TMyStringlist.Create;
begin
  fStringList := TStringList.Create();
end;

destructor TMyStringlist.Destroy;
begin
  fStringList.Free();
end;
Die Unit mit dem Interface kannst du in Echse und DLL benutzen. Die TMyStringList sollte aber niemals direkt zwischen den beiden übergeben werden sondern nur als Referenz auf IStringList.
Wenn du es übergibst, sollte der Parameter immer schön als "const" übergeben werden. Dadurch findet keine Referenzzählung statt und Delphi wird dir beim erreichen der 0 nicht die Instanz töten, obwohl du damit wahrscheinlich noch arbeiten willst. :shock:

Elvis 4. Jan 2007 18:44

Re: Klasseninstanz an DLL-Funktion übergeben (TStrings)
 
Sharky, wenn ich etwas übersetzen muss, einfach laut schreien. :mrgreen:
Wenigstens einmal/d kieke ich in die DP. ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:47 Uhr.
Seite 1 von 2  1 2      

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