Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Fehleranfääliges DirectoryExists auch in Delphi > XE 1? (https://www.delphipraxis.net/182746-fehleranfaeaeliges-directoryexists-auch-delphi-xe-1-a.html)

CCRDude 14. Nov 2014 12:26

Delphi-Version: XE

Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Unter Delphi XE finde ich in der SysUtils.pas:

Delphi-Quellcode:
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
var
  Code: Cardinal;
  Handle: THandle;
  LastError: Cardinal;
begin
  Result := False;
  Code := GetFileAttributes(PChar(Directory));

  if Code <> INVALID_FILE_ATTRIBUTES then
  begin
    [...]
  end
  else
  begin
    LastError := GetLastError;
    Result := (LastError <> ERROR_FILE_NOT_FOUND) and
      (LastError <> ERROR_PATH_NOT_FOUND) and
      (LastError <> ERROR_INVALID_NAME);
  end;
end;
Leider ist das fehleranfällig - es gibt Situationen, in denen GetLastError bei nicht existierenden Pfaden ungleich einer der drei Fehlermeldungen ist und damit die Existenz eines nicht existierenden Verzeichnisses angenommen wird. So erlebt unter Windows PE (Vista, Win7, Win 8 AIK/ADK-Versionen), allerdings nicht generell. Welcher Fehler dort gemeldet wird, habe ich noch nicht rausgefunden, da er nur bei Kunden auftritt, und ich ihn meist schon umschifft habe, indem ich Verzeichnisse mit FindFirst suche.

Generell ist es natürlich fehleranfällig, Erfolg anzunehmen, nur weil drei bestimmte Fehler nicht aufgetreten sind.

Daher meine Frage: ist dies in neueren Delphi-Versionen besser gelöst, kann da jemand mal in die SysUtils.pas / System.SysUtils.pas schauen bitte?
Kann das selber nicht nachschauen, die Trial hat scheinbar keine Sourcen dabei.

Bernhard Geyer 14. Nov 2014 12:56

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
In XE wird gegen folgende Fehlercodes geprüft:

ERROR_FILE_NOT_FOUND
ERROR_PATH_NOT_FOUND
ERROR_BAD_PATHNAME
ERROR_INVALID_NAME
ERROR_BAD_NETPATH
ERROR_NOT_READY
ERROR_BAD_NET_NAME

Sir Rufo 14. Nov 2014 13:57

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Mal anders gefragt:

In welchen Situationen kann es dazu kommen, dass
Delphi-Quellcode:
GetFileAttributes(PChar(Directory)) = INVALID_FILE_ATTRIBUTES
und es trotzdem um ein existierendes Verzeichnis handelt?

Ich hätte jetzt mal pauschal vermutet: keine.

Also könnte der Code wie folgt lauten
Delphi-Quellcode:
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
var
  Code: Cardinal;
  Handle: THandle;
  LastError: Cardinal;
begin
  Result := False;
  Code := GetFileAttributes(PChar(Directory));

  if Code <> INVALID_FILE_ATTRIBUTES then
  begin
    [...]
  end
  else
  begin
    Result := False;
{
    LastError := GetLastError;
    Result := (LastError <> ERROR_FILE_NOT_FOUND) and
      (LastError <> ERROR_PATH_NOT_FOUND) and
      (LastError <> ERROR_INVALID_NAME);
}
  end;
end;
ansonsten sollten die den Rückgabewert ändern auf
Delphi-Quellcode:
TDirectoryExistsResult = ( True, False, KnownByVulture );
:mrgreen:

Uwe Raabe 14. Nov 2014 14:14

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1279829)
Mal anders gefragt:

In welchen Situationen kann es dazu kommen, dass
Delphi-Quellcode:
GetFileAttributes(PChar(Directory)) = INVALID_FILE_ATTRIBUTES
und es trotzdem um ein existierendes Verzeichnis handelt?

Ich hätte jetzt mal pauschal vermutet: keine.

Nicht ganz:

Zitat:

If you call GetFileAttributes for a network share, the function fails, and GetLastError returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share.

Sir Rufo 14. Nov 2014 14:43

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1279833)
Zitat:

Zitat von Sir Rufo (Beitrag 1279829)
Mal anders gefragt:

In welchen Situationen kann es dazu kommen, dass
Delphi-Quellcode:
GetFileAttributes(PChar(Directory)) = INVALID_FILE_ATTRIBUTES
und es trotzdem um ein existierendes Verzeichnis handelt?

Ich hätte jetzt mal pauschal vermutet: keine.

Nicht ganz:

Zitat:

If you call GetFileAttributes for a network share, the function fails, and GetLastError returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share.

Soso, und wenn dieser Fehler da ist, dann ist es trotzdem ein existierendes Verzeichnis und der Rückgabewert muss
Delphi-Quellcode:
true
sein?

Kann ich nicht so wirklich glauben, denn
Zitat:

Zitat von Bernhard Geyer (Beitrag 1279819)
In XE wird gegen folgende Fehlercodes geprüft:

ERROR_FILE_NOT_FOUND
ERROR_PATH_NOT_FOUND
ERROR_BAD_PATHNAME
ERROR_INVALID_NAME
ERROR_BAD_NETPATH
ERROR_NOT_READY
ERROR_BAD_NET_NAME

Aha, also ergibt das auch
Delphi-Quellcode:
false
...

Also bei welcher Gelegenheit muss
Delphi-Quellcode:
DirectoryExists
ein
Delphi-Quellcode:
true
zurückliefern trotz dass wir bei
Delphi-Quellcode:
GetFileAttributes(PChar(Directory))
aks Rückgabe ein
Delphi-Quellcode:
INVALID_FILE_ATTRIBUTES
bekommen?

pelzig 14. Nov 2014 15:18

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Mal ganz extrem dumm gefragt:

Wat gibbes rück?

Ist das letzte Zeichen des Rückgabewertes etwa ein Backslash?

MfG

Sir Rufo 14. Nov 2014 15:27

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Ok, die wirklich korrekte Umsetzung der Funktion müsste so lauten:
Delphi-Quellcode:
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
var
  Code: Cardinal;
  Handle: THandle;
  LastError: Cardinal;
begin
  Result := False;
  Code := GetFileAttributes(PChar(Directory));

  if Code <> INVALID_FILE_ATTRIBUTES then
  begin
    [...]
  end
  else
  begin
    LastError := GetLastError;
    if
      (LastError <> ERROR_FILE_NOT_FOUND) and
      (LastError <> ERROR_PATH_NOT_FOUND) and
      (LastError <> ERROR_BAD_PATHNAME) and
      (LastError <> ERROR_INVALID_NAME) and
      (LastError <> ERROR_BAD_NETPATH) and
      (LastError <> ERROR_BAD_NET_NAME)
    then // Wir können keine Aussage darüber treffen, daher
      RaiseLastOSError( LastError );
  end;
end;
System Error Codes (0-499)

Bei einem
Delphi-Quellcode:
ERROR_TOO_MANY_OPEN_FILES
kann man einfach keine Aussage darüber treffen, ob das Verzeichnis existiert oder nicht. Also entweder einen TriState (Ja, Nein, WeissDerGeier) zurückliefern oder eine Exception werfen.

Sir Rufo 14. Nov 2014 15:30

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von pelzig (Beitrag 1279840)
Mal ganz extrem dumm gefragt:

Wat gibbes rück?

Ist das letzte Zeichen des Rückgabewertes etwa ein Backslash?

MfG

Ja mit einer hübschen Schleife drumherum :shock:

Rückgabewert von
Delphi-Quellcode:
DirectoryExists
BOOLEAN
Rückgabewert von
Delphi-Quellcode:
GetFileAttributes
Cardinal
Rückgabewert von
Delphi-Quellcode:
GetLastError
Cardinal

Da ist nicht viel Raum für ein Backslash

Uwe Raabe 14. Nov 2014 15:32

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1279839)
Soso, und wenn dieser Fehler da ist, dann ist es trotzdem ein existierendes Verzeichnis und der Rückgabewert muss
Delphi-Quellcode:
true
sein?

Ich meine schon. Schließlich existiert ja die Root des Share. Ob ich da reinschreiben kann ist wieder eine andere Frage.

Zitat:

Zitat von Sir Rufo (Beitrag 1279839)
Kann ich nicht so wirklich glauben, denn
...
Aha, also ergibt das auch
Delphi-Quellcode:
false

Ich habe ja nicht behauptet, daß die Implementation korrekt ist :-D

Sinnigerweise verhält sich Windows (zumindest 8.1) in diesem Punkt gar nicht nach der Dokumentation. Auch mit einem Network-Share kommt kein INVALID_FILE_ATTRIBUTES zurück, so daß dieses Argument wohl nicht zieht.

Aber vom Prinzip hat der OT schon Recht: es ist einfach ungeschickt, auf die möglichen Fehler abzuprüfen, anstatt auf die möglichen Ausnahmen von den Fehlern. Die Exception bei einem unerwarteten Rückgabewert gehört natürlich auch zum guten Standard.

Sir Rufo 14. Nov 2014 15:36

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Hier mal die Rückgabewerte und den entsprechenden LastError
DirectoryResultLastError
\\FalseERROR_INVALID_NAME
\\serverFalseERROR_BAD_PATHNAME
\\server\FalseERROR_BAD_PATHNAME
\\server\notexistingFalseERROR_BAD_PATHNAME
\\server\existingTrue 

hathor 14. Nov 2014 15:44

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
An den TE:
Teste doch mal diesen Code aus XE2:
http://www.delphipraxis.net/1222644-post11.html

jensw_2000 14. Nov 2014 22:05

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1279845)
Zitat:

Zitat von Sir Rufo (Beitrag 1279839)
Soso, und wenn dieser Fehler da ist, dann ist es trotzdem ein existierendes Verzeichnis und der Rückgabewert muss
Delphi-Quellcode:
true
sein?

Ich meine schon. Schließlich existiert ja die Root des Share. Ob ich da reinschreiben kann ist wieder eine andere Frage.

Genau hier liegt der Hase im Pfeffer.
Die "Root des Shares" ist der Server bzw. die "DFS Farm", da kann man nie was hinschreiben. Es ist kein Ordner.
Das Share ist die Bezeichnung hinter dem Servernamen.

Also:
\\Server\ <<--- hier schreibt keiner was hin.
FileExists und DirectoryExists müssen fehlschlagen. Es kann auch kein "\\Server\." oder "\\Server\.." geben.

\\Server\Share\ <<--- hier schon (DirectoryExists muss klappen, wenn die Berechtigungen vorhanden sind)
\\Server\Share\SubDirectory\ <<--- da auch (DirectoryExists muss klappen, wenn die Berechtigungen vorhanden sind)
\\Server\Share\File <<--- hier ebenfalls (FileExists muss klappen, wenn die Berechtigungen vorhanden sind)
\\Server\Share\SubDirectory\File <<--- genau wie dort (FileExists muss klappen, wenn die Berechtigungen vorhanden sind)

Uwe Raabe 14. Nov 2014 22:56

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von jensw_2000 (Beitrag 1279864)
Das Share ist die Bezeichnung hinter dem Servernamen.

Das ist aber auch genau das, was ich aus der MSDN-Doku unter network share verstanden habe.

Sir Rufo 15. Nov 2014 00:28

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1279866)
Zitat:

Zitat von jensw_2000 (Beitrag 1279864)
Das Share ist die Bezeichnung hinter dem Servernamen.

Das ist aber auch genau das, was ich aus der MSDN-Doku unter network share verstanden habe.

Das will auch niemand bestreiten, allerdings ist die Frage ja auch ein ganz andere:
Zitat:

Soll
Delphi-Quellcode:
DirectoryExists( '\\Server' )
tatsächlich ein
Delphi-Quellcode:
true
zurückliefern?
Klarer Fall: Nein, denn das ist kein Verzeichnis!

Eigentlich wäre es noch zu überlegen, ob hier nicht sogar eine Exception geworfen werden müsste, weil ja gar kein gültiger Verzeichnisname angegeben wurde, aber das verwirrt hier jetzt wohl mehr.

samso 15. Nov 2014 06:36

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Bei FileExists gibt/gab es ja eine ähnliche Abfrage. Dort hatte diese Abfrage den Sinn, im Fall einer gelockten Datei (z.b. ShareExclusiv) wieder zur alten Suche via FindFirst zurück zu fallen. Gibt es unter Windows die Möglichkeit ein Directory zu locken? Oder hat der Programmierer von DirectoryExists einfach zu viel Copy&Paste betrieben?

Sir Rufo 15. Nov 2014 10:31

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Nur so am Rande erwähnt, es gibt da z.B. den Fehler
Delphi-Quellcode:
ERROR_INVALID_PASSWORD
.

Angenommen es gibt ein Netzwerk-Device mit dem Namen
Delphi-Quellcode:
Server
und ich habe dort aber keine Berechtigung, dann liefert jede Abfrage
Delphi-Quellcode:
DirectoryExists( '\\Server\KomischesVerzeichnisDasEsAuchEhNichtGibt\' )
ganz stumpf ein
Delphi-Quellcode:
true
zurück.

Insgesamt muss man den hier auch den Kontext betrachten. So liefert auch eine Abfrage auf
Delphi-Quellcode:
\\.\COM1
oder
Delphi-Quellcode:
\\.\COM1\
ein
Delphi-Quellcode:
true
zurück (wenn es einen Com-Port COM1 gibt) und ein
Delphi-Quellcode:
\\.\COM5
oder
Delphi-Quellcode:
\\.\COM5\
liefert ein
Delphi-Quellcode:
false
wenn es den Com-Port eben nicht gibt.

Ja, ist das denn nun ein Verzeichnis oder nicht?
Will ich diese Funktion dazu gebrauchen können auf einen Com-Port zu prüfen?

hathor 15. Nov 2014 12:11

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Zitat:

Zitat von samso (Beitrag 1279877)
Gibt es unter Windows die Möglichkeit ein Directory zu locken?

http://msdn.microsoft.com/en-us/libr...vs.100%29.aspx

CCRDude 17. Nov 2014 10:33

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Vielen Dank für die zahlreichen Antworten!
Die haben mich auf die richtige Fährte gebracht...

Tatsächlich geht es auf den Rechnern, wo das Problem auftritt, um Netzwerk-Pfade, war mir erst gar nicht bewusst, da es um den "Start Menu\Programs"-Ordner geht.

Habe mir nun entsprechend auch ein Testprogramm geschrieben, dass mir zu diversen Pfaden die Rückgabewerte ausgibt, und damit eure Beschreibung nachvollzogen. Werde den entsprenden Code jetzt umstellen auf FindFirst, damit habe ich das Problem anderswo schonmal in den Griff bekommen (aus anderem Grund umgestellt damals) und dann mittelfristig wohl doch mal auf XE 7 umsteigen.

Sir Rufo 17. Nov 2014 11:15

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Auch mit XE7 wird das nicht besser.

Einzige Lösung: Schreibe dir eine eigene
Delphi-Quellcode:
DirectoryExists
Funktion, die sich genau so verhält, wie du das erwartest. Und das geht auch ohne
Delphi-Quellcode:
FindFirst
.

Wie du die umsetzt ist egal, solange die genau das macht, was du davon erwartest ;)

CCRDude 17. Nov 2014 11:29

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Mit XE 7 ist dieses Problem bereits behoben, habe ich ja direkt verglichen.

Wobei ich das Upgrade eher plane, weil diese Diskussion gezeigt hat, dass die RTL doch noch aktualisiert wird, nicht konkret für dieses Problem.

FindFirst war auch nur ein Platzhalter für eine wesenlich komplexere eigene Klasse, die Dateisysteminhalte ausliest und cacht (und nicht nur auf FindFirst, sondern auch Native-Zugriffen basiert und und ...). War nur an dieser Legacy-Code-Stelle noch nicht in Betrieb.

Sir Rufo 17. Nov 2014 12:30

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Mit XE7 sind aber nicht alle Probleme behoben (siehe
Delphi-Quellcode:
ERROR_INVALID_PASSWORD
).

Somit bleibt es dabei, dass du eine eigene Funktion erstellen musst, wenn diese robust laufen soll.

CCRDude 17. Nov 2014 12:31

AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
 
Genau, somit bleibt es dabei, dass ich ja schon geschrieben habe, dass ich e eine eigene komplexere Klasse für dieses Problem habe ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:48 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