Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch? (https://www.delphipraxis.net/202995-tshfileopstruct-wieviele-null-terminatoren-braucht-der-mensch.html)

Guido Eisenbeis 1. Jan 2020 20:58

TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
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.

Dalai 1. Jan 2020 21:36

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
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:
Delphi-Quellcode:
PChar(szSource + #0);
denn IIRC hängt der Cast zu PChar bereits ein NULL an.

Grüße
Dalai

himitsu 1. Jan 2020 21:52

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
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.
Delphi-Quellcode:
'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
Delphi-Quellcode:
Pointer(MyString)
statt
Delphi-Quellcode:
PChar(MyString)
.
(einziger Nachteil des Pointer, dabei geht die Typprüfung bezüglich ANSI und Unicode verloren)

Guido Eisenbeis 2. Jan 2020 00:53

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

Zitat von himitsu (Beitrag 1454269)
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, ...

Zitat:

Zitat von himitsu (Beitrag 1454269)
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.

Zitat:

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

Delphi-Quellcode:
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?

Dalai 2. Jan 2020 01:16

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

Zitat von Guido Eisenbeis (Beitrag 1454272)
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
Delphi-Quellcode:
string
. Strings sind in Delphi AFAIK nicht nullterminiert (sie haben aber im Gegensatz zu nullterminierten Strings eine Längenangabe).

Grüße
Dalai

Guido Eisenbeis 2. Jan 2020 01:47

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

Zitat von himitsu (Beitrag 1454269)
Delphi hängt standardmäßig immer zwei Nullen an seine Strings an.

Zitat:

Zitat von Dalai (Beitrag 1454273)
Strings sind in Delphi AFAIK nicht nullterminiert ...

Ei-jei-jei, was denn nu'? :wiejetzt:

Guido Eisenbeis 2. Jan 2020 01:55

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
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
Delphi-Quellcode:
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! :)

himitsu 2. Jan 2020 02:11

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
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.

Guido Eisenbeis 2. Jan 2020 02:32

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

Zitat von Dalai (Beitrag 1454273)
TFileName ist nur ein Alias für einen
Delphi-Quellcode:
string
.

Zitat:

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! :)

himitsu 2. Jan 2020 02:41

AW: TSHFileOpStruct - Wieviele Null-Terminatoren braucht der Mensch?
 
TFileName ist kein Alias, es ist ein Nachfahre. :zwinker:

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)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:57 Uhr.
Seite 1 von 3  1 23      

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