![]() |
Delphi-Version: XE
Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Unter Delphi XE finde ich in der SysUtils.pas:
Delphi-Quellcode:
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.
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; 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. |
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 |
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Mal anders gefragt:
In welchen Situationen kann es dazu kommen, dass
Delphi-Quellcode:
und es trotzdem um ein existierendes Verzeichnis handelt?
GetFileAttributes(PChar(Directory)) = INVALID_FILE_ATTRIBUTES
Ich hätte jetzt mal pauschal vermutet: keine. Also könnte der Code wie folgt lauten
Delphi-Quellcode:
ansonsten sollten die den Rückgabewert ändern auf
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;
Delphi-Quellcode:
:mrgreen:
TDirectoryExistsResult = ( True, False, KnownByVulture );
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
Zitat:
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
Delphi-Quellcode:
sein?
true
Kann ich nicht so wirklich glauben, denn Zitat:
Delphi-Quellcode:
...
false
Also bei welcher Gelegenheit muss
Delphi-Quellcode:
ein
DirectoryExists
Delphi-Quellcode:
zurückliefern trotz dass wir bei
true
Delphi-Quellcode:
aks Rückgabe ein
GetFileAttributes(PChar(Directory))
Delphi-Quellcode:
bekommen?
INVALID_FILE_ATTRIBUTES
|
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 |
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; ![]() Bei einem
Delphi-Quellcode:
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.
ERROR_TOO_MANY_OPEN_FILES
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
Rückgabewert von
Delphi-Quellcode:
BOOLEAN
DirectoryExists
Rückgabewert von
Delphi-Quellcode:
Cardinal
GetFileAttributes
Rückgabewert von
Delphi-Quellcode:
Cardinal
GetLastError
Da ist nicht viel Raum für ein Backslash |
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
Zitat:
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. |
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Hier mal die Rückgabewerte und den entsprechenden LastError
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
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) |
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
|
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
Zitat:
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. |
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?
|
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:
und ich habe dort aber keine Berechtigung, dann liefert jede Abfrage
Server
Delphi-Quellcode:
ganz stumpf ein
DirectoryExists( '\\Server\KomischesVerzeichnisDasEsAuchEhNichtGibt\' )
Delphi-Quellcode:
zurück.
true
Insgesamt muss man den hier auch den Kontext betrachten. So liefert auch eine Abfrage auf
Delphi-Quellcode:
oder
\\.\COM1
Delphi-Quellcode:
ein
\\.\COM1\
Delphi-Quellcode:
zurück (wenn es einen Com-Port COM1 gibt) und ein
true
Delphi-Quellcode:
oder
\\.\COM5
Delphi-Quellcode:
liefert ein
\\.\COM5\
Delphi-Quellcode:
wenn es den Com-Port eben nicht gibt.
false
Ja, ist das denn nun ein Verzeichnis oder nicht? Will ich diese Funktion dazu gebrauchen können auf einen Com-Port zu prüfen? |
AW: Fehleranfääliges DirectoryExists auch in Delphi > XE 1?
Zitat:
![]() |
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. |
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:
Funktion, die sich genau so verhält, wie du das erwartest. Und das geht auch ohne
DirectoryExists
Delphi-Quellcode:
.
FindFirst
Wie du die umsetzt ist egal, solange die genau das macht, was du davon erwartest ;) |
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. |
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. |
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 07:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz