Поиск папки пользователя приложения "true" для Windows?
У меня есть приложение Delphi 6, которое, как и большинство приложений Windows, считывает/записывает данные в папку "данные локальных приложений" пользователя. Я использую код ниже, чтобы определить эту папку. До сих пор этот код работал для большинства моих пользователей. Я столкнулся с пользователем, чьи локальные данные приложения не находятся в ожидаемой папке:
C:\Users\Bob\AppData\Roaming\
Обычно локальная папка данных приложения разрешает:
C:\Documents and Settings\Bob\Application Data\
Что странно в этой конкретной ситуации, так это то, что несколько ключей реестра, обычно встречающихся в HKEY_LOCAL_MACHINE, фактически находятся в HKEY_CURRENT_USER. Они работают в Windows 7.
Из-за отсутствия лучшего слова, есть ли способ получить "истинные" данные приложения для пользователя, чтобы я мог лучше ориентироваться в этой ситуации? Если разумно выбирать между специальными папками CSIDL_APPDATA, CSIDL_COMMON_APPDATA и CSIDL_LOCAL_APPDATA, какова логика для этого? Как вы можете сказать, я ищу универсальную функцию, которая может искоренить правильную папку данных приложения независимо от версии Windows, на которой выполняется пользователь, или их конкретной конфигурации ПК.
Я нашел этот пост, который, кажется, имеет ответ, но он использует функцию из библиотеки .NET, и я использую Delphi 6. Если это решение отвечает на мой вопрос, может кто-то сказать мне быстрый способ его репликации Delphi:
Как я могу получить путь к "данным приложения" текущего пользователя? папка?
// Function to get the app data special folder.
function GetAppdataFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_APPDATA);
end;
Ответы
Ответ 1
Код .net, на который вы ссылаетесь, использует Environment.SpecialFolder.ApplicationData
, который точно совпадает с CSIDL_APPDATA
. Таким образом, ваш код уже эквивалентен коду .net, к которому вы привязываетесь. И они оба относятся к тому же местоположению, что и FOLDERID_RoamingAppData
.
Взгляните на документацию для FOLDERID_RoamingAppData
. В нем говорится:
Default Path %APPDATA% (%USERPROFILE%\AppData\Roaming)
Legacy Default Path %APPDATA% (%USERPROFILE%\Application Data)
"Путь по умолчанию" - это то, что вы увидите в Vista или позже. "Legacy Path" - это то, что вы видите на XP.
Различное поведение, которое вы наблюдали, представляет собой не что иное, как ожидаемое различие между XP и Vista/7/8.
На моей машине с Windows,
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
оценивается как
C:\Users\heff\AppData\Roaming
Другими словами, ваш код уже поступает правильно. Вам вообще не нужно вносить какие-либо изменения в это. Продолжайте использовать GetSpecialFolderLocation(CSIDL_APPDATA)
.
Что странно в этой конкретной ситуации, так это то, что несколько ключей реестра, обычно встречающихся в HKEY_LOCAL_MACHINE, фактически находятся в HKEY_CURRENT_USER.
Это не редкость. Довольно часто приложения настраивают параметры по умолчанию в HKLM
, а затем копируют их в HKCU
, когда приложение запускается в первый раз. Не зная более подробных сведений о параметрах, о которых идет речь, сложно комментировать этот аспект вашего вопроса.
Ответ 2
Вы можете использовать это (обертка). Вам нужно добавить ShlApi в свой раздел uses. Передайте его CSIDL_APPDATA
точно так же, как ваш пример выше. Список различных значений CSIDL_
см. В странице MSDN здесь
function GetShellFolder(CSIDLFolder : integer) : string;
begin
SetLength(Result, MAX_PATH);
SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, false);
SetLength(Result, StrLen(PChar(Result)));
if (Result <> '') then
Result := IncludeTrailingBackslash(Result);
end;
Если вы поддерживаете более раннюю версию Windows (XP и ниже), которая отображается в вашем тексте, вы можете вместо этого использовать SHGetFolderPath
:
function GetFolderPath(Wnd: HWnd; CSIDLFolder: Integer): string;
begin
SetLength(Result, MAX_PATH);
Result := SHGetFolderPath(Wnd, CSIDLFolder, nil, 0, PChar(Result);
SetLength(Result, StrLen(PChar(Result)));
end;
Если вы только поддерживаете Vista и выше, вы должны использовать SHGetKnownFolderPath
и передать ей KNOWNFOLDERID
.
Что касается проблемы с реестром, Windows Vista и 7 гораздо более ограничивают места, в которые может писать пользователь, не являющийся администратором, и одно из мест, которое происходит в HKLM и HKCR. Многие элементы, которые раньше находились в этих ульях, теперь находятся в HKCU или там отражены.
Ответ 3
Если разумно выбирать между специальными папками CSIDL_APPDATA, CSIDL_COMMON_APPDATA и CSIDL_LOCAL_APPDATA, какова логика для этого?
Да, это всего лишь вопрос. Ваш код уже работает как ожидалось.
CSIDL_APPDATA
(FOLDERID_RoamingAppData
) - это данные, которые доступны для текущей учетной записи пользователя вызывающего потока (которая может быть выдана под себя) на нескольких машинах (данные "роуминга" "hense" ).
CSIDL_LOCAL_APPDATA
(FOLDERID_LocalAppData
) предназначен для данных, доступных для текущей учетной записи пользователя вызывающего потока только на локальной машине (hense "локальные" данные).
CSIDL_COMMON_APPDATA
(FOLDERID_ProgramData
) предназначен для данных, доступных для любой учетной записи пользователя только на локальном компьютере (не "роуминг" ).