![]() |
Delphi DLL String übergeben
Hi,
ich habe folgendes Problem. Ein bekannter hat mir unter Delphi 10.4 eine DLL übersetzt weil es nicht unter Delphi 2007 ging. Er hat auch ein kleines Test Programm gemacht damit ich sehe das alles läuft. Nun komme ich mit meinem Delphi 2007 daher. Die DLL laden usw. klappt alles. Nun versuche ich seit Samstag einen String zu übergeben. In der DLL ist die function so hinterlegt.
Delphi-Quellcode:
function ConnectApi(Key:PChar):Boolean; cdecl;
Egal wie ich es übergebe in der DLL kommt nur "Müll" an. Nicht der String. Wie gehe ich nun am besten vor? Ich habe auch per TV zugriff auf sein Delphi und könnte die Functions Parameter ändern. Was ich auch schon gemacht habe. Aber es passt nix. In 20 Stunden kann man viele (auch blöde) Sachen probieren. Aber ich bekomme es nicht hin. Ich hoffe es weiß jemand ob das überhaupt geht, also DLL mit 10.4 und Programm mir 2007. Und wenn ja, wie? Vielen Dank im voraus PS.: Nehme ich mein Testprogramm (in Delphi 2007 geschrieben) und übersetze es mit 10.4 dann läuft immer alles. Egal wie Doof/unlogisch die Parameter sind. |
AW: Delphi DLL String übergeben
In Delphi 2007 war PChar noch nicht Unicode. In Delphi 10.4. jedoch schon. Liegt wahrscheinlich daran... Besser wäre wohl, ihr würdet einen WideString-Parameter benutzen; der ist in allen Versionen gleich.
|
AW: Delphi DLL String übergeben
Und da kann man gar nichts machen?
|
AW: Delphi DLL String übergeben
Du könntest ggf. einen PWideChar statt PChar übergeben; das könnte vielleicht klappen.
|
AW: Delphi DLL String übergeben
Das Problem wird sein, dass D2007 (ANSI) und D10.4 (Unicode) nicht die gleiche Definition von PChar haben. Früher zeigte ein PChar auf ein Byte (Zeichen) und seit D2009 auf 2 Bytes = 1 Zeichen. Du musst deshalb sicherstellen, dass beide Delphis die Daten auf die gleiche Weise verarbeiten, also Ansi oder Unicode.
Deklariere mal in D10.4 die DLL Funktion so: function ConnectApi(Key: PAnsiChar):Boolean; cdecl; Die Routine in 10.4 muss dann den String entsrechend verarbeiten und als AnsiString übergeben. Wenn du das umgekehrte machen willst, muss du in D2007 einen WideString als PWideChar übergeben. Das müsste auch gehen. Die Deklaration in D2007 müsste dann so sein: function ConnectApi(Key: PWideChar):Boolean; cdecl; Beispiel D2007:
Delphi-Quellcode:
oder so:
var
s: WideString; begin s := 'mein key'; ConnectApi(PWideChar(s)); end;
Delphi-Quellcode:
var
s: String; begin s := 'mein key'; ConnectApi(PWideChar(WideString(s))); end; |
AW: Delphi DLL String übergeben
Könnte ich auch PAnsiString nehmen? Weil ich ja einen langen String übergeben muss.
Das hat sich überschnitten... Sorry |
AW: Delphi DLL String übergeben
Das geht. Ich brech ab. WideChar/String ist doch länger als 255, oder? Ich meine der wäre 0 Terminiert.
|
AW: Delphi DLL String übergeben
Zuerst müssen wir wissen, wie es denn nun genau gemacht wird. Bleibt die Deklaration in D1.04 so mit PChar?
Delphi-Quellcode:
Wenn dem so ist, kannst du es so machen wie in meinem vorherigen Beispiel. Du benötigst für D2007 eine andere Deklaration als in D10.4:
function ConnectApi(Key:PChar):Boolean; cdecl;
Delphi-Quellcode:
{$IFDEF UNICODE} // D2009+
function ConnectApi(Key:PChar):Boolean; cdecl {$ELSE} // D2007 function ConnectApi(Key:PWideChar):Boolean; cdecl {$ENDIF} Zitat:
|
AW: Delphi DLL String übergeben
Zitat:
|
AW: Delphi DLL String übergeben
Hi,
erstmal danke für deine Hilfe. Ich habe die DLL schon geändert in function ConnectApi(Key : PWideChar):Boolean; cdecl; Klappt einwandfrei. Das mit dem Ansi vergiss wieder. Wenn man soooo lange dran sitzt und keinen erfolg hat, dann kommen auch komische Fragen... :oops: |
AW: Delphi DLL String übergeben
Huhu,
es tut mir leid aber ich muss nochmal "Nerven". Ich hole mir einen String (die Antwort) folgendermaßen aus der DLL. Ist der String 2000 Lang klappt alles. Irgendwo bei 2500 liegt die grenze ab der ich dann komischerweise ein "Out of Memory" bekomme. Also 3000 Zeichen geht gar nicht. Ich versuche mal den Source wo es "knallt" hier zu Posten. Das ist ein kleines Testprogramm, dort kann ich die länge von dem String den haben möchte übergeben. In der DLL mache ich das...
Delphi-Quellcode:
Im Programm das...
var
Answer :WideString; procedure GetTxt(A:PWideChar;L:Integer); cdecl; var i :Integer; begin Answer:=''; for i:=0 to L-1 do begin Answer:=Answer+'A'; end; Move(Answer,A^,Length(Answer)); end;
Delphi-Quellcode:
Ich habe gestern wie wild gegoogelt aber ich finde nichts. Es spielt auch keine Rolle ob die DLL mit Delphi 10.4 oder 2007 erstellt wurde.
procedure TfMain.btnGetTxtClick(Sender: TObject);
var line :WideString; begin SetLength(Antwort,StrToInt(edtTextLen.Text)); GetTxt(@Antwort,StrToInt(edtTextLen.Text)); SetString(line,PWideChar(@Antwort[0]),Length(Antwort)); // hier geht es in die Hose. Wie gesagt ab ca. 2500 Zeichen. Bei 2000 klappt es end; Vielen Dank im voraus |
AW: Delphi DLL String übergeben
0 ist definitiv falsch:!:
Delphi-Quellcode:
oder besser
PWideChar(@Antwort[1])
Delphi-Quellcode:
(für die kurze Era wo das mal im Mobilen-Delphi ausprobiert wurde)
PWideChar(@Antwort[Low(string)])
oder einfach nur direkt
Delphi-Quellcode:
, denn Ersteres knallt dir bei einem leeren String (Length=0) gnadenlos eine Exception entgegen.
PWideChar(Antwort)
![]() Für AnsiString's und UnicodeString/String müsste ShareMem verwendet werden, oder eben als PChar übergeben. Wenn keine #0 im PChar/PWideChar oder PAnsiChar vorkommen, dann braucht man keine Länge einzeln zu übergeben. ![]() Für WideString geht es geht es auch direkt, da es nicht den DelphiMM benutzt, sondern den MemoryManager vom OLE32 und intern ist es eigentlich ein ![]() ![]() Außerdem nutzt es somit auch eine Art von ShareMem (nur halt nicht das vom Delphi), weswegen es keine Probleme mit DLLs und COM-Interfaces gibt. |
AW: Delphi DLL String übergeben
Zitat:
System._UStrFromPWCharLen für String/UnicodeString System._WStrFromPWCharLen für WideString [edit] Arg, wer hat sich denn diesen totalen Schwachsinn ausgedacht? Für WideString ist SetString komplett im A*** Echt mal, das einfach blind nach UnicodeString zu casten, ist grob fahrlässig ... hatte wohl auch wer mitbekommen und desswegen die Compilerwarnung via Pointer unterdrückt. [/edit] [edit2] Neee, das ist nur für Nicht-Windowse (iOS/ISX/Android/Linux), wo WideString heimlich ein UnicodeString ist. :oops: So oder so, warum nimmst du nicht einfach
Delphi-Quellcode:
und lässt das mit dem Len weg?
Line := A;
Oder eben direkt WideString als Parameter nutzen.
Delphi-Quellcode:
procedure GetTxt(const A: WideString); cdecl;
Und wozu das cdecl? (möglicher Aufruf aus C++ oder so?) |
AW: Delphi DLL String übergeben
Ich wollte nun sofort wenn ich aus der DLL wieder komme die Length(Antwort) ausgeben. Schon dabei scheppert es. Wenn ich mir den String Antwort im Debugger ansehe ist er meines Erachtens richtig. Auch eine Zusätzliche 0 am ende ändert nichts an der Sache. :(
Edit: @himitsu, Problem war am Anfang das die DLL unter Delphi 10.4 erstellt werden muss, ich aber mit Delphi 2007 arbeite. Da wurd ja ab Delphi 2009 etwas an den Strings geändert. "Rolf Frei" hat mich denn erstmal auf den richtigen Weg gebracht. |
AW: Delphi DLL String übergeben
nochmal
Zitat:
und deswegen fangen auch neueren LongStrings (AnsiString und UnicodeString) seit 20 Jahren mit 1 an zu zählen. Mit [0] schreibst zu in AdressOffest -1, also mitten in die Verwaltungsdaten, wo zufällig der Längen-Integer sich versteckt. |
AW: Delphi DLL String übergeben
Das mit der 0 habe ich schon geändert. Oder ist auch das Move(Answer,A^,Length(Answer)); in der DLL Falsch? Wenn ja, wie komme ich auf A^ + 1? Also A^+1 geht nicht.
|
AW: Delphi DLL String übergeben
Ups :oops:
Das im Programm habe ich falsch dargestellt. Das sieht so aus...
Delphi-Quellcode:
var
Antwort :array of Char; procedure TfMain.btnGetTxtClick(Sender: TObject); var line :WideString; begin SetLength(Antwort,StrToInt(edtTextLen.Text)); GetTxt(@Antwort,StrToInt(edtTextLen.Text)); SetString(line,PWideChar(@Antwort[1]),StrToInt(edtTextLen.Text)); //Length(Antwort)); |
AW: Delphi DLL String übergeben
dynamisches Array:
Delphi-Quellcode:
ist ein Zeiger auf die Variable, nicht auf die Daten.
@Antwort
Delphi-Quellcode:
ist ein Zeiger auf das erste Char, bzw. auf alle Chars im Array.
@Antwort[0]
Wie gesagt, mach doch einfach
Delphi-Quellcode:
und lass das ganze Rumgepointere sein.
procedure GetTxt(var A: WideString; L: Integer); cdecl;
Delphi-Quellcode:
Dann kann auch diese beschissene globale Variable weg.
procedure GetTxt(var A: WideString; L: Integer); cdecl;
var i :Integer; begin ... A := Answer; end; |
AW: Delphi DLL String übergeben
Hi,
danke dir habe es auf stdcall umgestellt. Läuft nun. Natürlich ohne Pointer :thumb: |
AW: Delphi DLL String übergeben
Du kannst ganz normal mit Strings arbeiten und benötigst kein Array of Char. Der Compiler nimmt dir da sehr viel Konvertierungsarbeit ab, wenn du es richtig machst. Ausserdem ist dir anscheinend nicht recht klar was der Unterschied von Unicode und Ansi ist. In Ansi (D2007) ist eine Zeichen (Char) ein Byte. Bei Unicode ist ein Zeichen (Char) 2 Byte. Du kannst also bei einem Speicher Movebefehl nicht einfach die Länge des String nehmen, da das dann zu wenig Speicher ist.
Delphi-Quellcode:
Das ist devinitv in der DLL falsch. Length(Answer) liefet dir die Anzahl Zeichen in Answer, aber du benötigst die Anzahl Bytes. Das muss daher so sein:
Move(Answer,A^,Length(Answer));
Delphi-Quellcode:
Leider ist mir nicht mehr so recht klar, was du nun wo genau machst. Die DLL ist immer noch mit D10.4 geschrieben? Wenn ja darfst du da keine WideStrings nutzen sondern ganz normal mit String und Char arbeiten. WideString und PWideChar bezieht sich nur auf D2007.
Move(Answer[1],A[0],Length(Answer) * SizeOf(Char));
D10.4 DLL:
Delphi-Quellcode:
D2007 Anwendung:
var
Answer :String; procedure GetTxt(A:PChar;L:Integer); cdecl; var i :Integer; begin Answer:=StringOfChar('A', L); SetLength(A, L); Move(Answer[1],A[0],Length(Answer) * SizeOf(Char)); // benötigen hier Bytes nicht Zeichen!!! end;
Delphi-Quellcode:
var
Antwort :String; // Dein D2007 kann in den TEdits, etc. eh kein Unicode nutzen, da macht es keinen Sinn mit WideString als Resultat. procedure TfMain.btnGetTxtClick(Sender: TObject); var wAntwort: Array of PWideChar; begin SetLength(wAntwort,StrToInt(edtTextLen.Text)); GetTxt(wAntwort[0],StrToInt(edtTextLen.Text)); Antwort := String(WideString(wAntwort)); // Eventuell geht es auch nur mit String(wAntwort) |
AW: Delphi DLL String übergeben
Danke, aber ich habe das schon geändert. Guck
![]() |
AW: Delphi DLL String übergeben
Du kannst auch einfach WideString verwenden und das einfach als Rückgabewert verwenden. Anders als für Strings brauchst du da nicht ShareMem, womit du dir nur unnötige Probleme und Einschränkungen schaffst (geht nur mit Delphi, Probleme bei unterschiedlichen Delphiversionen, ...).
|
AW: Delphi DLL String übergeben
Wie schon erwähnt, brauchst du für WideString und OleVariant (nicht Variant) kein ShareMem/SimpleShareMem, da hierfür bereits eine externe Speicherverwaltung genutzt wird.
@Rolf: Für externe Schnittstellen, wie z.B. DLLs, am Besten niemals dynamische Typen verwenden, also kein Char, PChar oder String, sondern nur statische Typen, wie z.B. PWideChar/PAnsiChar oder WideString. Rate mal, warum es damals 2009 fast überall geknallt hatte. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:50 Uhr. |
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