Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   String aus D5 DLL in Delphi 10.2 einslesen (https://www.delphipraxis.net/201351-string-aus-d5-dll-delphi-10-2-einslesen.html)

Rolf Frei 15. Jul 2019 12:11

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Wieso nicht einfach:

In der DLL: ExportString := StringList.Text
in der Anwendung: StringList.Text := ExportString

Damit lässt sich eine Stringlist mit der bestehenden Funktion ohne Probleme transferieren.

Stcall wird doch sicher einen Compilerfehler bringen. Ich vermute das ist hier einfach ein Schreibfehler des OP im Forum.

dummzeuch 15. Jul 2019 12:53

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Wenn der Export aus der DLL nicht als StdCall deklariert wurde, sollte der Import es auch nicht sein.

Laut Swiss Delphi Center (bzw. Peter Below, der den Artikel dort geschrieben hat) war die Default-Calling-Convention in Delphi 5 nicht StdCall sondern Register.

Normalerweise sollte man die aber in der DLL explizit angeben...

Ansonsten: Mit Delphi 2007 wurde der Standard-Memory-Manager auf FastMM geändert. Früher wurde für ShareMem eine DLL (BORLNDMM.dll?) benötigt, die dann sowohl das Programm als auch die DLL zur Speicherverwaltung benutzt haben. Seit FastMM ist das nicht mehr notwendig.

Ich frage mich gerade, ob das alte ShareMem noch kompatibel zum neuen ist.

Vielleicht muss man ein Flag setzen?
EnableBackwardCompileMMSharing

peterbelow 15. Jul 2019 13:34

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Zitat:

Zitat von kmma (Beitrag 1436744)
Hallo

Ich habe folgendes Problem. Ich muss eine D5 DLL in ein D10.2 Projekt einbiden. An der D5 DLL kann ich nichts meh ändern. Die DLL übergibt einen String (böse :-)

Ich habe das ganze mal auf folgende Minimalkostellation zusammengestaucht um das Problem zu zeigen.

D5 DLL

(Sharemem ist als erstes in der Uses Klausel)

Delphi-Quellcode:
library Project_d5;

uses
  sharemem,
  SysUtils,
  Classes;

function ExportString: string; export; forward;

function ExportString: string;
begin
   result := 'Hallo';
end;

exports
    ExportString;
end.
in D10.2:

Delphi-Quellcode:
unit DLL_string;

interface

uses
  sharemem, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

function ExportString: ansistring stcall; external 'xxx\Project_d5.dll';

var
  Form1: TForm1;

implementation

procedure TForm1.FormCreate(Sender: TObject);
  var a: shortstring;
begin
  a := Exportstring;
  showmessage(a);

end;
Beim Start wird zwar "Hallo" agezeigt, aber wenn die die Prozedur FormCreate verlassen wird, wirft das Programm eine Exception.

Hat jemand eine Idee, wie ich Strings aus D5 DLLs sauber einlesen kann?

PS. Falls das klappen sollte steht mir auch noch die Aufgabe bevor, StringLists aus D5 weier zu verarbeiten :-(


Gruß Klaus

Mein Beileid :).

Die sauberte Lösung wäre (falls Du D5 noch verfügbar hast) für diese DLL eine Wrapper-Dll zu bauen, die wie eine Windows API-DLL alle exportierten Funktionen mit stdcall calling convention und ausschließlich unter Verwendung von API-kompatiblen Datentypen für Parameter und Rückgabewerte deklariert. Für Text wäre das PChar (= PAnsiChar in Tokyo).

Du hast da sonst schwerwiegende Kompatibilitätsprobleme:
  • D5 und Tokyo verwenden unterschiedliche Memory manager, die von beiden Versionen verwendeten Sharemem-Versionen sind nicht kompatibel.
  • Der D5 String-Typ ist nicht kompatibel mit dem Tokyo Ansistring-Typ, da sich das in-Memory Layout geändert hat

jziersch 15. Jul 2019 14:28

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Zitat:

Die sauberte Lösung wäre (falls Du D5 noch verfügbar hast) für diese DLL eine Wrapper-Dll zu bauen, die wie eine Windows API-DLL alle exportierten Funktionen mit stdcall calling convention und ausschließlich unter Verwendung von API-kompatiblen Datentypen für Parameter und Rückgabewerte deklariert.
Das ist ein super Vorschlag und dürfte im Hinblick auf die StringList die einzig gangbare Lösung sein.

Mein Pointer Ansatz geht leider nicht wie gedacht. Man kann die Funktion nicht einfach anders deklarieren. Das gibt sofort einen crash.

Ich hatte mir das so gedacht:

Code:
function ExportString: AnsiString; external '..\..\Project1.dll'; // oder stdcall

procedure TForm1.Button1Click(Sender: TObject);
var s, s2 : AnsiString;
    pa : PAnsiChar;
    p : PInteger;
begin
   s := ExportString;
   pa := PAnsiChar(s);
   p := PInteger(pa);
   dec(p); // Length
   SetString(s2, pa, p^);
   Edit1.Text := s2;
   dec(p); // RefCount
   p^ := p^ + 1; // Verhindere Free auf den String
  FreeMem(p); // String freigeben
end;
Es geht, aber k.A. ob es hier ein Speicher loch gibt.

peterbelow 15. Jul 2019 16:45

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Zitat:

Zitat von jziersch (Beitrag 1436778)
Zitat:

Die sauberte Lösung wäre (falls Du D5 noch verfügbar hast) für diese DLL eine Wrapper-Dll zu bauen, die wie eine Windows API-DLL alle exportierten Funktionen mit stdcall calling convention und ausschließlich unter Verwendung von API-kompatiblen Datentypen für Parameter und Rückgabewerte deklariert.
Das ist ein super Vorschlag und dürfte im Hinblick auf die StringList die einzig gangbare Lösung sein.

Mein Pointer Ansatz geht leider nicht wie gedacht. Man kann die Funktion nicht einfach anders deklarieren. Das gibt sofort einen crash.

Ich hatte mir das so gedacht:

Code:
function ExportString: AnsiString; external '..\..\Project1.dll'; // oder stdcall

procedure TForm1.Button1Click(Sender: TObject);
var s, s2 : AnsiString;
    pa : PAnsiChar;
    p : PInteger;
begin
   s := ExportString;
   pa := PAnsiChar(s);
   p := PInteger(pa);
   dec(p); // Length
   SetString(s2, pa, p^);
   Edit1.Text := s2;
   dec(p); // RefCount
   p^ := p^ + 1; // Verhindere Free auf den String
  FreeMem(p); // String freigeben
end;
Es geht, aber k.A. ob es hier ein Speicher loch gibt.

Wie gesagt, Ansistring istnicht kompatibel mit einem D5 String, sieh die mal die Abschnitte über das memory layout von Strings im Delphi Language Guide der beiden Versionen an. Und wenn Du schonmal dabei bist, auch die Infos darüber, wie Funktionen mit komplexen Rückgabewerten wie String implementiert werden: in Wirklichekeit ist das nämlich

Delphi-Quellcode:
procedure ExportString(var S; string);
d.h. der Aufruf übergibt die Addresse der Variable s an die Dll, die dann im Speicher der Hostanwendung herumpfuscht.

Codehunter 17. Jul 2019 17:02

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Ich bin echt neugierig ob der Umweg über eine Wrapper-DLL funktioniert. Weil IMHO doch dann immer noch der Speichermanager der Hostanwendung am Werk ist. Oder denk ich da jetzt falsch und jede DLL verwaltet ihren Speicher selbst?

peterbelow 18. Jul 2019 10:15

AW: String aus D5 DLL in Delphi 10.2 einslesen
 
Zitat:

Zitat von Codehunter (Beitrag 1436947)
Ich bin echt neugierig ob der Umweg über eine Wrapper-DLL funktioniert. Weil IMHO doch dann immer noch der Speichermanager der Hostanwendung am Werk ist. Oder denk ich da jetzt falsch und jede DLL verwaltet ihren Speicher selbst?

Wenn die Wrapper-Dll wie eine API-Dll implementiert wird gibt das Problem nicht, weil keine dynamisch allokierten Speicherblöcke von einem anderen Modul freigegeben werden können. Um Daten von einer solchen DLL zu holen allokiert der Aufrufer einen Block ausreichender Größe, reicht den Pointer darauf und die Größe des Blocks an die DLL weiter, und die kopiert die Daten in den Block.

Die Wrapper-DLL und die gewrappte sind beide mit D5 geschrieben und können daher (müssen sogar) ShareMem (die D5 Version) verwenden. Aber die Tokyo-Anwendung kann die Wrapper-DLL ohne Sharemem verwenden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:05 Uhr.
Seite 2 von 2     12   

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