mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 13:20:27 -06:00
Merge pull request #8393 from CookiePLMonster/long-paths
Support Windows 10 long paths
This commit is contained in:
@ -26,6 +26,7 @@
|
|||||||
#include <IOKit/storage/IOMedia.h>
|
#include <IOKit/storage/IOMedia.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#else
|
#else
|
||||||
|
#include <climits>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -211,7 +212,7 @@ bool IsCDROMDevice(std::string device)
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
// Resolve symbolic links. This allows symbolic links to valid
|
// Resolve symbolic links. This allows symbolic links to valid
|
||||||
// drives to be passed from the command line with the -e flag.
|
// 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);
|
char* devname = realpath(device.c_str(), resolved_path);
|
||||||
if (!devname)
|
if (!devname)
|
||||||
return false;
|
return false;
|
||||||
|
@ -30,12 +30,6 @@ struct CrtDebugBreak
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Windows compatibility
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <limits.h>
|
|
||||||
#define MAX_PATH PATH_MAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define __getcwd _getcwd
|
#define __getcwd _getcwd
|
||||||
#define __chdir _chdir
|
#define __chdir _chdir
|
||||||
|
@ -49,4 +49,27 @@ std::string GetLastErrorString()
|
|||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr);
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr);
|
||||||
return std::string(error_message);
|
return std::string(error_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtains a full path to the specified module.
|
||||||
|
std::optional<std::wstring> 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<HMODULE>(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
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
@ -47,4 +48,7 @@ std::string LastStrerrorString();
|
|||||||
// Wrapper function to get GetLastError() string.
|
// Wrapper function to get GetLastError() string.
|
||||||
// This function might change the error code.
|
// This function might change the error code.
|
||||||
std::string GetLastErrorString();
|
std::string GetLastErrorString();
|
||||||
|
|
||||||
|
// Obtains a full path to the specified module.
|
||||||
|
std::optional<std::wstring> GetModuleName(void* hInstance);
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <winternl.h>
|
#include <winternl.h>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "Common/CommonFuncs.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/LdrWatcher.h"
|
#include "Common/LdrWatcher.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
@ -162,37 +164,26 @@ struct Version
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool GetModulePath(const wchar_t* name, std::wstring* path)
|
static std::optional<std::wstring> GetModulePath(const wchar_t* name)
|
||||||
{
|
{
|
||||||
auto module = GetModuleHandleW(name);
|
auto module = GetModuleHandleW(name);
|
||||||
if (module == nullptr)
|
if (module == nullptr)
|
||||||
return false;
|
return std::nullopt;
|
||||||
DWORD path_len = MAX_PATH;
|
|
||||||
retry:
|
return GetModuleName(module);
|
||||||
path->resize(path_len);
|
|
||||||
path_len = GetModuleFileNameW(module, const_cast<wchar_t*>(path->data()),
|
|
||||||
static_cast<DWORD>(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetModuleVersion(const wchar_t* name, Version* version)
|
static bool GetModuleVersion(const wchar_t* name, Version* version)
|
||||||
{
|
{
|
||||||
std::wstring path;
|
auto path = GetModulePath(name);
|
||||||
if (!GetModulePath(name, &path))
|
if (!path)
|
||||||
return false;
|
return false;
|
||||||
DWORD handle;
|
DWORD handle;
|
||||||
DWORD data_len = GetFileVersionInfoSizeW(path.c_str(), &handle);
|
DWORD data_len = GetFileVersionInfoSizeW(path->c_str(), &handle);
|
||||||
if (!data_len)
|
if (!data_len)
|
||||||
return false;
|
return false;
|
||||||
std::vector<u8> block(data_len);
|
std::vector<u8> 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;
|
return false;
|
||||||
void* buf;
|
void* buf;
|
||||||
UINT buf_len;
|
UINT buf_len;
|
||||||
|
@ -639,19 +639,21 @@ std::string CreateTempDir()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetTempFilenameForAtomicWrite(const std::string& path)
|
std::string GetTempFilenameForAtomicWrite(std::string path)
|
||||||
{
|
{
|
||||||
std::string abs = path;
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TCHAR absbuf[MAX_PATH];
|
std::unique_ptr<TCHAR[], decltype(&std::free)> absbuf{
|
||||||
if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != nullptr)
|
_tfullpath(nullptr, UTF8ToTStr(path).c_str(), 0), std::free};
|
||||||
abs = TStrToUTF8(absbuf);
|
if (absbuf != nullptr)
|
||||||
|
{
|
||||||
|
path = TStrToUTF8(absbuf.get());
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
char absbuf[PATH_MAX];
|
char absbuf[PATH_MAX];
|
||||||
if (realpath(path.c_str(), absbuf) != nullptr)
|
if (realpath(path.c_str(), absbuf) != nullptr)
|
||||||
abs = absbuf;
|
path = absbuf;
|
||||||
#endif
|
#endif
|
||||||
return abs + ".xxx";
|
return std::move(path) + ".xxx";
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -672,22 +674,26 @@ std::string GetBundleDirectory()
|
|||||||
|
|
||||||
std::string GetExePath()
|
std::string GetExePath()
|
||||||
{
|
{
|
||||||
static std::string dolphin_path;
|
static const std::string dolphin_path = [] {
|
||||||
if (dolphin_path.empty())
|
std::string result;
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TCHAR dolphin_exe_path[2048];
|
auto dolphin_exe_path = GetModuleName(nullptr);
|
||||||
TCHAR dolphin_exe_expanded_path[MAX_PATH];
|
if (dolphin_exe_path)
|
||||||
GetModuleFileName(nullptr, dolphin_exe_path, ARRAYSIZE(dolphin_exe_path));
|
{
|
||||||
if (_tfullpath(dolphin_exe_expanded_path, dolphin_exe_path,
|
std::unique_ptr<TCHAR[], decltype(&std::free)> dolphin_exe_expanded_path{
|
||||||
ARRAYSIZE(dolphin_exe_expanded_path)) != nullptr)
|
_tfullpath(nullptr, dolphin_exe_path->c_str(), 0), std::free};
|
||||||
dolphin_path = TStrToUTF8(dolphin_exe_expanded_path);
|
if (dolphin_exe_expanded_path)
|
||||||
else
|
{
|
||||||
dolphin_path = TStrToUTF8(dolphin_exe_path);
|
result = TStrToUTF8(dolphin_exe_expanded_path.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = TStrToUTF8(*dolphin_exe_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
dolphin_path = GetBundleDirectory();
|
result = GetBundleDirectory();
|
||||||
dolphin_path =
|
result = result.substr(0, result.find_last_of("Dolphin.app/Contents/MacOS") + 1);
|
||||||
dolphin_path.substr(0, dolphin_path.find_last_of("Dolphin.app/Contents/MacOS") + 1);
|
|
||||||
#else
|
#else
|
||||||
char dolphin_exe_path[PATH_MAX];
|
char dolphin_exe_path[PATH_MAX];
|
||||||
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
|
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
|
||||||
@ -696,9 +702,10 @@ std::string GetExePath()
|
|||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
dolphin_exe_path[len] = '\0';
|
dolphin_exe_path[len] = '\0';
|
||||||
dolphin_path = dolphin_exe_path;
|
result = dolphin_exe_path;
|
||||||
#endif
|
#endif
|
||||||
}
|
return result;
|
||||||
|
}();
|
||||||
return dolphin_path;
|
return dolphin_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ bool SetCurrentDir(const std::string& directory);
|
|||||||
std::string CreateTempDir();
|
std::string CreateTempDir();
|
||||||
|
|
||||||
// Get a filename that can hopefully be atomically renamed to the given path.
|
// 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
|
// Gets a set user directory path
|
||||||
// Don't call prior to setting the base user directory
|
// Don't call prior to setting the base user directory
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/JitRegister.h"
|
#include "Common/JitRegister.h"
|
||||||
#include "Common/x64ABI.h"
|
#include "Common/x64ABI.h"
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
<windowsSettings>
|
<windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
<dpiAware>true</dpiAware>
|
||||||
|
<longPathAware>true</longPathAware>
|
||||||
</windowsSettings>
|
</windowsSettings>
|
||||||
</application>
|
</application>
|
||||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
@ -226,46 +226,57 @@ void SetUserDirectory(const std::string& custom_path)
|
|||||||
// -> Use GetExeDirectory()\User
|
// -> Use GetExeDirectory()\User
|
||||||
|
|
||||||
// Check our registry keys
|
// Check our registry keys
|
||||||
|
// TODO: Maybe use WIL when it's available?
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
DWORD local = 0;
|
DWORD local = 0;
|
||||||
TCHAR configPath[MAX_PATH] = {0};
|
std::unique_ptr<TCHAR[]> configPath;
|
||||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE,
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE,
|
||||||
&hkey) == ERROR_SUCCESS)
|
&hkey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
DWORD size = 4;
|
DWORD size = 4;
|
||||||
if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr,
|
if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr,
|
||||||
reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS)
|
reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
local = 0;
|
local = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, nullptr, &size);
|
||||||
|
configPath = std::make_unique<TCHAR[]>(size / sizeof(TCHAR));
|
||||||
|
if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr,
|
||||||
|
reinterpret_cast<LPBYTE>(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);
|
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.
|
// Get Documents path in case we need it.
|
||||||
TCHAR my_documents[MAX_PATH];
|
// TODO: Maybe use WIL when it's available?
|
||||||
bool my_documents_found = SUCCEEDED(
|
PWSTR my_documents = nullptr;
|
||||||
SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents));
|
bool my_documents_found =
|
||||||
|
SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &my_documents));
|
||||||
|
|
||||||
if (local) // Case 1-2
|
if (local) // Case 1-2
|
||||||
user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||||
else if (configPath[0]) // Case 3
|
else if (configPath) // Case 3
|
||||||
user_path = TStrToUTF8(configPath);
|
user_path = TStrToUTF8(configPath.get());
|
||||||
else if (my_documents_found) // Case 4
|
else if (my_documents_found) // Case 4
|
||||||
user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP;
|
user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP;
|
||||||
else // Case 5
|
else // Case 5
|
||||||
user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
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
|
// Prettify the path: it will be displayed in some places, we don't want a mix
|
||||||
// of \ and /.
|
// 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.
|
// 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;
|
user_path += DIR_SEP;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -340,7 +351,7 @@ void SetUserDirectory(const std::string& custom_path)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
File::SetUserPath(D_USER_IDX, user_path);
|
File::SetUserPath(D_USER_IDX, std::move(user_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveWiimoteSources()
|
void SaveWiimoteSources()
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonFuncs.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
#include "UpdaterCommon/UI.h"
|
#include "UpdaterCommon/UI.h"
|
||||||
@ -33,28 +34,6 @@ std::vector<std::string> CommandLineToUtf8Argv(PCWSTR command_line)
|
|||||||
LocalFree(tokenized);
|
LocalFree(tokenized);
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> 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
|
}; // namespace
|
||||||
|
|
||||||
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
||||||
|
@ -29,8 +29,9 @@
|
|||||||
</compatibility>
|
</compatibility>
|
||||||
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
<asmv3:windowsSettings
|
<asmv3:windowsSettings
|
||||||
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
<dpiAware>True</dpiAware>
|
<dpiAware>true</dpiAware>
|
||||||
|
<longPathAware>true</longPathAware>
|
||||||
</asmv3:windowsSettings>
|
</asmv3:windowsSettings>
|
||||||
</asmv3:application>
|
</asmv3:application>
|
||||||
</assembly>
|
</assembly>
|
Reference in New Issue
Block a user