From 12ac98a5375f38a190925ef59bc923318a37fd0f Mon Sep 17 00:00:00 2001 From: Thorbjørn Lindeijer Date: Thu, 28 Mar 2024 07:34:25 -0700 Subject: Windows: Modernize getSpecialFolderLocation Ported from CSIDL to newer FOLDERID API and used wcstombs_s to convert the returned path to a multi-byte string. Fixes issues when the Windows username contains special characters. --- src/client.cpp | 6 ++--- src/utils/specialfolder.cpp | 55 ++++++++++++++++++++++----------------------- src/utils/specialfolder.h | 4 ++-- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 63452112..abd426ce 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1116,7 +1116,7 @@ void Client::initHomeDir() mLocalDataDir = PHYSFS_getUserDir(); mLocalDataDir += "/config/data/Mana"; #elif defined _WIN32 - mLocalDataDir = getSpecialFolderLocation(CSIDL_LOCAL_APPDATA); + mLocalDataDir = getSpecialFolderLocation(FOLDERID_LocalAppData); if (mLocalDataDir.empty()) mLocalDataDir = PHYSFS_getUserDir(); mLocalDataDir += "/Mana"; @@ -1281,9 +1281,9 @@ void Client::initScreenshotDir() else if (mScreenshotDir.empty()) { #ifdef _WIN32 - mScreenshotDir = getSpecialFolderLocation(CSIDL_MYPICTURES); + mScreenshotDir = getSpecialFolderLocation(FOLDERID_Pictures); if (mScreenshotDir.empty()) - mScreenshotDir = getSpecialFolderLocation(CSIDL_DESKTOP); + mScreenshotDir = getSpecialFolderLocation(FOLDERID_Desktop); #else mScreenshotDir = std::string(PHYSFS_getUserDir()) + "Desktop"; #endif diff --git a/src/utils/specialfolder.cpp b/src/utils/specialfolder.cpp index bd3e1bca..c351ba1a 100644 --- a/src/utils/specialfolder.cpp +++ b/src/utils/specialfolder.cpp @@ -1,6 +1,6 @@ /* * The Mana Client - * Copyright (C) 2010-2012 The Mana Developers + * Copyright (C) 2010-2024 The Mana Developers * * This file is part of The Mana Client. * @@ -21,6 +21,7 @@ #ifdef _WIN32 #include "specialfolder.h" #include +#include #ifdef SPECIALFOLDERLOCATION_TEST // compile with -DSPECIALFOLDERLOCATION_TEST to get a standalone @@ -29,49 +30,47 @@ #endif /* - * Retrieve the pathname of special folders on win32, or an empty string - * on error / if the folder does not exist. - * See http://msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx for - * a list of folder ids + * Retrieve the pathname of special folders on Windows, or an empty string + * on error. + * + * See https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid + * for a list of folder IDs. */ -std::string getSpecialFolderLocation(int folderId) +std::string getSpecialFolderLocation(const KNOWNFOLDERID &folderId) { std::string ret; - LPITEMIDLIST pItemIdList; - LPMALLOC pMalloc; - char szPath[MAX_PATH]; - - // get the item ID list for folderId - HRESULT hr = SHGetSpecialFolderLocation(NULL, folderId, &pItemIdList); - if (hr != S_OK) - return ret; + PWSTR widePath = 0; - // convert the ID list into a file system path - if (SHGetPathFromIDList(pItemIdList, szPath) == FALSE) - return ret; + HRESULT hr = SHGetKnownFolderPath(folderId, 0, NULL, &widePath); + if (hr == S_OK) + { + // determine needed bytes + size_t len; + if (wcstombs_s(&len, nullptr, 0, widePath, 0) == 0) + { + ret.resize(len - 1); // subtract null character + if (wcstombs_s(nullptr, ret.data(), len, widePath, len - 1) != 0) + ret.clear(); + } + } - // get the IMalloc pointer and free all resources we used - hr = SHGetMalloc(&pMalloc); - pMalloc->Free(pItemIdList); - pMalloc->Release(); + CoTaskMemFree(widePath); - ret = szPath; return ret; } #ifdef SPECIALFOLDERLOCATION_TEST int main() { - std::cout << "APPDATA " << getSpecialFolderLocation(CSIDL_APPDATA) + std::cout << "RoamingAppData " << getSpecialFolderLocation(FOLDERID_RoamingAppData) << std::endl; - std::cout << "DESKTOP " << getSpecialFolderLocation(CSIDL_DESKTOP) + std::cout << "Desktop " << getSpecialFolderLocation(FOLDERID_Desktop) << std::endl; - std::cout << "LOCAL_APPDATA " - << getSpecialFolderLocation(CSIDL_LOCAL_APPDATA) + std::cout << "LocalAppData " << getSpecialFolderLocation(FOLDERID_LocalAppData) << std::endl; - std::cout << "MYPICTURES " << getSpecialFolderLocation(CSIDL_MYPICTURES) + std::cout << "Pictures " << getSpecialFolderLocation(FOLDERID_Pictures) << std::endl; - std::cout << "PERSONAL " << getSpecialFolderLocation(CSIDL_PERSONAL) + std::cout << "Documents " << getSpecialFolderLocation(FOLDERID_Documents) << std::endl; } #endif diff --git a/src/utils/specialfolder.h b/src/utils/specialfolder.h index 411752a2..8570d009 100644 --- a/src/utils/specialfolder.h +++ b/src/utils/specialfolder.h @@ -1,6 +1,6 @@ /* * The Mana Client - * Copyright (C) 2010-2012 The Mana Developers + * Copyright (C) 2010-2024 The Mana Developers * * This file is part of The Mana Client. * @@ -24,7 +24,7 @@ #ifdef _WIN32 #include #include -std::string getSpecialFolderLocation(int folderId); +std::string getSpecialFolderLocation(const KNOWNFOLDERID &folderId); #endif #endif -- cgit v1.2.3-70-g09d2