Seite 2 von 2

Re: Fehler nach NewPrinterPage()

Verfasst: 16.11.2014 11:59
von Dieter
Hallo Shardik,
ich habe selbstverständlich auch deinen Code ausprobiert. Allerdings bekomme ich bei DirectoryEntryName() nur mit
aktivierter Unicode-Option Dateinamen mit Umlauten geliefert. Deshalb konnte ich ihn dann leider doch nicht verwenden.
Gruß
Dieter

Re: Fehler nach NewPrinterPage()

Verfasst: 16.11.2014 15:56
von Sicro
@Shardik:

Ich habe dich ja schon auf den doppelt großen Buffer hingewiesen, der per Space() in deinem Code erzeugt wird.
Damit du ts-soft und mich besser verstehst, habe ich kurz einen Code erstellt, der die Problematik klar veranschaulichen sollte.
Führe diesen Code im Unicode-Modus aus und schau dir die Debug-Ausgabe an:

Code: Alles auswählen

Define.s Text, Buffer, Output
Define.i BufferSize, i

;Text = "hr"
Text = "hallo"

Buffer = Space(StringByteLength(Text, #PB_Ascii))
BufferSize = StringByteLength(Buffer) + SizeOf(Character)
Debug "Buffer-Größe: " + BufferSize + " Bytes"
Debug "Variable-Inhalt: " + Text
Debug ""

For i = 0 To BufferSize-1
  Select PeekB(@Buffer + i)
    Case 32: Output + "[Leerzeichen]"
    Case  0: Output + "[Null]"
  EndSelect
Next
Debug "Buffer-Inhalt: " + Output 
Debug "Wie man sieht, wird zu viel Buffer reserviert und an jedem Leerzeichen noch ein Null-Zeichen angefügt."
Debug "Korrekt wäre:"
Output = ""
For i = 1 To Len(Text)
  Output + "[Leerzeichen]"
Next
Output + "[Null]"
Debug "Buffer-Inhalt: " + Output
Debug ""

Debug "Wir füllen den Buffer nun mit dem Inhalt der Text-Variable:"
PokeS(@Buffer, Text, -1, #PB_Ascii)
Output = ""
For i = 0 To BufferSize-1
  Byte = PeekB(@Buffer + i)
  Select Byte
    Case 32: Output + "[Leerzeichen]"
    Case 0:  Output + "[Null]"
    Default: Output + Chr(Byte)
  EndSelect
Next
Debug "Buffer-Inhalt: " + Output
Debug "Korrekt wäre:"
Output = Text
Output + "[Null]"
Debug "Buffer-Inhalt: " + Output
Debug ""
Debug "String-Länge mit PB-Len(): " + Len(Buffer)
Debug "Zeichen mit PB-Mid(): " + Mid(Buffer, 1)
Debug "Zeichen mit PB-Left(): " + Left(Buffer, 1)
Debug "Zeichen mit PB-Right(): " + Right(Buffer, 1)
Debug ""
Debug "Es gibt sicherlich noch weitere Funktionen, die eine falsche Ausgabe geben."
Debug "Diese sollten jedoch zur Darstellung der Problematik genügen."
Als Debug-Ausgabe erhalte ich mit eingeschaltetem Unicode-Modus:

Code: Alles auswählen

Buffer-Größe: 12 Bytes
Variable-Inhalt: hallo

Buffer-Inhalt: [Leerzeichen][Null][Leerzeichen][Null][Leerzeichen][Null][Leerzeichen][Null][Leerzeichen][Null][Null][Null]
Wie man sieht, wird zu viel Buffer reserviert und an jedem Leerzeichen noch ein Null-Zeichen angefügt.
Korrekt wäre:
Buffer-Inhalt: [Leerzeichen][Leerzeichen][Leerzeichen][Leerzeichen][Leerzeichen][Null]

Wir füllen den Buffer nun mit dem Inhalt der Text-Variable:
Buffer-Inhalt: hallo[Null][Leerzeichen][Null][Leerzeichen][Null][Null][Null]
Korrekt wäre:
Buffer-Inhalt: hallo[Null]

String-Länge mit PB-Len(): 5
Zeichen mit PB-Mid(): 慨汬o  
Zeichen mit PB-Left(): 慨
Zeichen mit PB-Right():  

Es gibt sicherlich noch weitere Funktionen, die eine falsche Ausgabe geben.
Diese sollten jedoch zur Darstellung der Problematik genügen.

Code: Alles auswählen

Buffer-Größe: 6 Bytes
Variable-Inhalt: hr

Buffer-Inhalt: [Leerzeichen][Null][Leerzeichen][Null][Null][Null]
Wie man sieht, wird zu viel Buffer reserviert und an jedem Leerzeichen noch ein Null-Zeichen angefügt.
Korrekt wäre:
Buffer-Inhalt: [Leerzeichen][Leerzeichen][Null]

Wir füllen den Buffer nun mit dem Inhalt der Text-Variable:
Buffer-Inhalt: hr[Null][Null][Null][Null]
Korrekt wäre:
Buffer-Inhalt: hr[Null]

String-Länge mit PB-Len(): 1
Zeichen mit PB-Mid(): 牨
Zeichen mit PB-Left(): 牨
Zeichen mit PB-Right(): 牨

Es gibt sicherlich noch weitere Funktionen, die eine falsche Ausgabe geben.
Diese sollten jedoch zur Darstellung der Problematik genügen.

Re: Fehler nach NewPrinterPage()

Verfasst: 16.11.2014 16:28
von ts-soft
Einfache Sache: Wir kompilieren im Unicode-Modus, das heißt alle Strings sind im Unicode-Modus, es gibt
keine Strings neben mir.

Code: Alles auswählen

ASCIIText = Space(StringByteLength(Text, #PB_Ascii))
@ASCIIText könnte als Buffer für ASCII dienen, aber ASCIIText.s ist nicht mehr nutzbar!

Du übergibst ASCIIText.s an DrawText(...), welches ungültig sein könnte, da nur Unicode-Strings verwaltet
werden. Den Buffer dürftest Du übergeben, aber der wird ja von DrawText() nicht erwartet.

Okay, der Stringmanager merkt es nicht, da keine Aktion und die defekte API auch nicht, so funktioniert der
Code, mehr oder weniger, zufällig.

Also: Für Buffer anderer Encoding besser Speicher verwenden. Wenn Buffer per Spaces genutzt wird, dann
nur den Buffer nutzen und niemals den String!

Gruß
Thomas

Re: Fehler nach NewPrinterPage()

Verfasst: 16.11.2014 18:24
von Shardik
Vielen Dank Sicro, für Dein tolles ausführliches Beispiel, das alles wunderbar klar macht und Danke an Thomas für Deine zusätzlichen Erläuterungen.

Der Grund für den "Missbrauch" eines Unicode-Strings war einfach meine Bequemlichkeit: ich brauche keinen Speicherpuffer mit AllocateMemory() anlegen und vor allem später nicht daran denken, diesen wieder freizugeben. Mein Denkfehler lag darin, dass StringByteLength(String, #PB_Ascii) ja korrekt die Länge eines ASCII-Strings angibt, aber Space(StringByteLength(Text, #PB_Ascii)) ja doch wieder im Unicode-Modus die doppelte benötigte Länge anlegt. Dass man mit einem ASCII-String im Unicode-Modus keine String-Operationen durchführen kann, war mir natürlich klar.

In einem früheren Beispiel im englischen Forum hatte ich daher auch im Unicode-Modus die ermittelte Länge für Space() durch 2 dividiert:

Code: Alles auswählen

CompilerIf #PB_Compiler_Unicode
  ASCIIText = Space(StringByteLength(Text, #PB_Ascii) / 2)
  PokeS(@ASCIIText, Text, -1, #PB_Ascii)
CompilerElse
  ASCIIText = Text
CompilerEndIf
Was haltet ihr davon? Die Länge des "missbrauchten" Unicode-Strings ASCIIText ist dann korrekt und der Buffer-Inhalt in Sicros Beispiel wäre dann auch im Unicode-Modus hinterher korrekt. Natürlich ist klar, dass mit der Space()-Funktion im Unicode-Modus der String ASCIIString nicht mit einem korrekten ASCII-String gefüllt ist, aber er dient ja auch nur als Speicherpuffer in der benötigten Größe. Und natürlich funktionieren die String-Operationen nicht, aber man würde ja auch mit einem Speicher-Puffer keine String-Operationen durchführen wollen. Natürlich würde der Einwand von Thomas noch immer gelten, dass DrawText() keinen Buffer erwartet sondern einen String, aber es funktioniert ja trotzdem. Zugegebenermaßen würden Probleme auftreten, wenn Fred den Stringmanager in neueren PB-Versionen verändern oder "schärfere" Prüfungen einbauen würde...

Re: Fehler nach NewPrinterPage()

Verfasst: 16.11.2014 20:10
von Sicro
Shardik hat geschrieben:

Code: Alles auswählen

ASCIIText = Space(StringByteLength(Text, #PB_Ascii) / 2)
So ist es schon viel besser. Im Buffer ist dann nur noch maximal ein Byte zu viel, wenn die String-Länge eine geradene Zahl ist.