Что может привести к тому, что SHGetFolderLocation вернет false с Lasterror, установленным в 59? - PullRequest
0 голосов
/ 16 мая 2019

У меня есть приложение, которое иногда не может получить путь к папке AppData.

Ситуация, похоже, возникает только на нашей ферме серверов Citrix, а не для каждого пользователя и не всегда (я почти не смог ее воспроизвести).

Проблема проявляется следующим образом:

SHGetFolderLocation называется так:

 Value := SHGetFolderLocation (0, CLSID, 0, 0, pidl);
 try
   case Value of
     S_OK:
     begin
       if not ShGetPathfromIDList(pidl, Path) then
         RaiseLastOSError();
       Result := trim(string(Path));
       break;
     end;
   else
     RaiseLastOSError();
   end;
 finally
   CoTaskMemFree(pidl);
 end;

(CLSID установлен на CSIDL_APPDATA, который определяется как 0x001a)

В соответствии с трассировкой стека мы видим, что SHGetFolderLocation возвращает false, вызывая вызов RaiseLastOSError, который указывает, что последний код ошибки был 59:

System Error. Code: 59. An unexpected network error occurred

Я ломаю голову, пытаясь выяснить, как я могу получить такое сообщение об ошибке: даже если возникла проблема с сетью, я не вижу причин, по которым SHGetFolderLocation может быть затронуто этим.

Есть предложения?

1 Ответ

2 голосов
/ 16 мая 2019

SHGetFolderLocation() и SHGetPathfromIDList() не сообщают коды ошибок через GetLastError(), поэтому вы не можете использовать RaiseLastOSError() в этой ситуации.

SHGetFolderLocation() возвращает значение HRESULT.Вы можете передать это значение в функцию OleCheck() RTL, которая вызовет исключение, если значение HRESULT представляет ошибку.

К сожалению, SHGetPathfromIDList() вообще не сообщает коды ошибок, так что если выЕсли вы хотите вызвать исключение в случае сбоя, вы должны вызвать собственное исключение вручную.

Вы не должны вызывать CoTaskMemFree(), если SHGetFolderLocation() не вернет S_OK, так как это единственное условие, когда ваш pidl обновляется, чтобы указывать на выделенную память.Любое другое возвращаемое значение установит вместо указателя pidl значение nil.

Попробуйте это:

OleCheck(SHGetFolderLocation(0, CLSID, 0, 0, pidl));
try
  if not SHGetPathFromIDList(pidl, Path) then
    raise Exception.Create('Cannot get filesystem path from PIDL');
  Result := string(Path);
finally
  CoTaskMemFree(pidl);
end;

Что можно значительно упростить, просто взамен SHGetFolderPath():

OleCheck(SHGetFolderPath(0, CSIDL, 0, SHGFP_TYPE_CURRENT, Path));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...