diff --git a/CMakeLists.txt b/CMakeLists.txt index e82cf99..91f9be2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") target_link_libraries(platform_folders PRIVATE "${_CoreServices_FRAMEWORK}") endif() +# Windows 7 or newer +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x0601 -DWINVER=0x0601") + # Cmake's find_package search path is different based on the system # See https://cmake.org/cmake/help/latest/command/find_package.html for the list if(CMAKE_SYSTEM_NAME STREQUAL "Windows") @@ -123,4 +126,6 @@ include(CTest) # BUILD_TESTING is defined (default ON) in CTest if(BUILD_TESTING) add_subdirectory(test) + add_executable(platform_folders_sample platform_folders.cpp) + target_link_libraries(platform_folders_sample PRIVATE platform_folders) endif() diff --git a/platform_folders.cpp b/platform_folders.cpp index 8741eaf..b1b34c9 100644 --- a/platform_folders.cpp +++ b/platform_folders.cpp @@ -36,8 +36,9 @@ int main() { std::cout << "Pictures: " << sago::getPicturesFolder() << "\n"; std::cout << "Music: " << sago::getMusicFolder() << "\n"; std::cout << "Video: " << sago::getVideoFolder() << "\n"; - std::cout << "Download: " << sago::getDownloadFolder1() << "\n"; + std::cout << "Download: " << sago::getDownloadFolder() << "\n"; std::cout << "Save Games 1: " << sago::getSaveGamesFolder1() << "\n"; + std::cout << "Save Games 2: " << sago::getSaveGamesFolder2() << "\n"; std::vector extraData; sago::appendAdditionalDataDirectories(extraData); for (size_t i=0; i < extraData.size(); ++i) { diff --git a/sago/platform_folders.cpp b/sago/platform_folders.cpp index c7b1709..1a4faff 100644 --- a/sago/platform_folders.cpp +++ b/sago/platform_folders.cpp @@ -64,25 +64,37 @@ static std::string win32_utf16_to_utf8(const wchar_t* wstr) { return res; } -static std::string GetWindowsFolder(int folderId, const char* errorMsg) { - wchar_t szPath[MAX_PATH]; - szPath[0] = 0; - if ( !SUCCEEDED( SHGetFolderPathW( nullptr, folderId, nullptr, 0, szPath ) ) ) { +class FreeCoTaskMemory { + LPWSTR pointer = NULL; +public: + FreeCoTaskMemory(LPWSTR pointer) : pointer(pointer) {}; + ~FreeCoTaskMemory() { + CoTaskMemFree(pointer); + } +}; + +static std::string GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, const char* errorMsg) { + LPWSTR wszPath = NULL; + HRESULT hr; + hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath); + FreeCoTaskMemory scopeBoundMemory(wszPath); + + if (!SUCCEEDED(hr)) { throw std::runtime_error(errorMsg); } - return win32_utf16_to_utf8(szPath); + return win32_utf16_to_utf8(wszPath); } static std::string GetAppData() { - return GetWindowsFolder(CSIDL_APPDATA, "RoamingAppData could not be found"); + return GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData could not be found"); } static std::string GetAppDataCommon() { - return GetWindowsFolder(CSIDL_COMMON_APPDATA, "Common appdata could not be found"); + return GetKnownWindowsFolder(FOLDERID_ProgramData, "ProgramData could not be found"); } static std::string GetAppDataLocal() { - return GetWindowsFolder(CSIDL_LOCAL_APPDATA, "LocalAppData could not be found"); + return GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData could not be found"); } #elif defined(__APPLE__) #include @@ -291,7 +303,7 @@ PlatformFolders::~PlatformFolders() { std::string PlatformFolders::getDocumentsFolder() const { #ifdef _WIN32 - return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder"); + return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder"); #elif defined(__APPLE__) return GetMacFolder(kDocumentsFolderType, "Failed to find Documents Folder"); #else @@ -301,7 +313,7 @@ std::string PlatformFolders::getDocumentsFolder() const { std::string PlatformFolders::getDesktopFolder() const { #ifdef _WIN32 - return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find Desktop folder"); + return GetKnownWindowsFolder(FOLDERID_Desktop, "Failed to find Desktop folder"); #elif defined(__APPLE__) return GetMacFolder(kDesktopFolderType, "Failed to find Desktop folder"); #else @@ -311,7 +323,7 @@ std::string PlatformFolders::getDesktopFolder() const { std::string PlatformFolders::getPicturesFolder() const { #ifdef _WIN32 - return GetWindowsFolder(CSIDL_MYPICTURES, "Failed to find My Pictures folder"); + return GetKnownWindowsFolder(FOLDERID_Pictures, "Failed to find My Pictures folder"); #elif defined(__APPLE__) return GetMacFolder(kPictureDocumentsFolderType, "Failed to find Picture folder"); #else @@ -321,8 +333,7 @@ std::string PlatformFolders::getPicturesFolder() const { std::string PlatformFolders::getDownloadFolder1() const { #ifdef _WIN32 - //Pre Vista. Files was downloaded to the desktop - return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find My Downloads (Desktop) folder"); + return GetKnownWindowsFolder(FOLDERID_Downloads, "Failed to find My Downloads folder"); #elif defined(__APPLE__) return GetMacFolder(kDownloadsFolderType, "Failed to find Download folder"); #else @@ -332,7 +343,7 @@ std::string PlatformFolders::getDownloadFolder1() const { std::string PlatformFolders::getMusicFolder() const { #ifdef _WIN32 - return GetWindowsFolder(CSIDL_MYMUSIC, "Failed to find My Music folder"); + return GetKnownWindowsFolder(FOLDERID_Music, "Failed to find My Music folder"); #elif defined(__APPLE__) return GetMacFolder(kMusicDocumentsFolderType, "Failed to find Music folder"); #else @@ -342,7 +353,7 @@ std::string PlatformFolders::getMusicFolder() const { std::string PlatformFolders::getVideoFolder() const { #ifdef _WIN32 - return GetWindowsFolder(CSIDL_MYVIDEO, "Failed to find My Video folder"); + return GetKnownWindowsFolder(FOLDERID_Videos, "Failed to find My Video folder"); #elif defined(__APPLE__) return GetMacFolder(kMovieDocumentsFolderType, "Failed to find Movie folder"); #else @@ -354,7 +365,7 @@ std::string PlatformFolders::getSaveGamesFolder1() const { #ifdef _WIN32 //A dedicated Save Games folder was not introduced until Vista. For XP and older save games are most often saved in a normal folder named "My Games". //Data that should not be user accessible should be placed under GetDataHome() instead - return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder")+"\\My Games"; + return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder")+"\\My Games"; #elif defined(__APPLE__) return GetMacFolder(kApplicationSupportFolderType, "Failed to find Application Support Folder"); #else @@ -370,10 +381,14 @@ std::string getDocumentsFolder() { return PlatformFolders().getDocumentsFolder(); } -std::string getDownloadFolder1() { +std::string getDownloadFolder() { return PlatformFolders().getDownloadFolder1(); } +std::string getDownloadFolder1() { + return getDownloadFolder(); +} + std::string getPicturesFolder() { return PlatformFolders().getPicturesFolder(); } @@ -390,5 +405,12 @@ std::string getSaveGamesFolder1() { return PlatformFolders().getSaveGamesFolder1(); } +std::string getSaveGamesFolder2() { +#ifdef _WIN32 + return GetKnownWindowsFolder(FOLDERID_SavedGames, "Failed to find Saved Games folder"); +#else + return PlatformFolders().getSaveGamesFolder1(); +#endif +} } //namespace sago diff --git a/sago/platform_folders.h b/sago/platform_folders.h index 193fa4d..6102c81 100644 --- a/sago/platform_folders.h +++ b/sago/platform_folders.h @@ -124,7 +124,13 @@ std::string getDocumentsFolder(); /** * The folder where files are downloaded. - * @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder. + * @return Absolute path to the folder where files are downloaded to. + */ +std::string getDownloadFolder(); + +/** + * The folder where files are downloaded. + * @note This is provided for backward compatibility. Use getDownloadFolder instead. * @return Absolute path to the folder where files are downloaded to. */ std::string getDownloadFolder1(); @@ -148,7 +154,7 @@ std::string getMusicFolder(); std::string getVideoFolder(); /** - * The base folder for storring saved games. + * A base folder for storring saved games. * You must add the program name to it like this: * @code{.cpp} * string saved_games_folder = sago::getSaveGamesFolder1()+"/My Program Name/"; @@ -159,6 +165,20 @@ std::string getVideoFolder(); */ std::string getSaveGamesFolder1(); +/** + * A base folder for storring saved games. + * You must add the program name to it like this: + * @code{.cpp} + * string saved_games_folder = sago::getSaveGamesFolder2()+"/My Program Name/"; + * @endcode + * @note PlatformFolders provide different folders to for saved games as not all operating systems has support for Saved Games yet. + * It is recommended to pick the highest number (currently getSaveGamesFolder2) at the time your product enters production and stick with it + * @note Windows: This returns the "Saved Games" folder. This folder exist in Vista and later + * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome() + * @return The folder base folder for storring save games. + */ +std::string getSaveGamesFolder2(); + #ifndef DOXYGEN_SHOULD_SKIP_THIS /**