From 3b21d328653f7a472b0f77ef1cc0c85766566b96 Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 6 Oct 2019 21:37:51 +0200 Subject: [PATCH 1/4] Remove MAX_PATH limit from: - GetTempFilenameForAtomicWrite - SetUserDirectory --- Source/Core/Common/FileUtil.cpp | 16 ++++++------ Source/Core/Common/FileUtil.h | 2 +- Source/Core/UICommon/UICommon.cpp | 41 ++++++++++++++++++++----------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 75118bffac..814d891c22 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -639,19 +639,21 @@ std::string CreateTempDir() #endif } -std::string GetTempFilenameForAtomicWrite(const std::string& path) +std::string GetTempFilenameForAtomicWrite(std::string path) { - std::string abs = path; #ifdef _WIN32 - TCHAR absbuf[MAX_PATH]; - if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != nullptr) - abs = TStrToUTF8(absbuf); + std::unique_ptr absbuf{ + _tfullpath(nullptr, UTF8ToTStr(path).c_str(), 0), std::free}; + if (absbuf != nullptr) + { + path = TStrToUTF8(absbuf.get()); + } #else char absbuf[PATH_MAX]; if (realpath(path.c_str(), absbuf) != nullptr) - abs = absbuf; + path = absbuf; #endif - return abs + ".xxx"; + return std::move(path) + ".xxx"; } #if defined(__APPLE__) diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 57e645c285..ff574dee5a 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -172,7 +172,7 @@ bool SetCurrentDir(const std::string& directory); std::string CreateTempDir(); // Get a filename that can hopefully be atomically renamed to the given path. -std::string GetTempFilenameForAtomicWrite(const std::string& path); +std::string GetTempFilenameForAtomicWrite(std::string path); // Gets a set user directory path // Don't call prior to setting the base user directory diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 935d07b043..878181bd9d 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -211,46 +211,57 @@ void SetUserDirectory(const std::string& custom_path) // -> Use GetExeDirectory()\User // Check our registry keys + // TODO: Maybe use WIL when it's available? HKEY hkey; DWORD local = 0; - TCHAR configPath[MAX_PATH] = {0}; + std::unique_ptr configPath; if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { DWORD size = 4; if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr, reinterpret_cast(&local), &size) != ERROR_SUCCESS) + { local = 0; + } + + size = 0; + RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, nullptr, &size); + configPath = std::make_unique(size / sizeof(TCHAR)); + if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, + reinterpret_cast(configPath.get()), &size) != ERROR_SUCCESS) + { + configPath.reset(); + } - size = MAX_PATH; - if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, - &size) != ERROR_SUCCESS) - configPath[0] = 0; RegCloseKey(hkey); } - local = local || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt"); + local = local != 0 || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt"); - // Get Program Files path in case we need it. - TCHAR my_documents[MAX_PATH]; - bool my_documents_found = SUCCEEDED( - SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); + // Get Documents path in case we need it. + // TODO: Maybe use WIL when it's available? + PWSTR my_documents = nullptr; + bool my_documents_found = + SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &my_documents)); if (local) // Case 1-2 user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - else if (configPath[0]) // Case 3 - user_path = TStrToUTF8(configPath); + else if (configPath) // Case 3 + user_path = TStrToUTF8(configPath.get()); else if (my_documents_found) // Case 4 user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP; else // Case 5 user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + CoTaskMemFree(my_documents); + // Prettify the path: it will be displayed in some places, we don't want a mix // of \ and /. - user_path = ReplaceAll(user_path, "\\", DIR_SEP); + user_path = ReplaceAll(std::move(user_path), "\\", DIR_SEP); // Make sure it ends in DIR_SEP. - if (*user_path.rbegin() != DIR_SEP_CHR) + if (user_path.back() != DIR_SEP_CHR) user_path += DIR_SEP; #else @@ -325,7 +336,7 @@ void SetUserDirectory(const std::string& custom_path) #endif } #endif - File::SetUserPath(D_USER_IDX, user_path); + File::SetUserPath(D_USER_IDX, std::move(user_path)); } void SaveWiimoteSources() From 689378b435c73b624cfdea8fe971db6b1d72c48e Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 6 Oct 2019 22:17:00 +0200 Subject: [PATCH 2/4] Move GetModuleName to Common This unifies GetModuleFileName calls between Dolphin and WinUpdater and allows to gracefully remove MAX_PATH limit from GetExePath --- Source/Core/Common/CommonFuncs.cpp | 23 +++++++++++++++++ Source/Core/Common/CommonFuncs.h | 4 +++ Source/Core/Common/CompatPatches.cpp | 29 ++++++++-------------- Source/Core/Common/FileUtil.cpp | 37 ++++++++++++++++------------ Source/Core/WinUpdater/Main.cpp | 23 +---------------- 5 files changed, 59 insertions(+), 57 deletions(-) diff --git a/Source/Core/Common/CommonFuncs.cpp b/Source/Core/Common/CommonFuncs.cpp index 7b109e81c5..a8c1abfea2 100644 --- a/Source/Core/Common/CommonFuncs.cpp +++ b/Source/Core/Common/CommonFuncs.cpp @@ -49,4 +49,27 @@ std::string GetLastErrorString() MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr); return std::string(error_message); } + +// Obtains a full path to the specified module. +std::optional GetModuleName(void* hInstance) +{ + DWORD max_size = 50; // Start with space for 50 characters and grow if needed + std::wstring name(max_size, L'\0'); + + DWORD size; + while ((size = GetModuleFileNameW(static_cast(hInstance), name.data(), max_size)) == + max_size && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + max_size *= 2; + name.resize(max_size); + } + + if (size == 0) + { + return std::nullopt; + } + name.resize(size); + return name; +} #endif diff --git a/Source/Core/Common/CommonFuncs.h b/Source/Core/Common/CommonFuncs.h index e276bea7ae..2378aab3db 100644 --- a/Source/Core/Common/CommonFuncs.h +++ b/Source/Core/Common/CommonFuncs.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -47,4 +48,7 @@ std::string LastStrerrorString(); // Wrapper function to get GetLastError() string. // This function might change the error code. std::string GetLastErrorString(); + +// Obtains a full path to the specified module. +std::optional GetModuleName(void* hInstance); #endif diff --git a/Source/Core/Common/CompatPatches.cpp b/Source/Core/Common/CompatPatches.cpp index 03963ccdee..e07028e9e4 100644 --- a/Source/Core/Common/CompatPatches.cpp +++ b/Source/Core/Common/CompatPatches.cpp @@ -4,12 +4,14 @@ #include #include +#include #include #include #include #include +#include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/LdrWatcher.h" #include "Common/StringUtil.h" @@ -162,37 +164,26 @@ struct Version } }; -static bool GetModulePath(const wchar_t* name, std::wstring* path) +static std::optional GetModulePath(const wchar_t* name) { auto module = GetModuleHandleW(name); if (module == nullptr) - return false; - DWORD path_len = MAX_PATH; -retry: - path->resize(path_len); - path_len = GetModuleFileNameW(module, const_cast(path->data()), - static_cast(path->size())); - if (!path_len) - return false; - auto error = GetLastError(); - if (error == ERROR_SUCCESS) - return true; - if (error == ERROR_INSUFFICIENT_BUFFER) - goto retry; - return false; + return std::nullopt; + + return GetModuleName(module); } static bool GetModuleVersion(const wchar_t* name, Version* version) { - std::wstring path; - if (!GetModulePath(name, &path)) + auto path = GetModulePath(name); + if (!path) return false; DWORD handle; - DWORD data_len = GetFileVersionInfoSizeW(path.c_str(), &handle); + DWORD data_len = GetFileVersionInfoSizeW(path->c_str(), &handle); if (!data_len) return false; std::vector block(data_len); - if (!GetFileVersionInfoW(path.c_str(), handle, data_len, block.data())) + if (!GetFileVersionInfoW(path->c_str(), handle, data_len, block.data())) return false; void* buf; UINT buf_len; diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 814d891c22..f0594cffcc 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -674,22 +674,26 @@ std::string GetBundleDirectory() std::string GetExePath() { - static std::string dolphin_path; - if (dolphin_path.empty()) - { + static const std::string dolphin_path = [] { + std::string result; #ifdef _WIN32 - TCHAR dolphin_exe_path[2048]; - TCHAR dolphin_exe_expanded_path[MAX_PATH]; - GetModuleFileName(nullptr, dolphin_exe_path, ARRAYSIZE(dolphin_exe_path)); - if (_tfullpath(dolphin_exe_expanded_path, dolphin_exe_path, - ARRAYSIZE(dolphin_exe_expanded_path)) != nullptr) - dolphin_path = TStrToUTF8(dolphin_exe_expanded_path); - else - dolphin_path = TStrToUTF8(dolphin_exe_path); + auto dolphin_exe_path = GetModuleName(nullptr); + if (dolphin_exe_path) + { + std::unique_ptr dolphin_exe_expanded_path{ + _tfullpath(nullptr, dolphin_exe_path->c_str(), 0), std::free}; + if (dolphin_exe_expanded_path) + { + result = TStrToUTF8(dolphin_exe_expanded_path.get()); + } + else + { + result = TStrToUTF8(*dolphin_exe_path); + } + } #elif defined(__APPLE__) - dolphin_path = GetBundleDirectory(); - dolphin_path = - dolphin_path.substr(0, dolphin_path.find_last_of("Dolphin.app/Contents/MacOS") + 1); + result = GetBundleDirectory(); + result = result.substr(0, result.find_last_of("Dolphin.app/Contents/MacOS") + 1); #else char dolphin_exe_path[PATH_MAX]; ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path)); @@ -698,9 +702,10 @@ std::string GetExePath() len = 0; } dolphin_exe_path[len] = '\0'; - dolphin_path = dolphin_exe_path; + result = dolphin_exe_path; #endif - } + return result; + }(); return dolphin_path; } diff --git a/Source/Core/WinUpdater/Main.cpp b/Source/Core/WinUpdater/Main.cpp index 9196805819..2e1bd36ff8 100644 --- a/Source/Core/WinUpdater/Main.cpp +++ b/Source/Core/WinUpdater/Main.cpp @@ -10,6 +10,7 @@ #include #include +#include "Common/CommonFuncs.h" #include "Common/StringUtil.h" #include "UpdaterCommon/UI.h" @@ -33,28 +34,6 @@ std::vector CommandLineToUtf8Argv(PCWSTR command_line) LocalFree(tokenized); return argv; } - -std::optional GetModuleName(HINSTANCE hInstance) -{ - std::wstring name; - DWORD max_size = 50; // Start with space for 50 characters and grow if needed - name.resize(max_size); - - DWORD size; - while ((size = GetModuleFileNameW(hInstance, name.data(), max_size)) == max_size && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - max_size *= 2; - name.resize(max_size); - } - - if (size == 0) - { - return {}; - } - name.resize(size); - return name; -} }; // namespace int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) From 45890c20cfcc066f9ea264499edf8adfb22e5518 Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 6 Oct 2019 20:26:31 +0200 Subject: [PATCH 3/4] Remove obsolete "Windows compatibility" macros --- Source/Core/Common/CDUtils.cpp | 3 ++- Source/Core/Common/Common.h | 6 ------ Source/Core/Core/PowerPC/Jit64/JitAsm.cpp | 2 ++ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Source/Core/Common/CDUtils.cpp b/Source/Core/Common/CDUtils.cpp index fb67d076c6..559ff0234f 100644 --- a/Source/Core/Common/CDUtils.cpp +++ b/Source/Core/Common/CDUtils.cpp @@ -26,6 +26,7 @@ #include #include #else +#include #include #include #include @@ -211,7 +212,7 @@ bool IsCDROMDevice(std::string device) #ifndef _WIN32 // Resolve symbolic links. This allows symbolic links to valid // drives to be passed from the command line with the -e flag. - char resolved_path[MAX_PATH]; + char resolved_path[PATH_MAX]; char* devname = realpath(device.c_str(), resolved_path); if (!devname) return false; diff --git a/Source/Core/Common/Common.h b/Source/Core/Common/Common.h index eb0944bd8a..81a6e04ea3 100644 --- a/Source/Core/Common/Common.h +++ b/Source/Core/Common/Common.h @@ -30,12 +30,6 @@ struct CrtDebugBreak #endif -// Windows compatibility -#ifndef _WIN32 -#include -#define MAX_PATH PATH_MAX -#endif - #ifdef _MSC_VER #define __getcwd _getcwd #define __chdir _chdir diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index 1389fb05cc..18ed533c0b 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -4,6 +4,8 @@ #include "Core/PowerPC/Jit64/JitAsm.h" +#include + #include "Common/CommonTypes.h" #include "Common/JitRegister.h" #include "Common/x64ABI.h" From ea8a3059bff1693ea640777a3aeb0c31daf18951 Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 6 Oct 2019 22:23:06 +0200 Subject: [PATCH 4/4] Enable Win10 long path awareness in manifest files --- Source/Core/DolphinQt/DolphinQt.manifest | 5 +++-- Source/Core/WinUpdater/Updater.exe.manifest | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/Core/DolphinQt/DolphinQt.manifest b/Source/Core/DolphinQt/DolphinQt.manifest index 8c709b5c38..01910f52dc 100644 --- a/Source/Core/DolphinQt/DolphinQt.manifest +++ b/Source/Core/DolphinQt/DolphinQt.manifest @@ -1,8 +1,9 @@ - - true + + true + true diff --git a/Source/Core/WinUpdater/Updater.exe.manifest b/Source/Core/WinUpdater/Updater.exe.manifest index 0a3ca72f6d..e661623b28 100644 --- a/Source/Core/WinUpdater/Updater.exe.manifest +++ b/Source/Core/WinUpdater/Updater.exe.manifest @@ -29,8 +29,9 @@ - True + xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> + true + true \ No newline at end of file