Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Probleme mit PWideChar (https://www.delphipraxis.net/204264-probleme-mit-pwidechar.html)

Benmik 12. Mai 2020 16:16

Probleme mit PWideChar
 
Ich parse die MFT mittels eines USN-Records:
Delphi-Quellcode:
  USN_RECORD = record
    ...
    FileNameLength: Word;
    FileNameOffset: Word;
    FileName: PWChar;
  end;
Dort ist FileName als PWChar deklariert, was über MarshaledString ein PWideChar ist.
Die Zuweisung von FileName geschieht in
Delphi-Quellcode:
function USNRecFromPointer(const P: Pointer): TUSNRecord;
(P ist ein Pointer auf den Laufwerks-Char) mittels
Delphi-Quellcode:
Result.FileName := PWChar(Integer(P) + Result.FileNameOffset);
Wenn ich mir nun innerhalb dieser Funktion den Wert von Result.FileName im Debugger anzeigen lasse, dann wird der korrekte Dateiname angezeigt. In der Prozedur, die USNRecFromPointer aufruft und den TUSNRecord zurück erhält, ist aber FileName plötzlich ein String der Länge FileNameLength voller kryptischer Unicode-Zeichen. Die Zuweisung an eine String-Variable ändert daran nichts.

Die einzige funktionierende Lösung, die ich gefunden habe, ist
Delphi-Quellcode:
WideCharToString(PWChar(Integer(AUSN) + AUSN.FileNameOffset)
.

Hier fiel mir nun auf, dass der Dateiname in einigen Fällen um ein oder zwei Zeichen zu lang war. Ich dachte mir, dass der Record die FileNameLength vielleicht nicht umsonst mitliefert. Da ein WideChar 2 Bytes umfasst, musste ich die Länge halbieren und kam auf
Delphi-Quellcode:
WideCharLenToString(PWChar(Integer(AUSN) + AUSN.FileNameOffset),Round(AUSN.FileNameLength / 2))
, was auch endlich anstandslos funktioniert. Aber das kann es ja wohl nicht sein. Was geht da eigentlich vor? Und warum wird FileName im identischen Record einmal "richtig" und einmal als UTF-16-String angezeigt?

Assarbad 12. Mai 2020 16:39

AW: Probleme mit PWideChar
 
Also, dies entspricht in etwa einem UNICODE_STRING der kommt im Kernel und Usermode auf Windows massig vor. Wichtig ist, daß es ein gezählter String ist (das dient der Sicherheit).

Der Inhalt dieser Strings muß nicht zwingend nullterminiert sein. Liegt hier vielleicht schon das Problem?

Außerdem sind die beiden Längenangaben immer gerade Zahlen, da sie die Anzahl in Bytes und nicht etwa in WideChar angeben.

Leider gibst du keinen relevanten Code, weshalb ich nur diese beiden Punkte als Denkanstoß liefern kann. Kannst du noch Code nachliefern (WideCharLenToString, WideCharToString ...)?

Benmik 12. Mai 2020 16:41

AW: Probleme mit PWideChar
 
Ich dachte, ich hätte alles Wichtige an Code mitgeliefert. Was fehlt dir?

EDIT: Das sind Delphi-Funktionen.

Assarbad 12. Mai 2020 16:46

AW: Probleme mit PWideChar
 
Zitat:

Zitat von Benmik (Beitrag 1464399)
Ich dachte, ich hätte alles Wichtige an Code mitgeliefert. Was fehlt dir?

EDIT: Das sind Delphi-Funktionen.

Alles klar. Dann übergebe ich mal an die Delphianer die es noch immer sind.

Das mit der Nullterminierung ist also schon ausgeschlossen? Kurzum: nach wiederholter Lektüre deines Beitrags eingangs, scheinst du dich über die Zählung in Bytes zu ärgern und über die Tatsache, daß die Strings nicht nullterminiert daherkommen, oder? Umgekehrt gefragt: woher die Annahme daß das nicht sein kann? Eigentlich ist das so ganz normal.

Übrigens ist Round() falsch. Wenn du einen ungeraden Zahlwert in dem Feld siehst, darfst du getrost davon ausgehen, daß der Wert nicht stimmt.

Benmik 12. Mai 2020 16:53

AW: Probleme mit PWideChar
 
Zitat:

Zitat von Assarbad (Beitrag 1464400)
...scheinst du dich über die Zählung in Bytes zu ärgern und über die Tatsache, daß die Strings nicht nullterminiert daherkommen, oder?

Nein, mein Code erscheint mir als Gefrickel und ich denke, dass es eine bessere Lösung gibt.

Das Round ist notwendig, damit ein Integer rauskommt. Ich hätte auch Trunc() nehmen können.

himitsu 12. Mai 2020 17:00

AW: Probleme mit PWideChar
 
Ja, der Debugger sieht den Typ "PWideChar" und nimmt das als Nullterminiert an,
was aber egal ist, so lange doe Werte in FileName und FileNameLength korrekt sind und zusammenpassen, gehen die entsprechenden Funktionen damit "richtig" um, welche diesen Typ dann auch korrekt via Längenangabe auswerten.

Wie Assarbad schon sagte, wenn dieser Typ nicht nullterminiert ist (sein muß), dann muß man eben auch die Längenangabe verwenden, wenn man den String auslesen will.

Neben WideCharLenToString gibt es auch noch Delphi-Referenz durchsuchenSetString,
aber diese brauchst du ja nur, wenn du selber diesen "String" auslesen und in einen Delphi-String umwandeln willst.


Das, was du als Zeiger an USNRecFromPointer übergibst, das wird nicht zufällig zwischendurch freigegeben, nachdem du diese Funktion aufgerufen hattest?
Der Dateiname bleibt weiterhin in der anderen Struktur und dieses USNRecFromPointer scheint nur einen Record zu erstellen, der darauf zeigt. (jedenfalls sieht die halbgezeigt Zeile Code danach aus)

Würde dann in etwa so aussehn.
Delphi-Quellcode:
SetString(S, PWideChar(NativeInt(AUSN) + AUSN.FileNameOffset), AUSN.FileNameLength div SizeOf(WideChar)); // oder einfach nur "div 2"



PS: statt NativeInt bzw. NativeUInt verwende ich lieber einen Typ IntPtr (was im Prinzip auch nur ein NativeInt ist, aber so besser anzeigt, was er machen will).

Benmik 12. Mai 2020 17:18

AW: Probleme mit PWideChar
 
Da bringt mich ja schon mal gut weiter.

Die aufrufende Routine heißt
Delphi-Quellcode:
function TFrmMFT.MFTEnumCallback(AUSN: PUSNRecord; Extra: Pointer): Boolean;
, und sie ruft als Erstes
Delphi-Quellcode:
USNRecFromPointer(AUSN);
auf. Dazwischen geschieht nichts.

Bei einem Beispiel-Dateinamen werden 41 Zeichen übergeben, das letzte ist nicht #0; die FileNameLength ist 22 und der Dateiname 11 Zeichen lang.

EDIT: SetString funktioniert auch einwandfrei.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:42 Uhr.

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