Entwickler-Ecke
Sonstiges (Delphi) - Wo liegt der Haken? String ist auf einmal ein anderer
alias5000 - Di 05.06.07 15:54
Titel: Wo liegt der Haken? String ist auf einmal ein anderer
Hi!
Ich habe ein seltsames Problem.
Das Problem ist folgendes:
Ich packe in ein Objekt einen String rein, reiche den über 5 Ecken weiter und bekomme dann später einen anderen String da rein. Und dazu einen ganz seltsamen.
Der Hintergrund ist folgender:
Ich habe mir eine Komponente geschrieben, die mir mein selbst definiertes Textformatierungsformat in HTML umwandelt.
Da das Umwandeln in einem Thread passiert, wird das Programm über ein Event benachrichtigt, wenn das Umwandeln fertig ist. Es müssen aber Informationen weitergegeben werden, zwischen der Methode, die das Umwandeln anstößt und dem Zeitpunkt, an dem das Umwandeln fertig ist. Das sollen beliebige Daten sein (die Anwendung soll den Typ bestimmen können), daher ist das einfach ein Pointer.
Wenn die Anwendung das Umwandeln anstößt, passiert folgendes:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| info := THTMLConvInfo.Create; info.Log := log; info.HTMLSource := Source; info.AdditionalText := PChar(GlobalSettings.TextConv.FormatStringToHTML(Utils.GetLogMessageBegin(User), Font) + '<br>%%&&MESSAGETEXT&&%%<br>'); info.ReplacePattern := PChar('%%&&MESSAGETEXT&&%%'); GlobalSettings.TextConv.ParseToHTML(Text, info); |
info ist vom Typ THTMLConvInfo, der wie folgt definiert ist und das Konstrukt ist, dass die Anwendungsspezifischen Daten enthält:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| THTMLConvInfo = class Log: THTMLViewer; HTMLSource: TStringList; AdditionalText: PChar; ReplacePattern: PChar; end; |
In der Komponente, die nach HTML umwandelt (zu ihr gehört die Methode ParseToHTML) wird ein Thread erstellt (Ableitung von TThread), in dessen Konstruktor der Pointer "Data" einfach weitergegeben wird und in einer Variable im Thread-Objekt gespeichert ist.
Die Execute-Methode des Threads sieht so aus:
Delphi-Quelltext
1: 2: 3:
| ConvertToRealHTML(fInput, fOutput, fParserOffset); |
Durch Debuggen habe ich rausgefunden, dass sich der PChar AdditionalInfo in dem Objekt THTMLConvInfo mal in einen anderen ändert (obwohl er nicht sollte), oder auch nicht.
Beim Debuggen bin ich darauf gestoßen, dass an dieser Codestelle der PChar AdditionalText (das Objekt dazu ist ja im allgemeinen Pointer "Data" des Thread Objekts gespeichert) in den Text "Output" ändert und dies dann später auch in der Hauptanwendung so ankommt.
Die Codestelle ist ein schlichtes insert:
Delphi-Quelltext
1: 2:
| Insert(newtag, Output, CurrentPosition); |
Output ist wie gesagt ein string, dessen Wert mein AdditionalText auch übernimmt, aber halt nur manchmal. Output ist schon in der Deklaration der Methode ConvertToRealHTML deklariert. Der Rest sind nur lokale Variablen, die sich aus dem Kontext ergeben sollten.
Jetzt hatte ich vermutet, dass die Informationen, auf die der Pointer zeigt, einfach verloren gehen. Dann habe ich aber mal den Pointer zu Testzwecken durch das ersetzt, was ich da in meinem Fall reinlade, nämlich eine Instanz von THTMLConvInfo. Das Ergebnis ist leider immernoch dasselbe :cry:
Gruß
alias5000
Posting nochmal komplett überarbeitet, um das Problem etwas klarer darzustellenEdit2: Letzten Absatz verändert
alias5000 - Di 05.06.07 16:17
Dank
GTA-Place's Hinweis hat sich rausgestellt, dass vor dem PostMessage der String auch schon nimmer stimmt.
Gruß
alias5000
Edit: durch das editierte Post oben verliert dieser Post seinen Sinn
alias5000 - Mi 06.06.07 00:54
Die Sache wird nun etwas seltsam für mich.
Ich hab dem ganzen mal hinterherdebuggt, mit folgendem Ergebnis:
Der Wert ändert sich in der Routine ConvertToRealHTML, die im Thread ausgeführt wird und letztendlich den Input in meinem Format in den Output in HTML-Formatierung umwandelt.
Die Routine ist, zur Erinnerung, wiefolgt deklariert:
Delphi-Quelltext
1:
| procedure TLC2HTMLParserThread.ConvertToRealHTML(Input: string; var Output: string; Offset: integer); |
Die Variable fData (Typ Pointer), in der der String steckt, der sich verändert, wird in der gesamten Routine nicht ein einzigstes mal angefasst.
Wenn ich folgende Anweisung ausführe, ändert sich häufiger der String in den String, der in der Variable "Output" (im folgenden Quelltext) steckt:
Delphi-Quelltext
1:
| Insert(newtag, Output, CurrentPosition); |
newtag ist vom Typ string und schlichtweg der HTML-Tag, der in den String als neuer eingefügt werden soll, Output dann natürlich der String, in den alles geht (das ist die Variable, die im header der Routine ConvertToRealHTML deklariert ist) und CurrentPoisition ist ja klar, denk ich mal.
Da fData ein Pointer ist, kann das sein, dass durch ein insert im Speiher irgendwas verschoben wird???
Ich steh grad gewaltig auf dem SChlauch...
gruß
alias5000
Edit: das habe ich auch in den ersten Post mit eingearbeitet
Narses - Mi 06.06.07 01:18
Moin!
Ich gebe zu, ich blicke auf Anhieb nicht voll durch, was du da im Detail tust, aber ich gebe mal folgendes zu bedenken, da du ja auch schon selbst auf die Pointer-Zusammenhänge verwiesen hast:
Wenn du (lange Delphi-)Strings durch Pointer "weiterreichst", dann hängst du AFAIK die Compiler-Magic ab, die an den Strings "hängt". :idea:
Vielleicht kann
BenBE dazu bessere "Auskünfte" geben, ich stecke nicht soo tief im Compiler... :?
cu
Narses
alias5000 - Mi 06.06.07 01:50
Das du da nicht genau durchblickst, versteh ich, iss ja auch recht langatmig beschrieben. Morgen editier ich vllcht den Beitrag nochmal zusammen, weil ich das Problem ja jetzt eingrenzen konnte.
Ich sprech Benny morgen mal an, ob er was weiß :idea:
Dass er die Strings evtl. "verliert" hate ich auch schon überlegt (nur als Spekulation) und hatte daraufhin (ohne zu wissen, ob das konkret was ändert) auf PChar umgeschwenkt. Auch wenn ich "Data" als TObject, statt Pointer weitergebe, ändert sich nichts am Verhalten (was ich auch nicht ernsthaft erwarte) :cry:
alzaimar - Mi 06.06.07 06:44
Wieso verwendest Du überhaupt Windows-Botschaften? Deklariere Dir einfach ein Event 'OnAfterConvert':
Delphi-Quelltext
1:
| TAfterConvertEvent = Procedure (Sender : TObject; Const anOutput, aData : String); |
Und ParseToHTML erhält einen weiteren Parameter, nämlich die Callback-Routine.
So wäre das sauber in imho spricht nichts dagegen, daß das dann sauber funktioniert.
Neben den erwähnten Problemen mit den String-Referenzzählern könnte ich mir auch noch vorstellen, das der Thread gar nicht mehr lebt, wenn die Windows-Botschaft abgearbeitet wird: Schließlich arbeitest Du mit PostMessage, und da weiss man ja nie, wann die Message verdaut wird.
alias5000 - Mi 06.06.07 10:59
Das mit den Windows Botschaften habe ich rausgenommen, auch weil sich damit nichts an dem eigentlichen Problem ändert. Das tritt im Thread selbst schon auf (beschrieben im Post vor dem von Narses).
Gruß
alias5000
Edit: So ich habe jetzt wie versprochen das erste Posting so editiert, dass die eigentliche Problemstelle hoffentlich etwas klarer wird
Edit2: ich habe oben noch etwas neues hinzugefügt (dass ich mal den Pointer durch das konkrete THTMLConvInfo ersetzt habe)
alzaimar - Mi 06.06.07 11:29
Ah, sorry. Mein Tip: Alle PCHAR raus, und statt dessen String rein. Denn Insert verschiebt natürlich Speicher und den ganzen String auch... Wenn Du mit Strings arbeitest, musst du dich damit nicht rumschlagen...
alias5000 - Mi 06.06.07 11:36
Woooohooooo
Das wars :D
Ich weiß jetzt nimmer, warum ich da PChars eingesetzt habe (den Grund habe ich glaub ich inzwischen eh aus der Source rauseditiert), aber jetzt funktioniert es einwandfrei :D
Vielen Dank
alias5000
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!