Функция delphi directoryexists нечетное поведение для подключенных к сети устройств

В delphi XE, когда я вызываю функцию SysUtils DirectoryExists со следующим вводом

'А:\блабла\'

где Y — единица, отображенная в сети, она корректно возвращает false, поскольку blabla не существует.

Но когда я звоню со следующим вводом

'Д:\блабла\Д:\бла'

он возвращает истину.

Документация плохая, и я нигде не нашел в Интернете людей с такой же проблемой.

может быть у кого-то здесь уже была эта проблема, или знаете, что происходит?


person dmd_anfini    schedule 01.03.2013    source источник


Ответы (2)


Похоже, ошибка в реализации функции DirectoryExists.

Это соответствующий код этой функции

function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
{$IFDEF MSWINDOWS}
var
  Code: Cardinal;
  Handle: THandle;
  LastError: Cardinal;
begin
  Result := False;
  Code := GetFileAttributes(PChar(Directory));

  if Code <> INVALID_FILE_ATTRIBUTES then
  begin
    ...
    //more code
    ...
  end
  else
  begin
    LastError := GetLastError;
    Result := (LastError <> ERROR_FILE_NOT_FOUND) and
      (LastError <> ERROR_PATH_NOT_FOUND) and
      (LastError <> ERROR_INVALID_NAME) and
      (LastError <> ERROR_BAD_NETPATH);
  end;
end;
{$ENDIF MSWINDOWS}

Как видите, GetFileAttributes< /a> вызов функции завершился неудачно, результат GetLastError сравнивается с набором возможных значений. но в вашем случае передача недопустимого пути вернет ERROR_BAD_PATHNAME (161), поэтому функция возвращает True.

person RRUZ    schedule 01.03.2013
comment
+1. Это было исправлено в XE3 согласно быстрому тесту с использованием того же пути, что и в исходном вопросе. Однако я не знаю, в какой версии было сделано первое исправление; Я бы заподозрил XE2 из-за того, что там была XPlatform. - person Ken White; 02.03.2013
comment
@KenWhite, возможно, ошибка была исправлена ​​в XE3 upd1, потому что в XE3 она все еще присутствует. - person RRUZ; 02.03.2013
comment
Код выглядит так же, но на самом деле запуск теста возвращает False, как и должно быть. Я не просматривал код, чтобы увидеть, что изменилось в поведении; Я просто добавил быструю строку в консольное приложение, которое использовал для чего-то другого, и запустил его. - person Ken White; 02.03.2013
comment
В XE3 up1 код также проверяет ERROR_NOT_READY. Но когда я запускаю код, я получаю LastError из ERROR_INVALID_NAME или ERROR_PATH_NOT_FOUND, если Y: не отображается. Я не видел ERROR_BAD_PATHNAME. Какую ОС вы используете @RRUZ? Кажется, что должен быть представлен отчет о контроле качества, как только мы сможем локализовать эту ошибку. - person David Heffernan; 02.03.2013
comment
@DavidHeffernan, я использую Win7 x64, этот DirectoryExists('Y:\blabla\Y:\bla') возвращает true, а этот DirectoryExists('Y:\blabla') возвращает false. - person RRUZ; 02.03.2013
comment
Вин7 х64 тоже. Но я не могу получить ERROR_BAD_PATHNAME. Странный. - person David Heffernan; 02.03.2013
comment
@DavidHeffernan, вы создаете сетевой диск Y:, а затем тестируете код? - person RRUZ; 02.03.2013
comment
Нет, я использовал C: для своего теста. Должен ли это быть сетевой том? - person David Heffernan; 02.03.2013
comment
@DavidHeffernan, да, проблема может быть воспроизведена на сетевом диске. - person RRUZ; 02.03.2013
comment
Верно. Я только что воспроизвел на своем рабочем компьютере, используя один из подключенных сетевых томов. Вы хотите отправить отчет о контроле качества? - person David Heffernan; 02.03.2013

Ошибка все еще присутствует в XE8 (и, вероятно, в других версиях). Как указано выше RRUZ, это связано с реализациями SysUtils ОБИХ DirectoryExists() и TDirectory.Exists() .

Проблема заключается в том длинном списке «проверок», который предполагает, что они являются единственными действительными причинами того, что INVALID_FILE_ATTRIBUTES мог быть возвращен в контексте «существования» папки. Но причина, по которой мы вызываем эти подпрограммы, заключается в том, что почти всегда мы можем проверить, можем ли мы действительно использовать папку, о которой спрашиваем. Наличие INVALID_FILE_ATTRIBUTES почти всегда означает, что мы не можем. В любом случае, проводимые в настоящее время тесты не дают ощутимых результатов. Уже один этот факт делает это упражнение совершенно излишним, так как оно позволяет некоторым другим кодам неисправностей проскальзывать через сеть и устанавливать конечный результат в ИСТИНА, когда это не должно быть. Хотя я могу только представить, что изначально у этого безумия был какой-то метод, вроде «о, он существует, но может быть недействителен», он противоречит внутренней истине, что будущее может принести гораздо больше кодов, сгенерированных многими до сих пор. неизвестные файловые системы и/или аппаратное обеспечение: таким образом, в 99,9% случаев получение INVALID_FILE_ATTRIBUTES должно означать, что папка непригодна для использования, и поэтому нелогично разрешать TRUE быть возвращены после того, как это уже было установлено.

К сожалению, мы не можем знать, существует ли код, который опирается на настоящее поведение для определения «существующих путей с проблемами» — и в этом случае вызову подпрограммы в том виде, в каком она существует в настоящее время, должна предшествовать проверка синтаксиса пути: в противном случае он сказал бы, что путь, описанный с плохим синтаксисом, «существует», что является нонсенсом! После этого вы не сможете повторить GetLastError, так как ошибка уже будет устранена.

Таким образом, единственное лекарство — обернуть все вызовы Sysutils.DirectoryExists и (к сожалению, также) TDirectory.Exists кодом что устраняет проблему заранее. Например:

DirectoryUsable(const Directory: string; FollowLink: Boolean = True): Boolean;
begin
   Result := GetFileAttributes(PChar(Directory)) <> INVALID_FILE_ATTRIBUTES;
   if Result then Result := DirectoryExists( Directory, FollowLink );
end;

Либо так, либо вы проводите отдельную предварительную проверку всех «плохих» случаев, о которых вы знаете и которые пропустили Embarcadero, т. е. играете в ту же проигрышную игру, что и они. Ужасно, но вот.

Вы также можете изменить библиотеку SysUtils самостоятельно, чтобы добавить отсутствующие случаи, которые вам придется переделывать с каждым выпуском Delphi и для каждого нового случая, с которым вы сталкиваетесь. Вероятно, было бы лучше, если бы Embarcadero, наконец, «сжала зубы» и нашла лучшее решение этой проблемы. Возможно, используя другой параметр флага по умолчанию, который говорит «отклонить все недопустимые каталоги». Я бы также предположил, что по умолчанию это значение TRUE.

person Alex T    schedule 12.06.2017
comment
Я бы не стал здесь напрягаться. Единственный реальный способ (не говоря о плохо сцепленном пути в коде), когда эта функция может получить искаженную строку пути, - это ввод пользователя, который как таковой должен быть проверен или ограничен (если вы предоставите пользователю свободную руку для ввода, он может ввести что угодно ). Для проверки вы можете использовать, например. PathIsDirectory. - person Victoria; 13.06.2017
comment
Спасибо за подсказку о PathIsDirectory - я даже не знал об этой процедуре. И вы правы насчет проверки пользовательского ввода - это очень мучительно, учитывая все перестановки, которые может использовать пользователь, такие как вводные \\?\ и встроенные подстановки %token%. - person Alex T; 14.06.2017
comment
Я все еще не совсем убежден, что пользователь будет единственной причиной получения сценария, в котором у вас есть INVALID_FILE_ATTRIBUTES, в результате чего DirectoryExists возвращает TRUE, когда на самом деле этого не должно быть. Напрашивается вопрос, нужно ли после установления существования каталога всегда вызывать GetFileAttributes, чтобы убедиться, что он действительно пригоден для использования (что означает, что вы явно кодируете то, что уже находится в DirectoryExists, просто для обнаружения дальнейших случаев. Это все еще кажется мне неправильным. - person Alex T; 14.06.2017