Получение пути к временной папке пользователя в Windows

Как я могу получить путь к временной папке пользователя в C++? Моя программа должна работать в Windows Vista и XP, и у них разные временные пути. Как я могу получить это без потери совместимости?

10 ответов

Решение

Есть ли причина, по которой вы не можете использовать Win32 GetTempPath API?

Этот API доступен начиная с W2K и, следовательно, будет доступен для всех перечисленных целей.

Начиная с C++ 17 вы можете использовать кроссплатформенную функцию:std::filesystem::temp_directory_path()

https://en.cppreference.com/w/cpp/filesystem/temp_directory_path

Функция GetTempPath извлекает путь к каталогу, предназначенному для временных файлов. Эта функция заменяет функцию GetTempDrive.

DWORD GetTempPath(

DWORD nBufferLength, // size, in characters, of the buffer 
LPTSTR lpBuffer // address of buffer for temp. path 
); 

параметры

nBufferLength

Определяет размер в символах строкового буфера, идентифицируемого lpBuffer.

lpBuffer

Указывает на строковый буфер, который получает строку с нулевым символом в конце, указывающую путь к временному файлу.

Возвращаемые значения

Если функция завершается успешно, возвращаемое значение представляет собой длину в символах строки, скопированной в lpBuffer, не включая завершающий нулевой символ. Если возвращаемое значение больше, чем nBufferLength, возвращаемое значение является размером буфера, необходимого для хранения пути. Если функция не работает, возвращаемое значение равно нулю. Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.

замечания

Функция GetTempPath получает временный путь к файлу следующим образом:

  1. Путь, указанный в переменной среды TMP.
  2. Путь, указанный переменной среды TEMP, если TMP не определен.
  3. Текущий каталог, если и TMP, и TEMP не определены.

В Windows 10 это может быть непросто, поскольку значение временного пути зависит не только от того, какой он установлен по умолчанию, но и от того, какое приложение вы используете. Так что это зависит от того, что конкретно вам нужно.

[Общая область] TEMP в пользовательских данных локального приложения

#include <Windows.h>
#include <Shlobj.h>
#include <Shlobj_core.h>
#include <string_view>
// ...
static void GetUserLocalTempPath(std::wstring& input_parameter) {
    static constexpr std::wstring_view temp_label = L"\\Temp\\";
    HWND folder_handle = { 0 };
    WCHAR temp_path[MAX_PATH];
    auto get_folder = SHGetFolderPath( 
        folder_handle, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, temp_path
    );
    if (get_folder == S_OK) {
        input_parameter = static_cast<const wchar_t*>(temp_path);
        input_parameter.append(temp_label);
        CloseHandle(folder_handle);
    }
}

GetUserLocalTempPath скорее всего вернет полное имя вместо короткого.
Кроме того, если что-то работает, оно делает это как СИСТЕМА вместо зарегистрированного пользователя, а не возвращает %USERPROFILE%\AppData\Local\Temp, он вернет что-то более похожее, C:\Windows\System32\config\systemprofile\AppData\Local\Temp

Temp для любой переменной среды TEMP

#include <Windows.h>
// ...
static void GetEnvTempPath(std::wstring& input_parameter) {
    wchar_t * env_var_buffer = nullptr;
    std::size_t size = 0;
    if ( _wdupenv_s(&env_var_buffer, &size, L"TEMP") == 0 &&
         env_var_buffer != nullptr) {
        input_parameter = static_cast<const wchar_t*>(env_var_buffer);
    }
}

[Надежный] Temp для всего, что доступно вашему приложению (C++17)

#include <filesystem>
// ...
auto temp_path = std::filesystem::temporary_directory_path().wstring();

temporary_directory_pathскорее всего вернет короткое имя вместо полного имени.


Вы, вероятно, получите максимальную отдачу от первой и последней функций в зависимости от ваших потребностей. Если вы имеете дело с приложениями AppContainer, перейдите на последнее, предоставленное <filesystem>, Это должно вернуть что-то вроде,

C:\Users\user name\AppData\Local\Packages\{APP's GUID}\AC\Temp

Функция GetTempPath вернет путь с коротким именем, например: C:\Users\WDKREM~1\AppData\Local\Temp\,

Чтобы получить полное временное имя пути, используйте впоследствии GetLongPathName.

#include <iostream>
#include <string>

int main(int argc, char* argv[]){

    std::cout << getenv("TEMP") << std::endl;

    return 0;
}

Используйте GetTempPath(), чтобы получить путь к каталогу, предназначенному для временных файлов.

wstring TempPath;
wchar_t wcharPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, wcharPath))
   TempPath = wcharPath;

Как отметил VictorV, GetTempPath возвращает свернутый путь. Вам нужно будет использовать оба GetTempPath а также GetLongPathName макросы, чтобы получить полностью расширенный путь.

std::vector<TCHAR> collapsed_path;
TCHAR copied = MAX_PATH;
while ( true )
{
    collapsed_path.resize( copied );
    copied = GetTempPath( collapsed_path.size( ), collapsed_path.data( ) );
    if ( copied == 0 ) 
        throw std::exception( "An error occurred while creating temporary path" );
    else if ( copied < collapsed_path.size( ) ) break;
}

std::vector<TCHAR> full_path;
copied = MAX_PATH;
while ( true )
{
    full_path.resize( copied );
    copied = GetLongPathName( collapsed_path.data( ), full_path.data( ), full_path.size( ) );
    if ( copied == 0 ) 
        throw std::exception( "An error occurred while creating temporary path" );
    else if ( copied < full_path.size( ) ) break;
}
std::string path( std::begin( full_path ), std::end( full_path ) );

GetTempPath не будет работать в Vista, если у пользователей нет прав администратора. Я столкнулся с этой проблемой прямо сейчас с одним из моих приложений.

используйте константу по умолчанию. Пример :

      wchar_t defaultTempPath[MAX_PATH];
GetTempPathW(MAX_PATH, defaultTempPath);

// in case you return the result in a string function
return wstring(defaultTempPath);

В C++ — константа, представляющая максимальную длину пути к файлу в операционной системе Windows. Он определяется как 260 символов, включая завершающий нулевой символ.

The MAX_PATHконстанта используется в различныхWin32 APIфункции и структуры, работающие с путями к файлам . Важно отметить, что это ограничение применяется конкретно к Windows API и может быть неприменимо к другим платформам или файловым системам.

Другие вопросы по тегам