AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
Thema durchsuchen
Ansicht
Themen-Optionen

TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

Ein Thema von Guido Eisenbeis · begonnen am 1. Jan 2020 · letzter Beitrag vom 7. Jan 2020
Antwort Antwort
Seite 1 von 3  1 23      
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#1

TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 1. Jan 2020, 20:58
Nachdem ich ewig lange recherchiert habe, wie man komplette Ordnerinhalte kopiert (alle Dateien und Unterordner), habe ich nicht wirklich herausfinden können, wieviele Null-Terminatoren bei den Pfaden im TSHFileOpStruct benötigt werden.

Microsoft sagt unter Remarks, Important: "You must ensure that the source and destination paths are double-null terminated. ..."

Manche Codes im INet benutzen TStrings oder AnsiString, andere benutzen TFileName. Die einen terminieren pFrom und pTo überhaupt nicht zusätzlich, andere mit 1 zusätzlichen #0, und wiederum andere mit 2 zusätzlichen #0. Erstaunlicherweise sind die meisten Beiträge, die ich dazu gefunden habe, aus den frühen 2000er Jahren. Da ist ja viel Zeit vergangen. Wie sieht das denn heute aus? Welcher Eingangs-Dateityp (für Source- und Destination-Path) muss mit wie vielen Terminatoren ergänzt werden, wenn er mit PChar() an pFrom und pTo übergeben wird?

Im Moment benutze ich den folgenden Code, der TFileName als Typ für Source und Destination verwendet. Dabei werden keine zusätzlichen Null-Terminatoren benutzt. Ist das überhaupt in Ordnung? Leider konnte ich diesbezüglich keine Informationen zu TFileName finden.

Delphi-Quellcode:
// Routine zum Kopieren von Dateien und Ordnern.
function SHCopyFile(Handle: THandle; szSource, szDestination: TFileName): Boolean;
var
  ShellFileOperation: TSHFileOpStruct;
begin
  Result := True;
  try
    with ShellFileOperation do
    begin
      Wnd := 0;
      wFunc := FO_COPY;
      pFrom := PChar(szSource);
      pTo := PChar(szDestination);
      fFlags := FOF_NOCONFIRMMKDIR or FOF_NOCONFIRMATION;
    end;
    SHFileOperation(ShellFileOperation);
  except
    Result := False;
  end;
end;
Guido.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.680 Beiträge
 
Delphi 5 Professional
 
#2

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 1. Jan 2020, 21:36
Eigentlich steht alles in dem verlinkten MS-Artikel drin:
Zitat:
pFrom

Type: PCZZTSTR

[...]
Although this member is declared as a single null-terminated string, it is actually a buffer that can hold multiple null-delimited file names. Each file name is terminated by a single NULL character. The last file name is terminated with a double NULL character ("\0\0") to indicate the end of the buffer.
Damit die API-Funktion weiß, wo das Ende des Buffers ist, sind zwei NULLs nötig.

Im Delphi würde ich das wohl so machen: PChar(szSource + #0); denn IIRC hängt der Cast zu PChar bereits ein NULL an.

Grüße
Dalai
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#3

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 1. Jan 2020, 21:52
Delphi hängt standardmäßig immer zwei Nullen an seine Strings an. (als Kompatibilität auch zu solchen Listen)
Also im Prinzip könnte man es hier auch weglassen, aber zur Dokumentation hänge ich auch meistens die richtige Anzahl der Nullen nochmals an, also diese #0#0 für Listen. (nur bei "einfachen" PChars lasse ich diese #0 weg)

Und ja, hier sind es "eigentlich" zwei #0,
denn es ist eine Liste von Pfaden, wobei als Listenende ein Leerstring definiert ist.
'Datei1'#0 + 'Datei2'#0 + {ENDE} ''#0; , also effektiv #0#0 am Ende.

PS: Die RTTI nutzt sowas ebenfalls, z.B. bei der Namensliste für ENUMs,
oder die StringListen in den Ressources.


PS: ein PChar-Cast, von einem String aus, gibt immer einen "gültigen" Zeiger zurück.
Ein leerer String ist zwar NIL, aber hier wird dann ein Zeiger auf eine Konstante mit #0#0 zurückgegeben.
Wer für eine Funktion ein "echtes" NIL benötigt, wenn der String leer ist, der sollte mit Pointer casten Pointer(MyString) statt PChar(MyString) .
(einziger Nachteil des Pointer, dabei geht die Typprüfung bezüglich ANSI und Unicode verloren)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 1. Jan 2020 um 22:06 Uhr)
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 00:53
Delphi hängt standardmäßig immer zwei Nullen an seine Strings an. (als Kompatibilität auch zu solchen Listen)
Also im Prinzip könnte man es hier auch weglassen, ...
PS: ein PChar-Cast, von einem String aus, gibt immer einen "gültigen" Zeiger zurück.
Ein leerer String ist zwar NIL, aber hier wird dann ein Zeiger auf eine Konstante mit #0#0 zurückgegeben.
Im Delphi würde ich das wohl so machen: PChar(szSource + #0); denn IIRC hängt der Cast zu PChar bereits ein NULL an.
PChar(szSource + #0); Wie viele #0's ergibt das denn?


Gibt es denn auch "zuviele" #0's? Wenn ein string in Delphi schon standardmäßig 2 #0 hat und ich z. B. eingebe:
Delphi-Quellcode:
  pFrom := PChar(szSource + #0#0);
  pTo := PChar(szDestination + #0#0);
Kann es dann passieren, dass pFrom nun 4 #0 am Ende hat, und die Funktion das als Leerstring für pTo auswertet?

Wie sieht das denn mit TFileName aus, also mit wie vielen #0's ist TFileName abgeschlossen?
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.680 Beiträge
 
Delphi 5 Professional
 
#5

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 01:16
Wie viele #0's ergibt das denn?
Mindestens zwei.

Zitat:
Gibt es denn auch "zuviele" #0's?
Kommt auf den Anwendungszweck an. Meistens nein, und in diesem Fall definitiv nicht.

Zitat:
Wenn ein string in Delphi schon standardmäßig 2 #0 hat und ich z. B. eingebe:
Delphi-Quellcode:
  pFrom := PChar(szSource + #0#0);
  pTo := PChar(szDestination + #0#0);
Kann es dann passieren, dass pFrom nun 4 #0 am Ende hat, und die Funktion das als Leerstring für pTo auswertet?
Nein. Wie bei MS beschrieben, liest die API-Funktion bis zum ersten doppelten NULL und stoppt dort. Die Einzelstrings sind mit einfachen NULLs voneinander getrennt.

Zitat:
Wie sieht das denn mit TFileName aus, also mit wie vielen #0's ist TFileName abgeschlossen?
TFileName ist nur ein Alias für einen string . Strings sind in Delphi AFAIK nicht nullterminiert (sie haben aber im Gegensatz zu nullterminierten Strings eine Längenangabe).

Grüße
Dalai
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 01:47
Delphi hängt standardmäßig immer zwei Nullen an seine Strings an.
Strings sind in Delphi AFAIK nicht nullterminiert ...
Ei-jei-jei, was denn nu'?
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 01:55
PChar(szSource + #0) ==> Wie viele #0's ergibt das denn? ==> Mindestens zwei.

Gibt es denn auch "zuviele" #0's? ==> Kommt auf den Anwendungszweck an. Meistens nein, und in diesem Fall definitiv nicht.

Kann es dann passieren, dass pFrom nun 4 #0 am Ende hat, und die Funktion das als Leerstring für pTo auswertet? ==> Nein. Wie bei MS beschrieben, liest die API-Funktion bis zum ersten doppelten NULL und stoppt dort. Die Einzelstrings sind mit einfachen NULLs voneinander getrennt.

... mit wie vielen #0's ist TFileName abgeschlossen? ==> TFileName ist nur ein Alias für einen string . Strings sind in Delphi AFAIK nicht nullterminiert (sie haben aber im Gegensatz zu nullterminierten Strings eine Längenangabe).

@Dalai Vielen Dank für die deutlichen Aussagen!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#8

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 02:11
Jain.
Delphi-Strings sind per-se nicht null-terminiert, da ihre Länge gespeichert und von Delphi verwendet wird.
Beim ShortString (dem "String" aus TurboPascal und dem ersten Delphi) gibt es nur das Längen-Byte und keine explizite #0 am Ende.

Bei den LongStrings (AnsiString/UTF8String/RawByteString/... und UnicodeString) gibt es aber als Optimierung auch die #0#0 am Ende, damit es ohne umkopieren direkt nach PChar gecastet werden kann.
Der WideString ... OLE32-String (MSDN-Library durchsuchenSysAllocStringLen) hat auch eine Längenangabe und die #0#0 (nur ihm fehlt die Referenzzählung, welche netter Weise die Delphi-Strings besitzen).

Also Delphi/Pascal verwendet bei String-Operationen nur die Längenangabe, aber bei der Verwaltung wird hinter dem letzten Zeichen noch ein Bereich mit den #0#0 bereitgehalten.

Beispiel: StrLen im C++ liest den String Zeichen für Zeichen und sucht die erste #0 (Ende-Anfang=Länge), während Length direkt den Längen-Integer ausliest.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 2. Jan 2020 um 02:17 Uhr)
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 02:32
TFileName ist nur ein Alias für einen string .
Zitat von Aus der Delphi Hilfe:
Der Typ String ist ein Alias für UnicodeString.
Von diesen ganzen Aliasen (Aliases, Alianten, ... Aliens?) schwirrt mir der Kopf. Ich mache es jetzt einfach so:

function SHCopyFile(Handle: THandle; szSource, szDestination: TFileName): Boolean;
...
pFrom := PChar(szSource + #0);
pTo := PChar(szDestination + #0);

Vielen Dank für eure Infos!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#10

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?

  Alt 2. Jan 2020, 02:41
TFileName ist kein Alias, es ist ein Nachfahre.

Delphi-Quellcode:
type
  TFileName = type string;
              ^^^^
Definiert einen neuen Typ mit den selben Eigenschaften, welcher auch zuweisungskompatibel ist.

String ist sowas, wie Integer früher und NativeInt jetzt ist ... er ist ein Alias auf den nativen Typen des Compilers.
* vor Delphi2009 war es der AnsiString
* und gaaaaaanz früher war es kein Alias, da war es der Typ String, welcher jetzt ShortString heißt (aber der Einfachheit halber könnte man es da als Alias für den ShortString sehen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:31 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