![]() |
Delphi-Version: 10.1 Berlin
Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Hallo zusammen,
ich habe mich lange Zeit nicht mehr mit Delphi beschäftigt und stehe nun vor einem Problem, welches ich alleine anscheinend nicht bewältigen kann. Folgende Ausgangs-Situation: Ich muss aus C# eine Delphi-DLL mit Parametern (BSTR -> WideString) aufrufen, in der DLL ein PDF erzeugen und dieses base64-decodiert wieder zurückgeben. Das funktioniert auch alles; naja - der Aufruf zumindest und es kommt auch etwas zurück. Das Problem, mit welchem ich derzeit kämpfe ist folgendes: Die Delphi-DLL ist sehr komplex und es erfolgt eine lange Kette von Prozedur-/Funktionsaufrufen. Am Ende der Kette wird der String erzeugt, welchen ich am Anfang der DLL wieder herausgeben muss. Die PDF-Engine schreibt dazu in einen StringStream. Da es sehr aufwändig wäre, diesen String - nachträglich - durch die Prozeduren/Funktionen durchzureichen (würde einen sehr großen Aufwand bedeuten), dachte ich mir, dass ich das über Pointer realisiere. Das Resultat: mal geht es, mal nicht und ich glaube, dass das am Speicherreservieren usw. hängt. In der DLL habe ich ein paar Variablen in die ich später die Adresse für die PDF-Daten sowie deren Größe schreibe und entsprechende Pointer darauf.
Delphi-Quellcode:
Diese übergebe ich in die Klasse, die das PDF-Dokument erzeugt.
// in der DLL
BinaryContentAddress: Integer; // address of the binary content PBinaryContentAddress: ^Integer; BinaryContentSize: Integer; // size of the binary content PBinaryContentSize: ^Integer;
Delphi-Quellcode:
Wenn das Ganze durch ist bin ich wieder zurück am Anfang der DLL.
// Aufruf der Methode Data2Ext der Klasse 1
Data2Ext(PBinaryContentAddress, PBinaryContentSize, PStringContentAddress, PStringContentSize); // ... // Implementierung in Klasse 1 FOutputStreamInt: TStringStream; // internal stream for the binary content FAddressBinaryContent: Integer; // binary content address FAddressBinaryContentSize: Integer; // binary content size address // ... // Methode Data2Ext in Klasse 1 FOutputStreamInt := TStringStream.Create; FAddressBinaryContent := BinaryContentAddressPointer; FAddressBinaryContentSize := BinaryContentSizePointer; // ... // Methode, die die Pointer für die Rückgabe aufbereitet Var PBinaryContent: ^Integer; // pointer to the binary content address PBinaryContentSize: ^Integer; // pointer to the binary content size BinaryContent: PChar; Begin If (FAddressBinaryContent > 0) And (FAddressBinaryContentSize > 0) Then Begin // get external addresses PBinaryContent := Pointer(FAddressBinaryContent); PBinaryContentSize := Pointer(FAddressBinaryContentSize); // write the pchar address to the external address BinaryContent := CoTaskMemAlloc((Length(FOutputStreamInt.DataString) + 1)); Move(FOutputStreamInt.DataString[1], BinaryContent^, Length(FOutputStreamInt.DataString) + 1); PBinaryContent^ := Cardinal(BinaryContent); // write the binary content size to the external address PBinaryContentSize^ := Length(FOutputStreamInt.DataString); If Assigned(FOutputStreamInt) Then FreeAndNil(FOutputStreamInt); End; Dort möchte ich die PDF-Daten auslesen, in einen String schreiben, base64 codieren und an den Aufrufer zurückgeben.
Delphi-Quellcode:
So weit, so gut.
Var
pBinaryContent: PChar; Begin // Get the pdf data address and its size If PBinaryContentAddress <> Nil Then BinaryContentAddress := PBinaryContentAddress^; If PBinaryContentSize <> Nil Then BinaryContentSize := PBinaryContentSize^; // Get the content SetLength(sBinaryContent, BinaryContentSize); Move(PChar(BinaryContentAddress)^, sBinaryContent[1], BinaryContentSize); sBase64Content := Coder.EncodeBase64(sBinaryContent); // ... Wie bereits gesagt - manchmal ist der String invalide, der da rauskommt und manchmal nicht. Und ich fürchte, dass ich da irgendetwas grundlegend falsch mache. Ich hoffe, dass mir hier jemand behilflich seine kann. Besten Dank im Voraus. |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Du schreibst ein C# Programm?
Du Hast eine Delphi DLL welche eine PDF-Engine enthält im Quellcode vorliegen? Die Delphi DLL hat die Funktionen mit dem Paramter "STDCALL" declariert, so dass sie einem C++ konformen Aufruf ermöglichen? # Oder wurde "CDECL" verwendet so dass die Funktionen C-konform in C# eingebunden werden müssen? Warum willst du die Delphi DLL dann noch verändern? Kannst du sie nicht einfach in den C# projekt einbinden und nutzen? |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Delphi-Quellcode:
Das scheint mir schon mal falsch.
If PBinaryContentSize <> Nil Then
BinaryContentSize := PBinaryContentSize^; Welche größe hat BinaryContentSize wenn PBinaryContentSize = Nil ist? Fehlt da nicht ein begin ? Nur auf
Delphi-Quellcode:
zugreifen wenn PBinaryContentSize und PBinaryContentAddress wirklich nicht nil sind.
SetLength(sBinaryContent, BinaryContentSize);
Move(PChar(BinaryContentAddress)^, sBinaryContent[1], BinaryContentSize);
Delphi-Quellcode:
If Assigned(PBinaryContentAddress) Then
begin BinaryContentAddress := PBinaryContentAddress^; If Assigned(PBinaryContentSize) Then begin BinaryContentSize := PBinaryContentSize^; // Get the content SetLength(sBinaryContent, BinaryContentSize); Move(PChar(BinaryContentAddress)^, sBinaryContent[1], BinaryContentSize); sBase64Content := Coder.EncodeBase64(sBinaryContent); end; end; |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Hi QuickAndDirty,
Zitat:
Zitat:
Zitat:
Das Ganze ist etwas komplizierter. Das kann und möchte ich hier aber nicht alles auseinander klamüsern :) Fakt ist, dass ich das benötige, nach dem ich gefragt habe. Es gibt keine Umgehungslösung oder etwas anderes. Ich möchte lediglich wissen, ob ich das mit dem Speicher reservieren etc. so richtig mache und warum es mal funktioniert und mal nicht. Dennoch vielen Dank für Deine Antwort :) *** Hi venice2 Zitat:
Zitat:
Zitat:
Ich möchte hier aber nochmal klarstellen, dass ich keine Zugriffsverletzung o.ä. bekomme - das ist nicht das Problem! Wie oben geschrieben geht es darum, dass das, was letztendlich in meinem String landet, gelegentlich nicht passt - meistens aber schon. Daher vermute ich, dass ich beim Reservieren des Speichers oder dem Schreiben in den String (oder vorher schon in den PChar) irgendetwas falsch mache. (CoAllocMemSize oder Move falsch verwendet?). Leider gibt es dazu heutzutage auch nicht mehr viel zu finden :( [OT] R.I.P Luckie Habe es gerade erst gelesen. Seine Tutorials und Expertise haben mir vor ~15 Jahren stets gut geholfen. [/OT] |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Zitat:
greifst du immer auf diese beiden Zeilen zu.
Delphi-Quellcode:
Egal ob BinaryContentSize 0 oder einen anderen Wert enthält. Oder PBinaryContentSize nil ist oder nicht.
SetLength(sBinaryContent, BinaryContentSize);
Move(PChar(BinaryContentAddress)^, sBinaryContent[1], BinaryContentSize); Warum willst du also einen move bzw. die länge auf 0 setzen wenn es nicht nötig ist. Egal. Überdenke es noch mal. EDIT: Versuche es mal mit FillChar bevor du neue Daten ermitteln willst. |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Zitat:
Zitat:
Ich seh ein PChar ... bei externen APIs arbeitet man niemals mit dyniamischen Typen! PWideChar oder PAnsiChar Und warum seh ich irgendwie nirgendwo etwas von BSTR/WideString? |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Genau wegen deiner Problem habe ich eine Wrapper.dll in C# geschrieben die man einfach als Verweis in C# einbinden kann.
Diese regelt dann die Kommunikation zwischen der Delphi.dll -> Wrapper.dll - Anwendung in C#. Somit konnte ich auf beide Varianten des Codes Einfluß nehmen (UnmanagedType und managedType) Zudem habe ich alle Strings aus Delphi als PWideChar übergeben. Nicht als PChar ! Delphi..
Delphi-Quellcode:
Pluginfile : PWideChar;
C# Wrapper
Code:
Nur so als Anregung.
[MarshalAs(UnmanagedType.BStr)]
public string PluginFile = string.Empty; Zitat:
![]() OK bin raus :) |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Wenn in C# ein BSTR, warum dann in Delphi ein PWideChar, anstatt eines WideString? (WideString ist intern ein BSTR)
Die Delphi-DLL wird überarbeitet? Wozu dann noch ein Wrapper dazwischen, anstatt direkt? |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
Hi Himitsu,
Zitat:
Zitat:
Gib mir doch mal einen Anschubs, wie das nun mit Unicode funktioniert. Zitat:
Wie gesagt: es geht ausschließlich um den Teil innerhalb der Delphi-DLL. In C# habe ich das schon mit BSTR deklariert ([MarshalAs(UnmanagedType.BStr)]) und die aufgerufene Routine in der Delphi-Dll verwendet natürlich WideString. Das schrieb ich ja auch in meinem initialen Beitrag ;) Zitat:
Zitat:
Zitat:
Edit: Ahhhh - wie kann man das auf Englisch umstellen? Da bekommt man ja die Krise bei dieser Übersetzung. Zitat:
Zitat:
Ich habe einen Webservice, der in C# geschrieben ist. Dieser soll halt das, was die Delphi-DLL an PDF-Stream erzeugt, an den Caller zurückgeben. Das ist der ganze Zauber. |
AW: Weitergabe eines Strings über Pointer funktioniert nicht - manchmal...
vor D2009 war
String = AnsiString PChar = PAnsiChar Char = AnsiChar seit D2009 sind es String = UnicodeString PChar = PWideChar Char = WideChar Entweder alle String/PChar/Char explitit auf ANSI ändern, so wie es früher war oder jetzt so lassen, wie es nun ist, aber dennoch alle Typen auf Unicode/Wide ändern, (sie sind es jetzt schon, aber wie gesagt, niemals dynamische Typen in externen Schnittstellen) aber beachten, dass Chars dort 2 Byte groß sind, also der Speicher ist doppelt so groß, was auch bei Length/Size beachtet werden muß. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:13 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