Merge pull request #91902 from bruvzg/win_long_path
[Windows] Always use absolute UNC paths and long path aware APIs, add "long path aware" flag to the application manifest.
This commit is contained in:
commit
da230f384b
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
#include "core/os/memory.h"
|
#include "core/os/memory.h"
|
||||||
|
#include "core/os/os.h"
|
||||||
#include "core/string/print_string.h"
|
#include "core/string/print_string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -69,9 +70,17 @@ struct DirAccessWindowsPrivate {
|
||||||
};
|
};
|
||||||
|
|
||||||
String DirAccessWindows::fix_path(const String &p_path) const {
|
String DirAccessWindows::fix_path(const String &p_path) const {
|
||||||
String r_path = DirAccess::fix_path(p_path);
|
String r_path = DirAccess::fix_path(p_path.trim_prefix(R"(\\?\)").replace("\\", "/"));
|
||||||
if (r_path.is_absolute_path() && !r_path.is_network_share_path() && r_path.length() > MAX_PATH) {
|
|
||||||
r_path = "\\\\?\\" + r_path.replace("/", "\\");
|
if (r_path.is_relative_path()) {
|
||||||
|
r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path);
|
||||||
|
} else if (r_path == ".") {
|
||||||
|
r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
|
}
|
||||||
|
r_path = r_path.simplify_path();
|
||||||
|
r_path = r_path.replace("/", "\\");
|
||||||
|
if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) {
|
||||||
|
r_path = R"(\\?\)" + r_path;
|
||||||
}
|
}
|
||||||
return r_path;
|
return r_path;
|
||||||
}
|
}
|
||||||
|
@ -140,28 +149,33 @@ String DirAccessWindows::get_drive(int p_drive) {
|
||||||
Error DirAccessWindows::change_dir(String p_dir) {
|
Error DirAccessWindows::change_dir(String p_dir) {
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION
|
||||||
|
|
||||||
p_dir = fix_path(p_dir);
|
String dir = fix_path(p_dir);
|
||||||
|
|
||||||
WCHAR real_current_dir_name[2048];
|
Char16String real_current_dir_name;
|
||||||
GetCurrentDirectoryW(2048, real_current_dir_name);
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
String prev_dir = String::utf16((const char16_t *)real_current_dir_name);
|
real_current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw());
|
||||||
|
String prev_dir = String::utf16((const char16_t *)real_current_dir_name.get_data());
|
||||||
|
|
||||||
SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
|
SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
|
||||||
bool worked = (SetCurrentDirectoryW((LPCWSTR)(p_dir.utf16().get_data())) != 0);
|
bool worked = (SetCurrentDirectoryW((LPCWSTR)(dir.utf16().get_data())) != 0);
|
||||||
|
|
||||||
String base = _get_root_path();
|
String base = _get_root_path();
|
||||||
if (!base.is_empty()) {
|
if (!base.is_empty()) {
|
||||||
GetCurrentDirectoryW(2048, real_current_dir_name);
|
str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
String new_dir = String::utf16((const char16_t *)real_current_dir_name).replace("\\", "/");
|
real_current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw());
|
||||||
|
String new_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
if (!new_dir.begins_with(base)) {
|
if (!new_dir.begins_with(base)) {
|
||||||
worked = false;
|
worked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worked) {
|
if (worked) {
|
||||||
GetCurrentDirectoryW(2048, real_current_dir_name);
|
str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
current_dir = String::utf16((const char16_t *)real_current_dir_name);
|
real_current_dir_name.resize(str_len + 1);
|
||||||
current_dir = current_dir.replace("\\", "/");
|
GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw());
|
||||||
|
current_dir = String::utf16((const char16_t *)real_current_dir_name.get_data());
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
|
SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
|
||||||
|
@ -172,12 +186,6 @@ Error DirAccessWindows::change_dir(String p_dir) {
|
||||||
Error DirAccessWindows::make_dir(String p_dir) {
|
Error DirAccessWindows::make_dir(String p_dir) {
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION
|
||||||
|
|
||||||
p_dir = fix_path(p_dir);
|
|
||||||
if (p_dir.is_relative_path()) {
|
|
||||||
p_dir = current_dir.path_join(p_dir);
|
|
||||||
p_dir = fix_path(p_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FileAccessWindows::is_path_invalid(p_dir)) {
|
if (FileAccessWindows::is_path_invalid(p_dir)) {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
WARN_PRINT("The path :" + p_dir + " is a reserved Windows system pipe, so it can't be used for creating directories.");
|
WARN_PRINT("The path :" + p_dir + " is a reserved Windows system pipe, so it can't be used for creating directories.");
|
||||||
|
@ -185,12 +193,12 @@ Error DirAccessWindows::make_dir(String p_dir) {
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_dir = p_dir.simplify_path().replace("/", "\\");
|
String dir = fix_path(p_dir);
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), nullptr);
|
success = CreateDirectoryW((LPCWSTR)(dir.utf16().get_data()), nullptr);
|
||||||
err = GetLastError();
|
err = GetLastError();
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -205,9 +213,10 @@ Error DirAccessWindows::make_dir(String p_dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String DirAccessWindows::get_current_dir(bool p_include_drive) const {
|
String DirAccessWindows::get_current_dir(bool p_include_drive) const {
|
||||||
|
String cdir = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
String base = _get_root_path();
|
String base = _get_root_path();
|
||||||
if (!base.is_empty()) {
|
if (!base.is_empty()) {
|
||||||
String bd = current_dir.replace("\\", "/").replace_first(base, "");
|
String bd = cdir.replace_first(base, "");
|
||||||
if (bd.begins_with("/")) {
|
if (bd.begins_with("/")) {
|
||||||
return _get_root_string() + bd.substr(1, bd.length());
|
return _get_root_string() + bd.substr(1, bd.length());
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,30 +225,25 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_include_drive) {
|
if (p_include_drive) {
|
||||||
return current_dir;
|
return cdir;
|
||||||
} else {
|
} else {
|
||||||
if (_get_root_string().is_empty()) {
|
if (_get_root_string().is_empty()) {
|
||||||
int pos = current_dir.find(":");
|
int pos = cdir.find(":");
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
return current_dir.substr(pos + 1);
|
return cdir.substr(pos + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return current_dir;
|
return cdir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirAccessWindows::file_exists(String p_file) {
|
bool DirAccessWindows::file_exists(String p_file) {
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION
|
||||||
|
|
||||||
if (!p_file.is_absolute_path()) {
|
String file = fix_path(p_file);
|
||||||
p_file = get_current_dir().path_join(p_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
p_file = fix_path(p_file);
|
|
||||||
|
|
||||||
DWORD fileAttr;
|
DWORD fileAttr;
|
||||||
|
fileAttr = GetFileAttributesW((LPCWSTR)(file.utf16().get_data()));
|
||||||
fileAttr = GetFileAttributesW((LPCWSTR)(p_file.utf16().get_data()));
|
|
||||||
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -250,14 +254,10 @@ bool DirAccessWindows::file_exists(String p_file) {
|
||||||
bool DirAccessWindows::dir_exists(String p_dir) {
|
bool DirAccessWindows::dir_exists(String p_dir) {
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION
|
||||||
|
|
||||||
if (p_dir.is_relative_path()) {
|
String dir = fix_path(p_dir);
|
||||||
p_dir = get_current_dir().path_join(p_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
p_dir = fix_path(p_dir);
|
|
||||||
|
|
||||||
DWORD fileAttr;
|
DWORD fileAttr;
|
||||||
fileAttr = GetFileAttributesW((LPCWSTR)(p_dir.utf16().get_data()));
|
fileAttr = GetFileAttributesW((LPCWSTR)(dir.utf16().get_data()));
|
||||||
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -265,66 +265,63 @@ bool DirAccessWindows::dir_exists(String p_dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Error DirAccessWindows::rename(String p_path, String p_new_path) {
|
Error DirAccessWindows::rename(String p_path, String p_new_path) {
|
||||||
if (p_path.is_relative_path()) {
|
String path = fix_path(p_path);
|
||||||
p_path = get_current_dir().path_join(p_path);
|
String new_path = fix_path(p_new_path);
|
||||||
}
|
|
||||||
|
|
||||||
p_path = fix_path(p_path);
|
|
||||||
|
|
||||||
if (p_new_path.is_relative_path()) {
|
|
||||||
p_new_path = get_current_dir().path_join(p_new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
p_new_path = fix_path(p_new_path);
|
|
||||||
|
|
||||||
// If we're only changing file name case we need to do a little juggling
|
// If we're only changing file name case we need to do a little juggling
|
||||||
if (p_path.to_lower() == p_new_path.to_lower()) {
|
if (path.to_lower() == new_path.to_lower()) {
|
||||||
if (dir_exists(p_path)) {
|
if (dir_exists(path)) {
|
||||||
// The path is a dir; just rename
|
// The path is a dir; just rename
|
||||||
return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED;
|
return MoveFileW((LPCWSTR)(path.utf16().get_data()), (LPCWSTR)(new_path.utf16().get_data())) != 0 ? OK : FAILED;
|
||||||
}
|
}
|
||||||
// The path is a file; juggle
|
// The path is a file; juggle
|
||||||
WCHAR tmpfile[MAX_PATH];
|
// Note: do not use GetTempFileNameW, it's not long path aware!
|
||||||
|
Char16String tmpfile_utf16;
|
||||||
if (!GetTempFileNameW((LPCWSTR)(fix_path(get_current_dir()).utf16().get_data()), nullptr, 0, tmpfile)) {
|
uint64_t id = OS::get_singleton()->get_ticks_usec();
|
||||||
return FAILED;
|
while (true) {
|
||||||
}
|
tmpfile_utf16 = (path + itos(id++) + ".tmp").utf16();
|
||||||
|
HANDLE handle = CreateFileW((LPCWSTR)tmpfile_utf16.get_data(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
if (!::ReplaceFileW(tmpfile, (LPCWSTR)(p_path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
DeleteFileW(tmpfile);
|
CloseHandle(handle);
|
||||||
return FAILED;
|
break;
|
||||||
}
|
}
|
||||||
|
if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_SHARING_VIOLATION) {
|
||||||
return ::_wrename(tmpfile, (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (file_exists(p_new_path)) {
|
|
||||||
if (remove(p_new_path) != OK) {
|
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED;
|
if (!::ReplaceFileW((LPCWSTR)tmpfile_utf16.get_data(), (LPCWSTR)(path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) {
|
||||||
|
DeleteFileW((LPCWSTR)tmpfile_utf16.get_data());
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MoveFileW((LPCWSTR)tmpfile_utf16.get_data(), (LPCWSTR)(new_path.utf16().get_data())) != 0 ? OK : FAILED;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (file_exists(new_path)) {
|
||||||
|
if (remove(new_path) != OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MoveFileW((LPCWSTR)(path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) != 0 ? OK : FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Error DirAccessWindows::remove(String p_path) {
|
Error DirAccessWindows::remove(String p_path) {
|
||||||
if (p_path.is_relative_path()) {
|
String path = fix_path(p_path);
|
||||||
p_path = get_current_dir().path_join(p_path);
|
const Char16String &path_utf16 = path.utf16();
|
||||||
}
|
|
||||||
|
|
||||||
p_path = fix_path(p_path);
|
|
||||||
|
|
||||||
DWORD fileAttr;
|
DWORD fileAttr;
|
||||||
|
|
||||||
fileAttr = GetFileAttributesW((LPCWSTR)(p_path.utf16().get_data()));
|
fileAttr = GetFileAttributesW((LPCWSTR)(path_utf16.get_data()));
|
||||||
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
return ::_wrmdir((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED;
|
return RemoveDirectoryW((LPCWSTR)(path_utf16.get_data())) != 0 ? OK : FAILED;
|
||||||
} else {
|
} else {
|
||||||
return ::_wunlink((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED;
|
return DeleteFileW((LPCWSTR)(path_utf16.get_data())) != 0 ? OK : FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,16 +336,16 @@ uint64_t DirAccessWindows::get_space_left() {
|
||||||
}
|
}
|
||||||
|
|
||||||
String DirAccessWindows::get_filesystem_type() const {
|
String DirAccessWindows::get_filesystem_type() const {
|
||||||
String path = fix_path(const_cast<DirAccessWindows *>(this)->get_current_dir());
|
String path = current_dir.trim_prefix(R"(\\?\)");
|
||||||
|
|
||||||
int unit_end = path.find(":");
|
|
||||||
ERR_FAIL_COND_V(unit_end == -1, String());
|
|
||||||
String unit = path.substr(0, unit_end + 1) + "\\";
|
|
||||||
|
|
||||||
if (path.is_network_share_path()) {
|
if (path.is_network_share_path()) {
|
||||||
return "Network Share";
|
return "Network Share";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unit_end = path.find(":");
|
||||||
|
ERR_FAIL_COND_V(unit_end == -1, String());
|
||||||
|
String unit = path.substr(0, unit_end + 1) + "\\";
|
||||||
|
|
||||||
WCHAR szVolumeName[100];
|
WCHAR szVolumeName[100];
|
||||||
WCHAR szFileSystemName[10];
|
WCHAR szFileSystemName[10];
|
||||||
DWORD dwSerialNumber = 0;
|
DWORD dwSerialNumber = 0;
|
||||||
|
@ -370,11 +367,7 @@ String DirAccessWindows::get_filesystem_type() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
|
bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
|
||||||
String f = p_path;
|
String f = fix_path(p_path);
|
||||||
if (!f.is_absolute_path()) {
|
|
||||||
f = get_current_dir().path_join(f);
|
|
||||||
}
|
|
||||||
f = fix_path(f);
|
|
||||||
|
|
||||||
HANDLE h_file = ::CreateFileW((LPCWSTR)(f.utf16().get_data()), 0,
|
HANDLE h_file = ::CreateFileW((LPCWSTR)(f.utf16().get_data()), 0,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
@ -397,12 +390,7 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirAccessWindows::is_link(String p_file) {
|
bool DirAccessWindows::is_link(String p_file) {
|
||||||
String f = p_file;
|
String f = fix_path(p_file);
|
||||||
|
|
||||||
if (!f.is_absolute_path()) {
|
|
||||||
f = get_current_dir().path_join(f);
|
|
||||||
}
|
|
||||||
f = fix_path(f);
|
|
||||||
|
|
||||||
DWORD attr = GetFileAttributesW((LPCWSTR)(f.utf16().get_data()));
|
DWORD attr = GetFileAttributesW((LPCWSTR)(f.utf16().get_data()));
|
||||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
@ -413,12 +401,7 @@ bool DirAccessWindows::is_link(String p_file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String DirAccessWindows::read_link(String p_file) {
|
String DirAccessWindows::read_link(String p_file) {
|
||||||
String f = p_file;
|
String f = fix_path(p_file);
|
||||||
|
|
||||||
if (!f.is_absolute_path()) {
|
|
||||||
f = get_current_dir().path_join(f);
|
|
||||||
}
|
|
||||||
f = fix_path(f);
|
|
||||||
|
|
||||||
HANDLE hfile = CreateFileW((LPCWSTR)(f.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
HANDLE hfile = CreateFileW((LPCWSTR)(f.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
if (hfile == INVALID_HANDLE_VALUE) {
|
if (hfile == INVALID_HANDLE_VALUE) {
|
||||||
|
@ -434,22 +417,18 @@ String DirAccessWindows::read_link(String p_file) {
|
||||||
GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
|
GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
|
||||||
CloseHandle(hfile);
|
CloseHandle(hfile);
|
||||||
|
|
||||||
return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)");
|
return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error DirAccessWindows::create_link(String p_source, String p_target) {
|
Error DirAccessWindows::create_link(String p_source, String p_target) {
|
||||||
if (p_target.is_relative_path()) {
|
String source = fix_path(p_source);
|
||||||
p_target = get_current_dir().path_join(p_target);
|
String target = fix_path(p_target);
|
||||||
}
|
|
||||||
|
|
||||||
p_source = fix_path(p_source);
|
DWORD file_attr = GetFileAttributesW((LPCWSTR)(source.utf16().get_data()));
|
||||||
p_target = fix_path(p_target);
|
|
||||||
|
|
||||||
DWORD file_attr = GetFileAttributesW((LPCWSTR)(p_source.utf16().get_data()));
|
|
||||||
bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY);
|
bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
||||||
if (CreateSymbolicLinkW((LPCWSTR)p_target.utf16().get_data(), (LPCWSTR)p_source.utf16().get_data(), flags) != 0) {
|
if (CreateSymbolicLinkW((LPCWSTR)target.utf16().get_data(), (LPCWSTR)source.utf16().get_data(), flags) != 0) {
|
||||||
return OK;
|
return OK;
|
||||||
} else {
|
} else {
|
||||||
return FAILED;
|
return FAILED;
|
||||||
|
@ -459,7 +438,12 @@ Error DirAccessWindows::create_link(String p_source, String p_target) {
|
||||||
DirAccessWindows::DirAccessWindows() {
|
DirAccessWindows::DirAccessWindows() {
|
||||||
p = memnew(DirAccessWindowsPrivate);
|
p = memnew(DirAccessWindowsPrivate);
|
||||||
p->h = INVALID_HANDLE_VALUE;
|
p->h = INVALID_HANDLE_VALUE;
|
||||||
current_dir = ".";
|
|
||||||
|
Char16String real_current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
real_current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw());
|
||||||
|
current_dir = String::utf16((const char16_t *)real_current_dir_name.get_data());
|
||||||
|
|
||||||
DWORD mask = GetLogicalDrives();
|
DWORD mask = GetLogicalDrives();
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,18 @@ bool FileAccessWindows::is_path_invalid(const String &p_path) {
|
||||||
|
|
||||||
String FileAccessWindows::fix_path(const String &p_path) const {
|
String FileAccessWindows::fix_path(const String &p_path) const {
|
||||||
String r_path = FileAccess::fix_path(p_path);
|
String r_path = FileAccess::fix_path(p_path);
|
||||||
if (r_path.is_absolute_path() && !r_path.is_network_share_path() && r_path.length() > MAX_PATH) {
|
|
||||||
r_path = "\\\\?\\" + r_path.replace("/", "\\");
|
if (r_path.is_relative_path()) {
|
||||||
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
r_path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path);
|
||||||
|
}
|
||||||
|
r_path = r_path.simplify_path();
|
||||||
|
r_path = r_path.replace("/", "\\");
|
||||||
|
if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) {
|
||||||
|
r_path = R"(\\?\)" + r_path;
|
||||||
}
|
}
|
||||||
return r_path;
|
return r_path;
|
||||||
}
|
}
|
||||||
|
@ -108,9 +118,6 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pretty much every implementation that uses fopen as primary
|
|
||||||
backend supports utf8 encoding. */
|
|
||||||
|
|
||||||
struct _stat st;
|
struct _stat st;
|
||||||
if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) {
|
if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) {
|
||||||
if (!S_ISREG(st.st_mode)) {
|
if (!S_ISREG(st.st_mode)) {
|
||||||
|
@ -125,7 +132,7 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
|
||||||
// platforms), we only check for relative paths, or paths in res:// or user://,
|
// platforms), we only check for relative paths, or paths in res:// or user://,
|
||||||
// other paths aren't likely to be portable anyway.
|
// other paths aren't likely to be portable anyway.
|
||||||
if (p_mode_flags == READ && (p_path.is_relative_path() || get_access_type() != ACCESS_FILESYSTEM)) {
|
if (p_mode_flags == READ && (p_path.is_relative_path() || get_access_type() != ACCESS_FILESYSTEM)) {
|
||||||
String base_path = path;
|
String base_path = p_path;
|
||||||
String working_path;
|
String working_path;
|
||||||
String proper_path;
|
String proper_path;
|
||||||
|
|
||||||
|
@ -144,23 +151,17 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
|
||||||
}
|
}
|
||||||
proper_path = "user://";
|
proper_path = "user://";
|
||||||
}
|
}
|
||||||
|
working_path = fix_path(working_path);
|
||||||
|
|
||||||
WIN32_FIND_DATAW d;
|
WIN32_FIND_DATAW d;
|
||||||
Vector<String> parts = base_path.split("/");
|
Vector<String> parts = base_path.simplify_path().split("/");
|
||||||
|
|
||||||
bool mismatch = false;
|
bool mismatch = false;
|
||||||
|
|
||||||
for (const String &part : parts) {
|
for (const String &part : parts) {
|
||||||
working_path = working_path.path_join(part);
|
working_path = working_path + "\\" + part;
|
||||||
|
|
||||||
// Skip if relative.
|
|
||||||
if (part == "." || part == "..") {
|
|
||||||
proper_path = proper_path.path_join(part);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE fnd = FindFirstFileW((LPCWSTR)(working_path.utf16().get_data()), &d);
|
HANDLE fnd = FindFirstFileW((LPCWSTR)(working_path.utf16().get_data()), &d);
|
||||||
|
|
||||||
if (fnd == INVALID_HANDLE_VALUE) {
|
if (fnd == INVALID_HANDLE_VALUE) {
|
||||||
mismatch = false;
|
mismatch = false;
|
||||||
break;
|
break;
|
||||||
|
@ -186,12 +187,22 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
|
||||||
if (is_backup_save_enabled() && p_mode_flags == WRITE) {
|
if (is_backup_save_enabled() && p_mode_flags == WRITE) {
|
||||||
save_path = path;
|
save_path = path;
|
||||||
// Create a temporary file in the same directory as the target file.
|
// Create a temporary file in the same directory as the target file.
|
||||||
WCHAR tmpFileName[MAX_PATH];
|
// Note: do not use GetTempFileNameW, it's not long path aware!
|
||||||
if (GetTempFileNameW((LPCWSTR)(path.get_base_dir().utf16().get_data()), (LPCWSTR)(path.get_file().utf16().get_data()), 0, tmpFileName) == 0) {
|
String tmpfile;
|
||||||
last_error = ERR_FILE_CANT_OPEN;
|
uint64_t id = OS::get_singleton()->get_ticks_usec();
|
||||||
return last_error;
|
while (true) {
|
||||||
|
tmpfile = path + itos(id++) + ".tmp";
|
||||||
|
HANDLE handle = CreateFileW((LPCWSTR)tmpfile.utf16().get_data(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(handle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_SHARING_VIOLATION) {
|
||||||
|
last_error = ERR_FILE_CANT_WRITE;
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
path = tmpFileName;
|
path = tmpfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
f = _wfsopen((LPCWSTR)(path.utf16().get_data()), mode_string, is_backup_save_enabled() ? _SH_SECURE : _SH_DENYNO);
|
f = _wfsopen((LPCWSTR)(path.utf16().get_data()), mode_string, is_backup_save_enabled() ? _SH_SECURE : _SH_DENYNO);
|
||||||
|
@ -235,7 +246,7 @@ void FileAccessWindows::_close() {
|
||||||
} else {
|
} else {
|
||||||
// Either the target exists and is locked (temporarily, hopefully)
|
// Either the target exists and is locked (temporarily, hopefully)
|
||||||
// or it doesn't exist; let's assume the latter before re-trying.
|
// or it doesn't exist; let's assume the latter before re-trying.
|
||||||
rename_error = _wrename((LPCWSTR)(path_utf16.get_data()), (LPCWSTR)(save_path_utf16.get_data())) != 0;
|
rename_error = MoveFileW((LPCWSTR)(path_utf16.get_data()), (LPCWSTR)(save_path_utf16.get_data())) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rename_error) {
|
if (!rename_error) {
|
||||||
|
@ -262,7 +273,7 @@ String FileAccessWindows::get_path() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
String FileAccessWindows::get_path_absolute() const {
|
String FileAccessWindows::get_path_absolute() const {
|
||||||
return path;
|
return path.trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileAccessWindows::is_open() const {
|
bool FileAccessWindows::is_open() const {
|
||||||
|
@ -548,10 +559,11 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String file = fix_path(p_file);
|
String file = p_file;
|
||||||
if (file.ends_with("/") && file != "/") {
|
if (file.ends_with("/") && file != "/") {
|
||||||
file = file.substr(0, file.length() - 1);
|
file = file.substr(0, file.length() - 1);
|
||||||
}
|
}
|
||||||
|
file = fix_path(file);
|
||||||
|
|
||||||
struct _stat st;
|
struct _stat st;
|
||||||
int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st);
|
int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st);
|
||||||
|
@ -582,14 +594,15 @@ bool FileAccessWindows::_get_hidden_attribute(const String &p_file) {
|
||||||
|
|
||||||
Error FileAccessWindows::_set_hidden_attribute(const String &p_file, bool p_hidden) {
|
Error FileAccessWindows::_set_hidden_attribute(const String &p_file, bool p_hidden) {
|
||||||
String file = fix_path(p_file);
|
String file = fix_path(p_file);
|
||||||
|
const Char16String &file_utf16 = file.utf16();
|
||||||
|
|
||||||
DWORD attrib = GetFileAttributesW((LPCWSTR)file.utf16().get_data());
|
DWORD attrib = GetFileAttributesW((LPCWSTR)file_utf16.get_data());
|
||||||
ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file);
|
ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file);
|
||||||
BOOL ok;
|
BOOL ok;
|
||||||
if (p_hidden) {
|
if (p_hidden) {
|
||||||
ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib | FILE_ATTRIBUTE_HIDDEN);
|
ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib | FILE_ATTRIBUTE_HIDDEN);
|
||||||
} else {
|
} else {
|
||||||
ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib & ~FILE_ATTRIBUTE_HIDDEN);
|
ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib & ~FILE_ATTRIBUTE_HIDDEN);
|
||||||
}
|
}
|
||||||
ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file);
|
ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file);
|
||||||
|
|
||||||
|
@ -606,14 +619,15 @@ bool FileAccessWindows::_get_read_only_attribute(const String &p_file) {
|
||||||
|
|
||||||
Error FileAccessWindows::_set_read_only_attribute(const String &p_file, bool p_ro) {
|
Error FileAccessWindows::_set_read_only_attribute(const String &p_file, bool p_ro) {
|
||||||
String file = fix_path(p_file);
|
String file = fix_path(p_file);
|
||||||
|
const Char16String &file_utf16 = file.utf16();
|
||||||
|
|
||||||
DWORD attrib = GetFileAttributesW((LPCWSTR)file.utf16().get_data());
|
DWORD attrib = GetFileAttributesW((LPCWSTR)file_utf16.get_data());
|
||||||
ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file);
|
ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file);
|
||||||
BOOL ok;
|
BOOL ok;
|
||||||
if (p_ro) {
|
if (p_ro) {
|
||||||
ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib | FILE_ATTRIBUTE_READONLY);
|
ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib | FILE_ATTRIBUTE_READONLY);
|
||||||
} else {
|
} else {
|
||||||
ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib & ~FILE_ATTRIBUTE_READONLY);
|
ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib & ~FILE_ATTRIBUTE_READONLY);
|
||||||
}
|
}
|
||||||
ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file);
|
ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<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">
|
||||||
|
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
|
<ws2:longPathAware>true</ws2:longPathAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
<dependency>
|
<dependency>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity
|
<assemblyIdentity
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Get executable name.
|
// Get executable name.
|
||||||
WCHAR exe_name[MAX_PATH] = {};
|
WCHAR exe_name[32767] = {};
|
||||||
if (!GetModuleFileNameW(nullptr, exe_name, MAX_PATH)) {
|
if (!GetModuleFileNameW(nullptr, exe_name, 32767)) {
|
||||||
wprintf(L"GetModuleFileName failed, error %d\n", GetLastError());
|
wprintf(L"GetModuleFileName failed, error %d\n", GetLastError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,7 +317,7 @@ public:
|
||||||
if (!lpw_path) {
|
if (!lpw_path) {
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
String path = String::utf16((const char16_t *)lpw_path).simplify_path();
|
String path = String::utf16((const char16_t *)lpw_path).replace("\\", "/").trim_prefix(R"(\\?\)").simplify_path();
|
||||||
if (!path.begins_with(root.simplify_path())) {
|
if (!path.begins_with(root.simplify_path())) {
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,26 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
|
||||||
pfd->SetOptions(flags | FOS_FORCEFILESYSTEM);
|
pfd->SetOptions(flags | FOS_FORCEFILESYSTEM);
|
||||||
pfd->SetTitle((LPCWSTR)fd->title.utf16().ptr());
|
pfd->SetTitle((LPCWSTR)fd->title.utf16().ptr());
|
||||||
|
|
||||||
String dir = fd->current_directory.replace("/", "\\");
|
String dir = ProjectSettings::get_singleton()->globalize_path(fd->current_directory);
|
||||||
|
if (dir == ".") {
|
||||||
|
dir = OS::get_singleton()->get_executable_path().get_base_dir();
|
||||||
|
}
|
||||||
|
if (dir.is_relative_path() || dir == ".") {
|
||||||
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
if (dir == ".") {
|
||||||
|
dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/");
|
||||||
|
} else {
|
||||||
|
dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir = dir.simplify_path();
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
if (!dir.is_network_share_path() && !dir.begins_with(R"(\\?\)")) {
|
||||||
|
dir = R"(\\?\)" + dir;
|
||||||
|
}
|
||||||
|
|
||||||
IShellItem *shellitem = nullptr;
|
IShellItem *shellitem = nullptr;
|
||||||
hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
|
hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
|
||||||
|
@ -585,7 +604,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
|
||||||
PWSTR file_path = nullptr;
|
PWSTR file_path = nullptr;
|
||||||
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
file_names.push_back(String::utf16((const char16_t *)file_path));
|
file_names.push_back(String::utf16((const char16_t *)file_path).replace("\\", "/").trim_prefix(R"(\\?\)"));
|
||||||
CoTaskMemFree(file_path);
|
CoTaskMemFree(file_path);
|
||||||
}
|
}
|
||||||
result->Release();
|
result->Release();
|
||||||
|
@ -599,7 +618,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
|
||||||
PWSTR file_path = nullptr;
|
PWSTR file_path = nullptr;
|
||||||
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
file_names.push_back(String::utf16((const char16_t *)file_path));
|
file_names.push_back(String::utf16((const char16_t *)file_path).replace("\\", "/").trim_prefix(R"(\\?\)"));
|
||||||
CoTaskMemFree(file_path);
|
CoTaskMemFree(file_path);
|
||||||
}
|
}
|
||||||
result->Release();
|
result->Release();
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "core/version.h"
|
#include "core/version.h"
|
||||||
|
|
||||||
|
#ifndef RT_MANIFEST
|
||||||
|
#define RT_MANIFEST 24
|
||||||
|
#endif
|
||||||
|
|
||||||
GODOT_ICON ICON platform/windows/godot_console.ico
|
GODOT_ICON ICON platform/windows/godot_console.ico
|
||||||
|
1 RT_MANIFEST "godot.manifest"
|
||||||
|
|
||||||
1 VERSIONINFO
|
1 VERSIONINFO
|
||||||
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
|
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
|
||||||
|
|
|
@ -90,6 +90,23 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||||
#define GetProcAddress (void *)GetProcAddress
|
#define GetProcAddress (void *)GetProcAddress
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static String fix_path(const String &p_path) {
|
||||||
|
String path = p_path;
|
||||||
|
if (p_path.is_relative_path()) {
|
||||||
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(path);
|
||||||
|
}
|
||||||
|
path = path.simplify_path();
|
||||||
|
path = path.replace("/", "\\");
|
||||||
|
if (!path.is_network_share_path() && !path.begins_with(R"(\\?\)")) {
|
||||||
|
path = R"(\\?\)" + path;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
static String format_error_message(DWORD id) {
|
static String format_error_message(DWORD id) {
|
||||||
LPWSTR messageBuffer = nullptr;
|
LPWSTR messageBuffer = nullptr;
|
||||||
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
@ -300,7 +317,7 @@ Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
void debug_dynamic_library_check_dependencies(const String &p_root_path, const String &p_path, HashSet<String> &r_checked, HashSet<String> &r_missing) {
|
void debug_dynamic_library_check_dependencies(const String &p_path, HashSet<String> &r_checked, HashSet<String> &r_missing) {
|
||||||
if (r_checked.has(p_path)) {
|
if (r_checked.has(p_path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -342,15 +359,15 @@ void debug_dynamic_library_check_dependencies(const String &p_root_path, const S
|
||||||
const IMAGE_IMPORT_DESCRIPTOR *import_desc = (const IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, false, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
|
const IMAGE_IMPORT_DESCRIPTOR *import_desc = (const IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, false, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
|
||||||
if (import_desc) {
|
if (import_desc) {
|
||||||
for (; import_desc->Name && import_desc->FirstThunk; import_desc++) {
|
for (; import_desc->Name && import_desc->FirstThunk; import_desc++) {
|
||||||
char16_t full_name_wc[MAX_PATH];
|
char16_t full_name_wc[32767];
|
||||||
const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, nullptr);
|
const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, nullptr);
|
||||||
String name = String(name_cs);
|
String name = String(name_cs);
|
||||||
if (name.begins_with("api-ms-win-")) {
|
if (name.begins_with("api-ms-win-")) {
|
||||||
r_checked.insert(name);
|
r_checked.insert(name);
|
||||||
} else if (SearchPathW(nullptr, (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) {
|
} else if (SearchPathW(nullptr, (LPCWSTR)name.utf16().get_data(), nullptr, 32767, (LPWSTR)full_name_wc, nullptr)) {
|
||||||
debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing);
|
debug_dynamic_library_check_dependencies(String::utf16(full_name_wc), r_checked, r_missing);
|
||||||
} else if (SearchPathW((LPCWSTR)(p_path.get_base_dir().utf16().get_data()), (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) {
|
} else if (SearchPathW((LPCWSTR)(p_path.get_base_dir().utf16().get_data()), (LPCWSTR)name.utf16().get_data(), nullptr, 32767, (LPWSTR)full_name_wc, nullptr)) {
|
||||||
debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing);
|
debug_dynamic_library_check_dependencies(String::utf16(full_name_wc), r_checked, r_missing);
|
||||||
} else {
|
} else {
|
||||||
r_missing.insert(name);
|
r_missing.insert(name);
|
||||||
}
|
}
|
||||||
|
@ -367,7 +384,7 @@ void debug_dynamic_library_check_dependencies(const String &p_root_path, const S
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Error OS_Windows::open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data) {
|
Error OS_Windows::open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data) {
|
||||||
String path = p_path.replace("/", "\\");
|
String path = p_path;
|
||||||
|
|
||||||
if (!FileAccess::exists(path)) {
|
if (!FileAccess::exists(path)) {
|
||||||
//this code exists so gdextension can load .dll files from within the executable path
|
//this code exists so gdextension can load .dll files from within the executable path
|
||||||
|
@ -413,12 +430,13 @@ Error OS_Windows::open_dynamic_library(const String &p_path, void *&p_library_ha
|
||||||
bool has_dll_directory_api = ((add_dll_directory != nullptr) && (remove_dll_directory != nullptr));
|
bool has_dll_directory_api = ((add_dll_directory != nullptr) && (remove_dll_directory != nullptr));
|
||||||
DLL_DIRECTORY_COOKIE cookie = nullptr;
|
DLL_DIRECTORY_COOKIE cookie = nullptr;
|
||||||
|
|
||||||
|
String dll_dir = ProjectSettings::get_singleton()->globalize_path(load_path.get_base_dir());
|
||||||
|
String wpath = fix_path(dll_dir);
|
||||||
if (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) {
|
if (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) {
|
||||||
String dll_dir = ProjectSettings::get_singleton()->globalize_path(load_path.get_base_dir());
|
cookie = add_dll_directory((LPCWSTR)(wpath.get_base_dir().utf16().get_data()));
|
||||||
cookie = add_dll_directory((LPCWSTR)(dll_dir.utf16().get_data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(load_path.utf16().get_data()), nullptr, (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
|
p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(wpath.utf16().get_data()), nullptr, (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
|
||||||
if (!p_library_handle) {
|
if (!p_library_handle) {
|
||||||
if (p_data != nullptr && p_data->generate_temp_files) {
|
if (p_data != nullptr && p_data->generate_temp_files) {
|
||||||
DirAccess::remove_absolute(load_path);
|
DirAccess::remove_absolute(load_path);
|
||||||
|
@ -429,7 +447,7 @@ Error OS_Windows::open_dynamic_library(const String &p_path, void *&p_library_ha
|
||||||
|
|
||||||
HashSet<String> checked_libs;
|
HashSet<String> checked_libs;
|
||||||
HashSet<String> missing_libs;
|
HashSet<String> missing_libs;
|
||||||
debug_dynamic_library_check_dependencies(load_path, load_path, checked_libs, missing_libs);
|
debug_dynamic_library_check_dependencies(wpath, checked_libs, missing_libs);
|
||||||
if (!missing_libs.is_empty()) {
|
if (!missing_libs.is_empty()) {
|
||||||
String missing;
|
String missing;
|
||||||
for (const String &E : missing_libs) {
|
for (const String &E : missing_libs) {
|
||||||
|
@ -883,7 +901,7 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
|
||||||
|
|
||||||
Dictionary ret;
|
Dictionary ret;
|
||||||
|
|
||||||
String path = p_path.replace("/", "\\");
|
String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path;
|
||||||
String command = _quote_command_line_argument(path);
|
String command = _quote_command_line_argument(path);
|
||||||
for (const String &E : p_arguments) {
|
for (const String &E : p_arguments) {
|
||||||
command += " " + _quote_command_line_argument(E);
|
command += " " + _quote_command_line_argument(E);
|
||||||
|
@ -932,7 +950,19 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
|
||||||
|
|
||||||
DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW;
|
DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW;
|
||||||
|
|
||||||
if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, nullptr, si_w, &pi.pi)) {
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
if (current_dir_name.size() >= MAX_PATH) {
|
||||||
|
Char16String current_short_dir_name;
|
||||||
|
str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0);
|
||||||
|
current_short_dir_name.resize(str_len);
|
||||||
|
GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size());
|
||||||
|
current_dir_name = current_short_dir_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi)) {
|
||||||
CLEAN_PIPES
|
CLEAN_PIPES
|
||||||
ERR_FAIL_V_MSG(ret, "Could not create child process: " + command);
|
ERR_FAIL_V_MSG(ret, "Could not create child process: " + command);
|
||||||
}
|
}
|
||||||
|
@ -962,7 +992,7 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||||
String path = p_path.replace("/", "\\");
|
String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path;
|
||||||
String command = _quote_command_line_argument(path);
|
String command = _quote_command_line_argument(path);
|
||||||
for (const String &E : p_arguments) {
|
for (const String &E : p_arguments) {
|
||||||
command += " " + _quote_command_line_argument(E);
|
command += " " + _quote_command_line_argument(E);
|
||||||
|
@ -1000,7 +1030,19 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
||||||
creation_flags |= CREATE_NO_WINDOW;
|
creation_flags |= CREATE_NO_WINDOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, inherit_handles, creation_flags, nullptr, nullptr, si_w, &pi.pi);
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
if (current_dir_name.size() >= MAX_PATH) {
|
||||||
|
Char16String current_short_dir_name;
|
||||||
|
str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0);
|
||||||
|
current_short_dir_name.resize(str_len);
|
||||||
|
GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size());
|
||||||
|
current_dir_name = current_short_dir_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, inherit_handles, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi);
|
||||||
if (!ret && r_pipe) {
|
if (!ret && r_pipe) {
|
||||||
CloseHandle(pipe[0]); // Cleanup pipe handles.
|
CloseHandle(pipe[0]); // Cleanup pipe handles.
|
||||||
CloseHandle(pipe[1]);
|
CloseHandle(pipe[1]);
|
||||||
|
@ -1064,7 +1106,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
|
Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
|
||||||
String path = p_path.replace("/", "\\");
|
String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path;
|
||||||
String command = _quote_command_line_argument(path);
|
String command = _quote_command_line_argument(path);
|
||||||
for (const String &E : p_arguments) {
|
for (const String &E : p_arguments) {
|
||||||
command += " " + _quote_command_line_argument(E);
|
command += " " + _quote_command_line_argument(E);
|
||||||
|
@ -1083,7 +1125,19 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
|
||||||
creation_flags |= CREATE_NO_WINDOW;
|
creation_flags |= CREATE_NO_WINDOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, creation_flags, nullptr, nullptr, si_w, &pi.pi);
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
if (current_dir_name.size() >= MAX_PATH) {
|
||||||
|
Char16String current_short_dir_name;
|
||||||
|
str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0);
|
||||||
|
current_short_dir_name.resize(str_len);
|
||||||
|
GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size());
|
||||||
|
current_dir_name = current_short_dir_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi);
|
||||||
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
|
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
|
||||||
|
|
||||||
ProcessID pid = pi.pi.dwProcessId;
|
ProcessID pid = pi.pi.dwProcessId;
|
||||||
|
@ -1451,8 +1505,8 @@ Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_na
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR file_path[MAX_PATH];
|
WCHAR file_path[32767];
|
||||||
hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], MAX_PATH);
|
hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], 32767);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1530,8 +1584,8 @@ String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR file_path[MAX_PATH];
|
WCHAR file_path[32767];
|
||||||
hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], MAX_PATH);
|
hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], 32767);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1637,7 +1691,7 @@ Error OS_Windows::shell_show_in_file_manager(String p_path, bool p_open_folder)
|
||||||
if (!p_path.is_quoted()) {
|
if (!p_path.is_quoted()) {
|
||||||
p_path = p_path.quote();
|
p_path = p_path.quote();
|
||||||
}
|
}
|
||||||
p_path = p_path.replace("/", "\\");
|
p_path = fix_path(p_path);
|
||||||
|
|
||||||
INT_PTR ret = OK;
|
INT_PTR ret = OK;
|
||||||
if (open_folder) {
|
if (open_folder) {
|
||||||
|
@ -1962,6 +2016,19 @@ String OS_Windows::get_system_ca_certificates() {
|
||||||
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
||||||
hInstance = _hInstance;
|
hInstance = _hInstance;
|
||||||
|
|
||||||
|
// Reset CWD to ensure long path is used.
|
||||||
|
Char16String current_dir_name;
|
||||||
|
size_t str_len = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
current_dir_name.resize(str_len + 1);
|
||||||
|
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
|
||||||
|
|
||||||
|
Char16String new_current_dir_name;
|
||||||
|
str_len = GetLongPathNameW((LPCWSTR)current_dir_name.get_data(), nullptr, 0);
|
||||||
|
new_current_dir_name.resize(str_len + 1);
|
||||||
|
GetLongPathNameW((LPCWSTR)current_dir_name.get_data(), (LPWSTR)new_current_dir_name.ptrw(), new_current_dir_name.size());
|
||||||
|
|
||||||
|
SetCurrentDirectoryW((LPCWSTR)new_current_dir_name.get_data());
|
||||||
|
|
||||||
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
|
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
|
||||||
RedirectIOToConsole();
|
RedirectIOToConsole();
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue