Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Stringübergabe in DLL´s (https://www.delphipraxis.net/731-stringuebergabe-dll%B4s.html)

Christian Seehase 30. Aug 2002 10:49

Moin Christian,

könntest Du bitte mal den Code der Routine die den string erzeugt, und der verarbeitenden Funktion posten (incl. Aufruf derselben)?
Irgendwie kann ich mir im Moment keine Ursache für das Problem erklären.
Der Funktionsabschnitt, in der die Execpetion ausgelöst wird wäre auch nicht schlecht.

Luckie 30. Aug 2002 12:44

Kuckst du hier: http://home.t-online.de/home/PeterJH...icles/dlls.htm

Christian Kaufmann 30. Aug 2002 12:48

Am Formular ist ein Memofeld und ein Button.


function spiegeln(p:pchar):pchar;
var
i:integer;
test1,test:string ;
begin

test:=string(p);
test1:='';
for i := length(test) downto 1 do
begin
test1:=test1+test[i];
end;
result:=pchar(test1);

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
memo1.Text:=(spiegeln(pchar(memo1.Text)));
end;

jbg 30. Aug 2002 13:19

Code:
[b]function[/b] spiegeln(p: PChar): PChar;
[b]var[/b] test: [b]string;
begin[/b]
  test := [b]string[/b](p);
  ...
  Result := PChar(test);
[b]end[/b];
Um dir mal zu erklären, warum das nicht funktioniert:

Dein Programm ruft spiegeln(PChar(MyString)) auf, dabei wird PChar(MyString) auf dem sog. Stack abgelegt und p zeigt auf die Speicherstelle im Stack, an der PChar(MyString) liegt. (Danach kommt noch die Rücksprungadresse auf den Stack.)
Nun wird Platz auf dem Stack für die lokale Variable test gemacht. In diese kopierst du den PChar, auf den p zeigt und führst deine Umkehrung durch.
Bis jetzt funktioniert alles, doch nun kommt der entscheidende logische Fehler:
Du weist Result nun einen Zeiger (PChar ist ja nur ein Zeiger) auf die Speicheradresse, an der test abgelegt ist, zu. Doch da test eine lokale Variable ist und somit auf dem Stack liegt, zeigt Result auf eine Adresse im Stack.
Durch das end; wird nun aber der von test belegte Stack-Speicher freigegeben, womit Result auf einen bereits freigegebenen Speicherbereich zeigt. Wenn nun ein weiterer Funktionsaufruf nach dem Zurückkehren der spiegeln-Funktion stattfindet (es reicht auch eine einfache Zuweisung von Variablen), dann überschreibt diese die noch auf dem Stack an der Result-"Adresse" liegenden, unveränderten Bytes mit ihren eigenen lokalen Variablen und Parametern.
Deswegen liefert die Funktion nur noch Bytesschrott zurück, der auch noch zum teilweise auch noch aus den "orignal"-Daten bestehen kann (was die Fehlersuche dann eher auf die Funktion selbst ziegt).


Das Problem könntest du z.B. so lösen, dass du den String "in-place" spiegelst (also Eingabe-Parameter = Ausgabe-Parameter):
Code:
[b]procedure[/b] spiegeln(p: PChar);
[b]var[/b] s: [b]string[/b];
[b]begin[/b]
  s := p;
  ...
  StrLCopy(p, PChar(s), StrLen(p)); // Daten in p zurückschreiben
[b]end[/b];

s := 'Dies ist ein Test';
spiegeln(PChar(s));
ShowMessage(s);
Das in-place-Verfahren funktioniert nur, wenn die Länge der Eingabedaten mit der der Ausgabe-Daten übereinstimmt.

Oder um es WinAPI gerecht zu machen:
Code:
[b]function[/b] spiegeln(p: PChar; Buffer: PChar; MaxBufferLen: Integer): Integer;
[b]var[/b] s: [b]string[/b];
[b]begin[/b]
  s := p;
  ...
  [b]if[/b] Buffer <> [b]nil then[/b]
    StrLCopy(Buffer, PChar(s), MaxBufferLen); // Daten in Buffer schreiben
  Result := Length(s); // Rückgabewert = Länge des bearbeiteten Strings
[b]end[/b];

[b]var[/b]
  Buf: PChar;
  BufSize: Integer;
[b]begin[/b]
  s := 'Dies ist ein Test';
  BufSize := spiegeln(PChar(s), nil, 0);
  Buf := StrAlloc(BufSize);
  [b]try[/b]
    spiegeln(PChar(s), Buf, BufSize);
  [b]finally[/b]
    StrDipose(Buf);
  [b]end[/b];
  ShowMessage(s);
[b]end[/b];

[i]// Wenn die max. Aufgabelänge bekannt ist, dann geht das auch so:[/i]
[b]var[/b] Buf: [b]array[/b][0..1024] [b]of[/b] Char;
SetString(s, Buf, spiegeln(PChar(s), Buf, 1024));
ShowMessage(s);
Ein function Xyz: PChar; sollte man nur verwenden, wenn man konstante oder global deklarierte Strings einsetzt. Konstante Strings sind nur Strings, die in '' stehen. Wenn ein + oder ein Funktionsaufruf notwendig sind, dann handelt es sich nicht um konstante Strings, da sie erst zur Laufzeit zusammengesetzt werden müssen. Am einfachsten kann man herausbekommen, ob ein String konstant ist oder nicht, indem man sich selbst nur Fragen muss, könnte man diesen String auch so deklarieren:

const MyString = 'Hier steht der zu "prüfende" String';

Christian Kaufmann 30. Aug 2002 17:23

Alles klar, ich hab einfach übersehen, daß ich mit dem result natürlich einen zeiger auf die stringvariable in der funktion zurückgebe, die natürlich nach dem end dereferenziert wird.
manchmal ist man schrecklich blind


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