feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
@ -23,6 +24,7 @@ common_win = [
"gl_manager_windows_angle.cpp",
"wgl_detect_version.cpp",
"rendering_context_driver_vulkan_windows.cpp",
"drop_target_windows.cpp",
]
if env.msvc:
@ -58,6 +60,9 @@ sources += res_obj
prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"])
arrange_program_clean(prog)
if env.msvc:
env.Depends(prog, "godot.natvis")
# Build console wrapper app.
if env["windows_subsystem"] == "gui":
env_wrap = env.Clone()
@ -78,16 +83,6 @@ if env["windows_subsystem"] == "gui":
env_wrap.Depends(prog_wrap, prog)
sources += common_win_wrap + res_wrap_obj
# Microsoft Visual Studio Project Generation
if env["vsproj"]:
env.vs_srcs += ["platform/windows/" + res_file]
env.vs_srcs += ["platform/windows/godot.natvis"]
for x in common_win:
env.vs_srcs += ["platform/windows/" + str(x)]
if env["windows_subsystem"] == "gui":
for x in common_win_wrap:
env.vs_srcs += ["platform/windows/" + str(x)]
if env["d3d12"]:
dxc_target_aliases = {
"x86_32": "x86",

View file

@ -40,8 +40,8 @@
int main(int argc, char *argv[]) {
// Get executable name.
WCHAR exe_name[MAX_PATH] = {};
if (!GetModuleFileNameW(nullptr, exe_name, MAX_PATH)) {
WCHAR exe_name[32767] = {};
if (!GetModuleFileNameW(nullptr, exe_name, 32767)) {
wprintf(L"GetModuleFileName failed, error %d\n", GetLastError());
return -1;
}
@ -65,7 +65,9 @@ int main(int argc, char *argv[]) {
// Enable virtual terminal sequences processing.
HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD out_mode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
DWORD out_mode = 0;
GetConsoleMode(stdout_handle, &out_mode);
out_mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(stdout_handle, out_mode);
// Find main executable name and check if it exist.

View file

@ -51,7 +51,7 @@ public:
void initialize();
void disable();
bool is_disabled() const { return disabled; };
bool is_disabled() const { return disabled; }
CrashHandler();
~CrashHandler();

View file

@ -118,7 +118,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
HANDLE process = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
DWORD offset_from_symbol = 0;
IMAGEHLP_LINE64 line = { 0 };
IMAGEHLP_LINE64 line = {};
std::vector<module_data> modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);

View file

@ -159,12 +159,18 @@ extern void CrashHandlerException(int signal) {
// Load process and image info to determine ASLR addresses offset.
MODULEINFO mi;
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &mi, sizeof(mi));
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &mi, sizeof(mi));
int64_t image_mem_base = reinterpret_cast<int64_t>(mi.lpBaseOfDll);
int64_t image_file_base = get_image_base(_execpath);
data.offset = image_mem_base - image_file_base;
data.state = backtrace_create_state(_execpath.utf8().get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));
if (FileAccess::exists(_execpath + ".debugsymbols")) {
_execpath = _execpath + ".debugsymbols";
}
_execpath = _execpath.replace("/", "\\");
CharString cs = _execpath.utf8(); // Note: should remain in scope during backtrace_simple call.
data.state = backtrace_create_state(cs.get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));
if (data.state != nullptr) {
data.index = 1;
backtrace_simple(data.state, 1, &trace_callback, &error_callback, reinterpret_cast<void *>(&data));

View file

@ -6,47 +6,40 @@ from typing import TYPE_CHECKING
import methods
from methods import print_error, print_warning
from platform_methods import detect_arch
from platform_methods import detect_arch, validate_arch
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
# To match other platforms
STACK_SIZE = 8388608
STACK_SIZE_SANITIZERS = 30 * 1024 * 1024
def get_name():
return "Windows"
def try_cmd(test, prefix, arch):
def try_cmd(test, prefix, arch, check_clang=False):
archs = ["x86_64", "x86_32", "arm64", "arm32"]
if arch:
archs = [arch]
for a in archs:
try:
out = subprocess.Popen(
get_mingw_bin_prefix(prefix, arch) + test,
get_mingw_bin_prefix(prefix, a) + test,
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
out.communicate()
outs, errs = out.communicate()
if out.returncode == 0:
if check_clang and not outs.startswith(b"clang"):
return False
return True
except Exception:
pass
else:
for a in ["x86_64", "x86_32", "arm64", "arm32"]:
try:
out = subprocess.Popen(
get_mingw_bin_prefix(prefix, a) + test,
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
out.communicate()
if out.returncode == 0:
return True
except Exception:
pass
return False
@ -75,23 +68,23 @@ def can_build():
def get_mingw_bin_prefix(prefix, arch):
if not prefix:
mingw_bin_prefix = ""
elif prefix[-1] != "/":
mingw_bin_prefix = prefix + "/bin/"
else:
mingw_bin_prefix = prefix + "bin/"
bin_prefix = (os.path.normpath(os.path.join(prefix, "bin")) + os.sep) if prefix else ""
ARCH_PREFIXES = {
"x86_64": "x86_64-w64-mingw32-",
"x86_32": "i686-w64-mingw32-",
"arm32": "armv7-w64-mingw32-",
"arm64": "aarch64-w64-mingw32-",
}
arch_prefix = ARCH_PREFIXES[arch] if arch else ""
return bin_prefix + arch_prefix
if arch == "x86_64":
mingw_bin_prefix += "x86_64-w64-mingw32-"
elif arch == "x86_32":
mingw_bin_prefix += "i686-w64-mingw32-"
elif arch == "arm32":
mingw_bin_prefix += "armv7-w64-mingw32-"
elif arch == "arm64":
mingw_bin_prefix += "aarch64-w64-mingw32-"
return mingw_bin_prefix
def get_detected(env: "SConsEnvironment", tool: str) -> str:
checks = [
get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) + tool,
get_mingw_bin_prefix(env["mingw_prefix"], "") + tool,
]
return str(env.Detect(checks))
def detect_build_env_arch():
@ -162,6 +155,13 @@ def detect_build_env_arch():
return ""
def get_tools(env: "SConsEnvironment"):
if os.name != "nt" or env["use_mingw"]:
return ["mingw"]
else:
return ["default"]
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
@ -203,6 +203,7 @@ def get_opts():
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
BoolVariable("use_ubsan", "Use LLVM compiler undefined behavior sanitizer (UBSAN)", False),
BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False),
BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting any errors to stderr.", True),
@ -247,45 +248,10 @@ def get_flags():
return {
"arch": arch,
"supported": ["mono"],
"supported": ["d3d12", "mono", "xaudio2"],
}
def build_res_file(target, source, env: "SConsEnvironment"):
arch_aliases = {
"x86_32": "pe-i386",
"x86_64": "pe-x86-64",
"arm32": "armv7-w64-mingw32",
"arm64": "aarch64-w64-mingw32",
}
cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]]
mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
for x in range(len(source)):
ok = True
# Try prefixed executable (MinGW on Linux).
cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
ok = False
except Exception:
ok = False
# Try generic executable (MSYS2).
if not ok:
cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
return -1
except Exception:
return -1
return 0
def setup_msvc_manual(env: "SConsEnvironment"):
"""Running from VCVARS environment"""
@ -387,7 +353,19 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
## Compile/link flags
env["MAXLINELENGTH"] = 8192 # Windows Vista and beyond, so always applicable.
if env["use_llvm"]:
env["CC"] = "clang-cl"
env["CXX"] = "clang-cl"
env["LINK"] = "lld-link"
env["AR"] = "llvm-lib"
env.AppendUnique(CPPDEFINES=["R128_STDC_ONLY"])
env.extra_suffix = ".llvm" + env.extra_suffix
# Ensure intellisense tools like `compile_commands.json` play nice with MSVC syntax.
env["CPPDEFPREFIX"] = "-D"
env["INCPREFIX"] = "-I"
env.AppendUnique(CPPDEFINES=[("alloca", "_alloca")])
if env["silence_msvc"] and not env.GetOption("clean"):
from tempfile import mkstemp
@ -471,7 +449,6 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
# Once it was thought that only debug builds would be too large,
# but this has recently stopped being true. See the mingw function
# for notes on why this shouldn't be enabled for gcc
@ -483,9 +460,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
else:
print_warning("Missing environment variable: WindowsSdkDir")
if int(env["target_win_version"], 16) < 0x0601:
print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
sys.exit(255)
validate_win_version(env)
env.AppendUnique(
CPPDEFINES=[
@ -507,6 +482,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if env["use_asan"]:
env.extra_suffix += ".san"
prebuilt_lib_extra_suffix = ".san"
env.AppendUnique(CPPDEFINES=["SANITIZERS_ENABLED"])
env.Append(CCFLAGS=["/fsanitize=address"])
env.Append(LINKFLAGS=["/INFERASANLIBS"])
@ -548,15 +524,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
LIBS += ["vulkan"]
if env["d3d12"]:
# Check whether we have d3d12 dependencies installed.
if not os.path.exists(env["mesa_libs"]):
print_error(
"The Direct3D 12 rendering driver requires dependencies to be installed.\n"
"You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
"See the documentation for more information:\n\t"
"https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
)
sys.exit(255)
check_d3d12_installed(env)
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
LIBS += ["dxgi", "dxguid"]
@ -595,6 +563,9 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if env["target"] in ["editor", "template_debug"]:
LIBS += ["psapi", "dbghelp"]
if env["use_llvm"]:
LIBS += [f"clang_rt.builtins-{env['arch']}"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
if vcvars_msvc_config:
@ -610,14 +581,20 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if env["lto"] != "none":
if env["lto"] == "thin":
print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
env.AppendUnique(CCFLAGS=["/GL"])
env.AppendUnique(ARFLAGS=["/LTCG"])
if not env["use_llvm"]:
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
env.AppendUnique(CCFLAGS=["-flto=thin"])
elif env["use_llvm"]:
env.AppendUnique(CCFLAGS=["-flto"])
else:
env.AppendUnique(CCFLAGS=["/GL"])
if env["progress"]:
env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"])
else:
env.AppendUnique(LINKFLAGS=["/LTCG"])
env.AppendUnique(ARFLAGS=["/LTCG"])
if vcvars_msvc_config:
env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")])
@ -628,7 +605,77 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
env["BUILDERS"]["Program"] = methods.precious_program
env.Append(LINKFLAGS=["/NATVIS:platform\\windows\\godot.natvis"])
env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
if env["use_asan"]:
env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE_SANITIZERS)])
else:
env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
def get_ar_version(env):
ret = {
"major": -1,
"minor": -1,
"patch": -1,
"is_llvm": False,
}
try:
output = (
subprocess.check_output([env.subst(env["AR"]), "--version"], shell=(os.name == "nt"))
.strip()
.decode("utf-8")
)
except (subprocess.CalledProcessError, OSError):
print_warning("Couldn't check version of `ar`.")
return ret
match = re.search(r"GNU ar(?: \(GNU Binutils\)| version) (\d+)\.(\d+)(?:\.(\d+))?", output)
if match:
ret["major"] = int(match[1])
ret["minor"] = int(match[2])
if match[3]:
ret["patch"] = int(match[3])
else:
ret["patch"] = 0
return ret
match = re.search(r"LLVM version (\d+)\.(\d+)\.(\d+)", output)
if match:
ret["major"] = int(match[1])
ret["minor"] = int(match[2])
ret["patch"] = int(match[3])
ret["is_llvm"] = True
return ret
print_warning("Couldn't parse version of `ar`.")
return ret
def get_is_ar_thin_supported(env):
"""Check whether `ar --thin` is supported. It is only supported since Binutils 2.38 or LLVM 14."""
ar_version = get_ar_version(env)
if ar_version["major"] == -1:
return False
if ar_version["is_llvm"]:
return ar_version["major"] >= 14
if ar_version["major"] == 2:
return ar_version["minor"] >= 38
print_warning("Unknown Binutils `ar` version.")
return False
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
def tempfile_arg_esc_func(arg):
from SCons.Subst import quote_spaces
arg = quote_spaces(arg)
# GCC requires double Windows slashes, let's use UNIX separator
return WINPATHSEP_RE.sub(r"/\1", arg)
def configure_mingw(env: "SConsEnvironment"):
@ -636,6 +683,20 @@ def configure_mingw(env: "SConsEnvironment"):
# https://www.scons.org/wiki/LongCmdLinesOnWin32
env.use_windows_spawn_fix()
# HACK: For some reason, Windows-native shells have their MinGW tools
# frequently fail as a result of parsing path separators incorrectly.
# For some other reason, this issue is circumvented entirely if the
# `mingw_prefix` bin is prepended to PATH.
if os.sep == "\\":
env.PrependENVPath("PATH", os.path.join(env["mingw_prefix"], "bin"))
# In case the command line to AR is too long, use a response file.
env["ARCOM_ORIG"] = env["ARCOM"]
env["ARCOM"] = "${TEMPFILE('$ARCOM_ORIG', '$ARCOMSTR')}"
env["TEMPFILESUFFIX"] = ".rsp"
if os.name == "nt":
env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func
## Build type
if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]):
@ -644,11 +705,11 @@ def configure_mingw(env: "SConsEnvironment"):
if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]):
env["use_llvm"] = False
# TODO: Re-evaluate the need for this / streamline with common config.
if env["target"] == "template_release":
if env["arch"] != "arm64":
env.Append(CCFLAGS=["-msse2"])
elif env.dev_build:
if not env["use_llvm"] and try_cmd("gcc --version", env["mingw_prefix"], env["arch"], True):
print("Detected GCC to be a wrapper for Clang.")
env["use_llvm"] = True
if env.dev_build:
# Allow big objects. It's supposed not to have drawbacks but seems to break
# GCC LTO, so enabling for debug builds only (which are not built with LTO
# and are the only ones with too big objects).
@ -662,9 +723,6 @@ def configure_mingw(env: "SConsEnvironment"):
## Compiler configuration
if os.name != "nt":
env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
if env["arch"] == "x86_32":
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static"])
@ -679,33 +737,36 @@ def configure_mingw(env: "SConsEnvironment"):
env.Append(CCFLAGS=["-ffp-contract=off"])
mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
if env["use_llvm"]:
env["CC"] = mingw_bin_prefix + "clang"
env["CXX"] = mingw_bin_prefix + "clang++"
if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
env["AS"] = mingw_bin_prefix + "as"
env.Append(ASFLAGS=["-c"])
if try_cmd("ar --version", env["mingw_prefix"], env["arch"]):
env["AR"] = mingw_bin_prefix + "ar"
if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]):
env["RANLIB"] = mingw_bin_prefix + "ranlib"
env["CC"] = get_detected(env, "clang")
env["CXX"] = get_detected(env, "clang++")
env["AR"] = get_detected(env, "ar")
env["RANLIB"] = get_detected(env, "ranlib")
env.Append(ASFLAGS=["-c"])
env.extra_suffix = ".llvm" + env.extra_suffix
else:
env["CC"] = mingw_bin_prefix + "gcc"
env["CXX"] = mingw_bin_prefix + "g++"
if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
env["AS"] = mingw_bin_prefix + "as"
if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
env["AR"] = mingw_bin_prefix + "gcc-ar"
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
env["CC"] = get_detected(env, "gcc")
env["CXX"] = get_detected(env, "g++")
env["AR"] = get_detected(env, "gcc-ar" if os.name != "nt" else "ar")
env["RANLIB"] = get_detected(env, "gcc-ranlib")
env["RC"] = get_detected(env, "windres")
ARCH_TARGETS = {
"x86_32": "pe-i386",
"x86_64": "pe-x86-64",
"arm32": "armv7-w64-mingw32",
"arm64": "aarch64-w64-mingw32",
}
env.AppendUnique(RCFLAGS=f"--target={ARCH_TARGETS[env['arch']]}")
env["AS"] = get_detected(env, "as")
env["OBJCOPY"] = get_detected(env, "objcopy")
env["STRIP"] = get_detected(env, "strip")
## LTO
if env["lto"] == "auto": # Full LTO for production with MinGW.
env["lto"] = "full"
if env["lto"] == "auto": # Enable LTO for production with MinGW.
env["lto"] = "thin" if env["use_llvm"] else "full"
if env["lto"] != "none":
if env["lto"] == "thin":
@ -720,18 +781,47 @@ def configure_mingw(env: "SConsEnvironment"):
else:
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
if not env["use_llvm"]:
# For mingw-gcc LTO, disable linker plugin and enable whole program to work around GH-102867.
env.Append(CCFLAGS=["-fno-use-linker-plugin", "-fwhole-program"])
env.Append(LINKFLAGS=["-fno-use-linker-plugin", "-fwhole-program"])
env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
if env["use_asan"]:
env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE_SANITIZERS)])
else:
env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
## Compile flags
if int(env["target_win_version"], 16) < 0x0601:
print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
sys.exit(255)
validate_win_version(env)
if not env["use_llvm"]:
env.Append(CCFLAGS=["-mwindows"])
if env["use_asan"] or env["use_ubsan"]:
if not env["use_llvm"]:
print("GCC does not support sanitizers on Windows.")
sys.exit(255)
if env["arch"] not in ["x86_32", "x86_64"]:
print("Sanitizers are only supported for x86_32 and x86_64.")
sys.exit(255)
env.extra_suffix += ".san"
env.AppendUnique(CPPDEFINES=["SANITIZERS_ENABLED"])
san_flags = []
if env["use_asan"]:
san_flags.append("-fsanitize=address")
if env["use_ubsan"]:
san_flags.append("-fsanitize=undefined")
# Disable the vptr check since it gets triggered on any COM interface calls.
san_flags.append("-fno-sanitize=vptr")
env.Append(CFLAGS=san_flags)
env.Append(CCFLAGS=san_flags)
env.Append(LINKFLAGS=san_flags)
if get_is_ar_thin_supported(env):
env.Append(ARFLAGS=["--thin"])
env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"])
env.Append(
CPPDEFINES=[
@ -778,15 +868,7 @@ def configure_mingw(env: "SConsEnvironment"):
env.Append(LIBS=["vulkan"])
if env["d3d12"]:
# Check whether we have d3d12 dependencies installed.
if not os.path.exists(env["mesa_libs"]):
print_error(
"The Direct3D 12 rendering driver requires dependencies to be installed.\n"
"You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
"See the documentation for more information:\n\t"
"https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
)
sys.exit(255)
check_d3d12_installed(env)
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
env.Append(LIBS=["dxgi", "dxguid"])
@ -822,19 +904,11 @@ def configure_mingw(env: "SConsEnvironment"):
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
# resrc
env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")})
def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
if env["arch"] not in supported_arches:
print_error(
'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
sys.exit(255)
validate_arch(env["arch"], get_name(), supported_arches)
# At this point the env has been set up with basic tools/compilers.
env.Prepend(CPPPATH=["#platform/windows"])
@ -862,3 +936,20 @@ def configure(env: "SConsEnvironment"):
else: # MinGW
configure_mingw(env)
def check_d3d12_installed(env):
if not os.path.exists(env["mesa_libs"]):
print_error(
"The Direct3D 12 rendering driver requires dependencies to be installed.\n"
"You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
"See the documentation for more information:\n\t"
"https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
)
sys.exit(255)
def validate_win_version(env):
if int(env["target_win_version"], 16) < 0x0601:
print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
sys.exit(255)

File diff suppressed because it is too large Load diff

View file

@ -38,8 +38,8 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "servers/audio_server.h"
@ -167,7 +167,7 @@ typedef bool(WINAPI *ShouldAppsUseDarkModePtr)();
typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name);
typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail);
typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOW *lpVersionInformation);
typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOEXW *lpVersionInformation);
typedef bool(WINAPI *AllowDarkModeForAppPtr)(bool darkMode);
typedef PreferredAppMode(WINAPI *SetPreferredAppModePtr)(PreferredAppMode appMode);
typedef void(WINAPI *RefreshImmersiveColorPolicyStatePtr)();
@ -350,9 +350,27 @@ typedef struct {
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_DPI_UNAWARE = 0,
SHC_PROCESS_SYSTEM_DPI_AWARE = 1,
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2,
} SHC_PROCESS_DPI_AWARENESS;
#ifndef WS_EX_NOREDIRECTIONBITMAP
#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
#endif
class DropTargetWindows;
#ifndef WDA_EXCLUDEFROMCAPTURE
#define WDA_EXCLUDEFROMCAPTURE 0x00000011
#endif
class DisplayServerWindows : public DisplayServer {
// No need to register with GDCLASS, it's platform-specific and nothing is added.
friend class DropTargetWindows;
_THREAD_SAFE_CLASS_
// UXTheme API
@ -387,12 +405,23 @@ class DisplayServerWindows : public DisplayServer {
void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver);
String tablet_driver;
Vector<String> tablet_drivers;
bool winink_disabled = false;
enum DriverID {
DRIVER_ID_COMPAT_OPENGL3 = 1 << 0,
DRIVER_ID_COMPAT_ANGLE_D3D11 = 1 << 1,
DRIVER_ID_RD_VULKAN = 1 << 2,
DRIVER_ID_RD_D3D12 = 1 << 3,
};
static BitField<DriverID> tested_drivers;
enum TimerID {
TIMER_ID_MOVE_REDRAW = 1,
TIMER_ID_WINDOW_ACTIVATION = 2,
};
OSVERSIONINFOEXW os_ver;
enum {
KEY_EVENT_BUFFER_SIZE = 512
};
@ -453,12 +482,17 @@ class DisplayServerWindows : public DisplayServer {
bool resizable = true;
bool window_focused = false;
int activate_state = 0;
bool was_maximized_pre_fs = false;
bool was_fullscreen_pre_min = false;
bool first_activation_done = false;
bool was_maximized = false;
bool always_on_top = false;
bool no_focus = false;
bool exclusive = false;
bool context_created = false;
bool mpass = false;
bool sharp_corners = false;
bool hide_from_capture = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
@ -505,11 +539,18 @@ class DisplayServerWindows : public DisplayServer {
Callable input_text_callback;
Callable drop_files_callback;
// OLE API
DropTargetWindows *drop_target = nullptr;
WindowID transient_parent = INVALID_WINDOW_ID;
HashSet<WindowID> transient_children;
bool is_popup = false;
Rect2i parent_safe_rect;
bool initialized = false;
HWND parent_hwnd = 0;
};
JoypadWindows *joypad = nullptr;
@ -518,12 +559,12 @@ class DisplayServerWindows : public DisplayServer {
uint64_t time_since_popup = 0;
Ref<Image> icon;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent);
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent, HWND p_parent_hwnd);
WindowID window_id_counter = MAIN_WINDOW_ID;
RBMap<WindowID, WindowData> windows;
WindowID last_focused_window = INVALID_WINDOW_ID;
WindowID last_mouse_button_down_window = INVALID_WINDOW_ID;
HCURSOR hCursor;
WNDPROC user_proc = nullptr;
@ -536,15 +577,54 @@ class DisplayServerWindows : public DisplayServer {
IndicatorID indicator_id_counter = 0;
HashMap<IndicatorID, IndicatorData> indicators;
struct FileDialogData {
HWND hwnd_owner = 0;
Rect2i wrect;
String appid;
String title;
String current_directory;
String root;
String filename;
bool show_hidden = false;
DisplayServer::FileDialogMode mode = FileDialogMode::FILE_DIALOG_MODE_OPEN_ANY;
Vector<String> filters;
TypedArray<Dictionary> options;
WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
Callable callback;
bool options_in_cb = false;
Thread listener_thread;
SafeFlag close_requested;
SafeFlag finished;
};
Mutex file_dialog_mutex;
List<FileDialogData *> file_dialogs;
HashMap<HWND, FileDialogData *> file_dialog_wnd;
struct FileDialogCallback {
Callable callback;
Variant status;
Variant files;
Variant index;
Variant options;
bool opt_in_cb = false;
};
List<FileDialogCallback> pending_cbs;
void process_file_dialog_callbacks();
static void _thread_fd_monitor(void *p_ud);
HashMap<int64_t, MouseButton> pointer_prev_button;
HashMap<int64_t, MouseButton> pointer_button;
HashMap<int64_t, LONG> pointer_down_time;
HashMap<int64_t, Vector2> pointer_last_pos;
void _send_window_event(const WindowData &wd, WindowEvent p_event);
void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
void _get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, DWORD &r_style, DWORD &r_style_ex);
MouseMode mouse_mode;
MouseMode mouse_mode_base = MOUSE_MODE_VISIBLE;
MouseMode mouse_mode_override = MOUSE_MODE_VISIBLE;
bool mouse_mode_override_enabled = false;
void _mouse_update_mode();
int restore_mouse_trails = 0;
bool use_raw_input = false;
@ -564,6 +644,8 @@ class DisplayServerWindows : public DisplayServer {
void _drag_event(WindowID p_window, float p_x, float p_y, int idx);
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
bool _is_always_on_top_recursive(WindowID p_window) const;
void _update_window_style(WindowID p_window, bool p_repaint = true);
void _update_window_mouse_passthrough(WindowID p_window);
@ -596,7 +678,17 @@ class DisplayServerWindows : public DisplayServer {
String _get_keyboard_layout_display_name(const String &p_klid) const;
String _get_klid(HKL p_hkl) const;
struct EmbeddedProcessData {
HWND window_handle = 0;
HWND parent_window_handle = 0;
bool is_visible = false;
};
HashMap<OS::ProcessID, EmbeddedProcessData *> embedded_processes;
HWND _find_window_from_process_id(OS::ProcessID p_pid, HWND p_current_hwnd);
public:
LRESULT WndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
@ -624,8 +716,14 @@ public:
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
virtual void beep() const override;
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
virtual void mouse_set_mode_override(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode_override() const override;
virtual void mouse_set_mode_override_enabled(bool p_override_enabled) override;
virtual bool mouse_is_mode_override_enabled() const override;
virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
@ -647,6 +745,7 @@ public:
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Color screen_get_pixel(const Point2i &p_position) const override;
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Ref<Image> screen_get_image_rect(const Rect2i &p_rect) const override;
virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver
virtual bool screen_is_kept_on() const override;
@ -728,6 +827,9 @@ public:
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_start_resize(WindowResizeEdge p_edge, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void cursor_set_shape(CursorShape p_shape) override;
virtual CursorShape cursor_get_shape() const override;
virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
@ -735,6 +837,10 @@ public:
virtual bool get_swap_cancel_ok() override;
virtual void enable_for_stealing_focus(OS::ProcessID pid) override;
virtual Error embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) override;
virtual Error request_close_embedded_process(OS::ProcessID p_pid) override;
virtual Error remove_embedded_process(OS::ProcessID p_pid) override;
virtual OS::ProcessID get_focused_process_id() override;
virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override;
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override;
@ -746,6 +852,7 @@ public:
virtual String keyboard_get_layout_name(int p_index) const override;
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
virtual void show_emoji_and_symbol_picker() const override;
virtual int tablet_get_driver_count() const override;
virtual String tablet_get_driver_name(int p_driver) const override;
@ -774,11 +881,11 @@ public:
virtual bool is_window_transparency_available() const override;
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_windows_driver();
DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error);
~DisplayServerWindows();
};

View file

@ -55,7 +55,6 @@
<member name="binary_format/architecture" type="String" setter="" getter="">
Application executable architecture.
Supported architectures: [code]x86_32[/code], [code]x86_64[/code], and [code]arm64[/code].
Official export templates include [code]x86_32[/code] and [code]x86_64[/code] binaries only.
</member>
<member name="binary_format/embed_pck" type="bool" setter="" getter="">
If [code]true[/code], project resources are embedded into the executable.

View file

@ -0,0 +1,375 @@
/**************************************************************************/
/* drop_target_windows.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "drop_target_windows.h"
#include "core/io/dir_access.h"
#include "core/math/random_pcg.h"
#include "core/os/time.h"
#include <fileapi.h>
// Helpers
static String create_temp_dir() {
Char16String buf;
int bufsize = GetTempPathW(0, nullptr) + 1;
buf.resize(bufsize);
if (GetTempPathW(bufsize, (LPWSTR)buf.ptrw()) == 0) {
return "";
}
String tmp_dir = String::utf16((const char16_t *)buf.ptr());
RandomPCG gen(Time::get_singleton()->get_ticks_usec());
const int attempts = 4;
for (int i = 0; i < attempts; ++i) {
uint32_t rnd = gen.rand();
String dirname = "godot_tmp_" + String::num_uint64(rnd);
String res_dir = tmp_dir.path_join(dirname);
Char16String res_dir16 = res_dir.utf16();
if (CreateDirectoryW((LPCWSTR)res_dir16.ptr(), nullptr)) {
return res_dir;
}
}
return "";
}
static bool remove_dir_recursive(const String &p_dir) {
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (dir_access->change_dir(p_dir) != OK) {
return false;
}
return dir_access->erase_contents_recursive() == OK;
}
static bool stream2file(IStream *p_stream, FILEDESCRIPTORW *p_desc, const String &p_path) {
if (DirAccess::make_dir_recursive_absolute(p_path.get_base_dir()) != OK) {
return false;
}
Char16String path16 = p_path.utf16();
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
if (p_desc->dwFlags & FD_ATTRIBUTES) {
dwFlagsAndAttributes = p_desc->dwFileAttributes;
}
HANDLE file = CreateFileW(
(LPCWSTR)path16.ptr(),
GENERIC_WRITE,
0,
nullptr,
CREATE_NEW,
dwFlagsAndAttributes,
nullptr);
if (!file) {
return false;
}
const int bufsize = 4096;
char buf[bufsize];
ULONG nread = 0;
DWORD nwritten = 0;
HRESULT read_result = S_OK;
bool result = true;
while (true) {
read_result = p_stream->Read(buf, bufsize, &nread);
if (read_result != S_OK && read_result != S_FALSE) {
result = false;
goto cleanup;
}
if (!nread) {
break;
}
while (nread > 0) {
if (!WriteFile(file, buf, nread, &nwritten, nullptr) || !nwritten) {
result = false;
goto cleanup;
}
nread -= nwritten;
}
}
cleanup:
CloseHandle(file);
return result;
}
// DropTargetWindows
bool DropTargetWindows::is_valid_filedescriptor() {
return cf_filedescriptor != 0 && cf_filecontents != 0;
}
HRESULT DropTargetWindows::handle_hdrop_format(Vector<String> *p_files, IDataObject *pDataObj) {
FORMATETC fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg;
HRESULT res = S_OK;
if (pDataObj->GetData(&fmt, &stg) != S_OK) {
return E_UNEXPECTED;
}
HDROP hDropInfo = (HDROP)GlobalLock(stg.hGlobal);
Char16String buf;
if (hDropInfo == nullptr) {
ReleaseStgMedium(&stg);
return E_UNEXPECTED;
}
int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0);
for (int i = 0; i < fcount; i++) {
int buffsize = DragQueryFileW(hDropInfo, i, nullptr, 0);
buf.resize(buffsize + 1);
if (DragQueryFileW(hDropInfo, i, (LPWSTR)buf.ptrw(), buffsize + 1) == 0) {
res = E_UNEXPECTED;
goto cleanup;
}
String file = String::utf16((const char16_t *)buf.ptr());
p_files->push_back(file);
}
cleanup:
GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg);
return res;
}
HRESULT DropTargetWindows::handle_filedescriptor_format(Vector<String> *p_files, IDataObject *pDataObj) {
FORMATETC fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg;
HRESULT res = S_OK;
if (pDataObj->GetData(&fmt, &stg) != S_OK) {
return E_UNEXPECTED;
}
FILEGROUPDESCRIPTORW *filegroup_desc = (FILEGROUPDESCRIPTORW *)GlobalLock(stg.hGlobal);
if (!filegroup_desc) {
ReleaseStgMedium(&stg);
return E_UNEXPECTED;
}
tmp_path = create_temp_dir();
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
PackedStringArray copied;
if (dir_access->change_dir(tmp_path) != OK) {
res = E_UNEXPECTED;
goto cleanup;
}
for (int i = 0; i < (int)filegroup_desc->cItems; ++i) {
res = save_as_file(tmp_path, filegroup_desc->fgd + i, pDataObj, i);
if (res != S_OK) {
res = E_UNEXPECTED;
goto cleanup;
}
}
copied = dir_access->get_files();
for (const String &file : copied) {
p_files->push_back(tmp_path.path_join(file));
}
copied = dir_access->get_directories();
for (const String &dir : copied) {
p_files->push_back(tmp_path.path_join(dir));
}
cleanup:
GlobalUnlock(filegroup_desc);
ReleaseStgMedium(&stg);
if (res != S_OK) {
remove_dir_recursive(tmp_path);
tmp_path.clear();
}
return res;
}
HRESULT DropTargetWindows::save_as_file(const String &p_out_dir, FILEDESCRIPTORW *p_file_desc, IDataObject *pDataObj, int p_file_idx) {
String relpath = String::utf16((const char16_t *)p_file_desc->cFileName);
String fullpath = p_out_dir.path_join(relpath);
if (p_file_desc->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (DirAccess::make_dir_recursive_absolute(fullpath) != OK) {
return E_UNEXPECTED;
}
return S_OK;
}
FORMATETC fmt = { cf_filecontents, nullptr, DVASPECT_CONTENT, p_file_idx, TYMED_ISTREAM };
STGMEDIUM stg;
HRESULT res = S_OK;
if (pDataObj->GetData(&fmt, &stg) != S_OK) {
return E_UNEXPECTED;
}
IStream *stream = stg.pstm;
if (stream == nullptr) {
res = E_UNEXPECTED;
goto cleanup;
}
if (!stream2file(stream, p_file_desc, fullpath)) {
res = E_UNEXPECTED;
goto cleanup;
}
cleanup:
ReleaseStgMedium(&stg);
return res;
}
DropTargetWindows::DropTargetWindows(DisplayServerWindows::WindowData *p_window_data) :
ref_count(1), window_data(p_window_data) {
cf_filedescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
cf_filecontents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
}
HRESULT STDMETHODCALLTYPE DropTargetWindows::QueryInterface(REFIID riid, void **ppvObject) {
if (riid == IID_IUnknown || riid == IID_IDropTarget) {
*ppvObject = static_cast<IDropTarget *>(this);
AddRef();
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DropTargetWindows::AddRef() {
return InterlockedIncrement(&ref_count);
}
ULONG STDMETHODCALLTYPE DropTargetWindows::Release() {
ULONG count = InterlockedDecrement(&ref_count);
if (count == 0) {
memfree(this);
}
return count;
}
HRESULT STDMETHODCALLTYPE DropTargetWindows::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
(void)grfKeyState;
(void)pt;
FORMATETC hdrop_fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
FORMATETC filedesc_fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
if (!window_data->drop_files_callback.is_valid()) {
*pdwEffect = DROPEFFECT_NONE;
} else if (pDataObj->QueryGetData(&hdrop_fmt) == S_OK) {
*pdwEffect = DROPEFFECT_COPY;
} else if (is_valid_filedescriptor() && pDataObj->QueryGetData(&filedesc_fmt) == S_OK) {
*pdwEffect = DROPEFFECT_COPY;
} else {
*pdwEffect = DROPEFFECT_NONE;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE DropTargetWindows::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
(void)grfKeyState;
(void)pt;
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DropTargetWindows::DragLeave() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE DropTargetWindows::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
(void)grfKeyState;
(void)pt;
*pdwEffect = DROPEFFECT_NONE;
if (!window_data->drop_files_callback.is_valid()) {
return S_OK;
}
FORMATETC hdrop_fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
FORMATETC filedesc_fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
Vector<String> files;
if (pDataObj->QueryGetData(&hdrop_fmt) == S_OK) {
HRESULT res = handle_hdrop_format(&files, pDataObj);
if (res != S_OK) {
return res;
}
} else if (pDataObj->QueryGetData(&filedesc_fmt) == S_OK && is_valid_filedescriptor()) {
HRESULT res = handle_filedescriptor_format(&files, pDataObj);
if (res != S_OK) {
return res;
}
} else {
return E_UNEXPECTED;
}
if (!files.size()) {
return S_OK;
}
Variant v_files = files;
const Variant *v_args[1] = { &v_files };
Variant ret;
Callable::CallError ce;
window_data->drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
if (!tmp_path.is_empty()) {
remove_dir_recursive(tmp_path);
tmp_path.clear();
}
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(window_data->drop_files_callback, v_args, 1, ce)));
return E_UNEXPECTED;
}
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}

View file

@ -0,0 +1,77 @@
/**************************************************************************/
/* drop_target_windows.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DROP_TARGET_WINDOWS_H
#define DROP_TARGET_WINDOWS_H
#include "display_server_windows.h"
#include <shlobj.h>
// Silence warning due to a COM API weirdness.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
// https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-dodragdrop#remarks
class DropTargetWindows : public IDropTarget {
LONG ref_count;
DisplayServerWindows::WindowData *window_data = nullptr;
CLIPFORMAT cf_filedescriptor = 0;
CLIPFORMAT cf_filecontents = 0;
String tmp_path;
bool is_valid_filedescriptor();
HRESULT handle_hdrop_format(Vector<String> *p_files, IDataObject *pDataObj);
HRESULT handle_filedescriptor_format(Vector<String> *p_files, IDataObject *pDataObj);
HRESULT save_as_file(const String &p_out_dir, FILEDESCRIPTORW *p_file_desc, IDataObject *pDataObj, int p_file_idx);
public:
DropTargetWindows(DisplayServerWindows::WindowData *p_window_data);
virtual ~DropTargetWindows() {}
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
// IDropTarget
HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
HRESULT STDMETHODCALLTYPE DragLeave() override;
HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
};
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif // DROP_TARGET_WINDOWS_H

View file

@ -39,17 +39,18 @@ void register_windows_exporter_types() {
}
void register_windows_exporter() {
// TODO: Move to editor_settings.cpp
#ifndef ANDROID_ENABLED
EDITOR_DEF("export/windows/rcedit", "");
EDITOR_DEF_BASIC("export/windows/rcedit", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
#ifdef WINDOWS_ENABLED
EDITOR_DEF("export/windows/signtool", "");
EDITOR_DEF_BASIC("export/windows/signtool", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
#else
EDITOR_DEF("export/windows/osslsigncode", "");
EDITOR_DEF_BASIC("export/windows/osslsigncode", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/osslsigncode", PROPERTY_HINT_GLOBAL_FILE));
// On non-Windows we need WINE to run rcedit
EDITOR_DEF("export/windows/wine", "");
EDITOR_DEF_BASIC("export/windows/wine", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE));
#endif
#endif

View file

@ -41,10 +41,7 @@
#include "editor/export/editor_export.h"
#include "editor/themes/editor_scale.h"
#include "modules/modules_enabled.gen.h" // For svg.
#ifdef MODULE_SVG_ENABLED
#include "modules/svg/image_loader_svg.h"
#endif
Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
@ -96,10 +93,9 @@ Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &
f->seek(prev_offset);
}
} else {
Ref<Image> src_image;
src_image.instantiate();
err = ImageLoader::load_image(p_src_path, src_image);
ERR_FAIL_COND_V(err != OK || src_image->is_empty(), ERR_CANT_OPEN);
Ref<Image> src_image = _load_icon_or_splash_image(p_src_path, &err);
ERR_FAIL_COND_V(err != OK || src_image.is_null() || src_image->is_empty(), ERR_CANT_OPEN);
for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
int size = (icon_size[i] == 0) ? 256 : icon_size[i];
@ -167,7 +163,7 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
}
}
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags) {
if (p_preset->get("application/modify_resources")) {
_rcedit_add_data(p_preset, p_path, false);
String wrapper_path = p_path.get_basename() + ".console.exe";
@ -178,7 +174,7 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset>
return OK;
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags) {
String custom_debug = p_preset->get("custom_template/debug");
String custom_release = p_preset->get("custom_template/release");
String arch = p_preset->get("binary_format/architecture");
@ -187,53 +183,11 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
template_path = template_path.strip_edges();
if (template_path.is_empty()) {
template_path = find_export_template(get_template_file_name(p_debug ? "debug" : "release", arch));
}
int export_angle = p_preset->get("application/export_angle");
bool include_angle_libs = false;
if (export_angle == 0) {
include_angle_libs = (String(GLOBAL_GET("rendering/gl_compatibility/driver.windows")) == "opengl3_angle") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) == "gl_compatibility");
} else if (export_angle == 1) {
include_angle_libs = true;
}
if (include_angle_libs) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->file_exists(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"), p_path.get_base_dir().path_join("libEGL.dll"), get_chmod_flags());
}
if (da->file_exists(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"), p_path.get_base_dir().path_join("libGLESv2.dll"), get_chmod_flags());
}
}
int export_d3d12 = p_preset->get("application/export_d3d12");
bool agility_sdk_multiarch = p_preset->get("application/d3d12_agility_sdk_multiarch");
bool include_d3d12_extra_libs = false;
if (export_d3d12 == 0) {
include_d3d12_extra_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility");
} else if (export_d3d12 == 1) {
include_d3d12_extra_libs = true;
}
if (include_d3d12_extra_libs) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->file_exists(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"))) {
if (agility_sdk_multiarch) {
da->make_dir_recursive(p_path.get_base_dir().path_join(arch));
da->copy(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"), p_path.get_base_dir().path_join(arch).path_join("D3D12Core.dll"), get_chmod_flags());
} else {
da->copy(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"), p_path.get_base_dir().path_join("D3D12Core.dll"), get_chmod_flags());
}
}
if (da->file_exists(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"))) {
if (agility_sdk_multiarch) {
da->make_dir_recursive(p_path.get_base_dir().path_join(arch));
da->copy(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"), p_path.get_base_dir().path_join(arch).path_join("d3d12SDKLayers.dll"), get_chmod_flags());
} else {
da->copy(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"), p_path.get_base_dir().path_join("d3d12SDKLayers.dll"), get_chmod_flags());
}
}
if (da->file_exists(template_path.get_base_dir().path_join("WinPixEventRuntime." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("WinPixEventRuntime." + arch + ".dll"), p_path.get_base_dir().path_join("WinPixEventRuntime.dll"), get_chmod_flags());
} else {
String exe_arch = _get_exe_arch(template_path);
if (arch != exe_arch) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Mismatching custom export template executable architecture: found \"%s\", expected \"%s\"."), exe_arch, arch));
return ERR_CANT_CREATE;
}
}
@ -251,7 +205,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
// Setup temp folder.
String path = p_path;
String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
String tmp_dir_path = EditorPaths::get_singleton()->get_temp_dir().path_join(pkg_name);
Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
if (export_as_zip) {
if (tmp_app_dir.is_null()) {
@ -267,6 +221,54 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe");
}
int export_angle = p_preset->get("application/export_angle");
bool include_angle_libs = false;
if (export_angle == 0) {
include_angle_libs = (String(GLOBAL_GET("rendering/gl_compatibility/driver.windows")) == "opengl3_angle") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) == "gl_compatibility");
} else if (export_angle == 1) {
include_angle_libs = true;
}
if (include_angle_libs) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->file_exists(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"), path.get_base_dir().path_join("libEGL.dll"), get_chmod_flags());
}
if (da->file_exists(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"), path.get_base_dir().path_join("libGLESv2.dll"), get_chmod_flags());
}
}
int export_d3d12 = p_preset->get("application/export_d3d12");
bool agility_sdk_multiarch = p_preset->get("application/d3d12_agility_sdk_multiarch");
bool include_d3d12_extra_libs = false;
if (export_d3d12 == 0) {
include_d3d12_extra_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility");
} else if (export_d3d12 == 1) {
include_d3d12_extra_libs = true;
}
if (include_d3d12_extra_libs) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->file_exists(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"))) {
if (agility_sdk_multiarch) {
da->make_dir_recursive(path.get_base_dir().path_join(arch));
da->copy(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"), path.get_base_dir().path_join(arch).path_join("D3D12Core.dll"), get_chmod_flags());
} else {
da->copy(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"), path.get_base_dir().path_join("D3D12Core.dll"), get_chmod_flags());
}
}
if (da->file_exists(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"))) {
if (agility_sdk_multiarch) {
da->make_dir_recursive(path.get_base_dir().path_join(arch));
da->copy(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"), path.get_base_dir().path_join(arch).path_join("d3d12SDKLayers.dll"), get_chmod_flags());
} else {
da->copy(template_path.get_base_dir().path_join("d3d12SDKLayers." + arch + ".dll"), path.get_base_dir().path_join("d3d12SDKLayers.dll"), get_chmod_flags());
}
}
if (da->file_exists(template_path.get_base_dir().path_join("WinPixEventRuntime." + arch + ".dll"))) {
da->copy(template_path.get_base_dir().path_join("WinPixEventRuntime." + arch + ".dll"), path.get_base_dir().path_join("WinPixEventRuntime.dll"), get_chmod_flags());
}
}
// Export project.
String pck_path = path;
if (embedded) {
@ -343,7 +345,7 @@ String EditorExportPlatformWindows::get_export_option_warning(const EditorExport
PackedStringArray version_array = file_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || file_version.contains("-")) {
!version_array[3].is_valid_int() || file_version.contains_char('-')) {
return TTR("Invalid file version.");
}
}
@ -353,7 +355,7 @@ String EditorExportPlatformWindows::get_export_option_warning(const EditorExport
PackedStringArray version_array = product_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || product_version.contains("-")) {
!version_array[3].is_valid_int() || product_version.contains_char('-')) {
return TTR("Invalid product version.");
}
}
@ -392,7 +394,13 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
return false;
}
if (p_option == "dotnet/embed_build_outputs") {
if (p_option == "dotnet/embed_build_outputs" ||
p_option == "custom_template/debug" ||
p_option == "custom_template/release" ||
p_option == "application/d3d12_agility_sdk_multiarch" ||
p_option == "application/export_angle" ||
p_option == "application/export_d3d12" ||
p_option == "application/icon_interpolation") {
return advanced_options_enabled;
}
return true;
@ -431,7 +439,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
"$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
"$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n"
"$settings = New-ScheduledTaskSettingsSet\n"
"$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries\n"
"$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n"
"Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n"
"Start-ScheduledTask -TaskName godot_remote_debug\n"
@ -495,7 +503,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
}
}
String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico");
String tmp_icon_path = EditorPaths::get_singleton()->get_temp_dir().path_join("_rcedit.ico");
if (!icon_path.is_empty()) {
if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path));
@ -503,7 +511,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
}
}
String file_verion = p_preset->get_version("application/file_version", true);
String file_version = p_preset->get_version("application/file_version", true);
String product_version = p_preset->get_version("application/product_version", true);
String company_name = p_preset->get("application/company_name");
String product_name = p_preset->get("application/product_name");
@ -518,9 +526,9 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
args.push_back("--set-icon");
args.push_back(tmp_icon_path);
}
if (!file_verion.is_empty()) {
if (!file_version.is_empty()) {
args.push_back("--set-file-version");
args.push_back(file_verion);
args.push_back(file_version);
}
if (!product_version.is_empty()) {
args.push_back("--set-product-version");
@ -753,9 +761,26 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
}
bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err = "";
String err;
bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates, p_debug);
String custom_debug = p_preset->get("custom_template/debug").operator String().strip_edges();
String custom_release = p_preset->get("custom_template/release").operator String().strip_edges();
String arch = p_preset->get("binary_format/architecture");
if (!custom_debug.is_empty() && FileAccess::exists(custom_debug)) {
String exe_arch = _get_exe_arch(custom_debug);
if (arch != exe_arch) {
err += vformat(TTR("Mismatching custom debug export template executable architecture: found \"%s\", expected \"%s\"."), exe_arch, arch) + "\n";
}
}
if (!custom_release.is_empty() && FileAccess::exists(custom_release)) {
String exe_arch = _get_exe_arch(custom_release);
if (arch != exe_arch) {
err += vformat(TTR("Mismatching custom release export template executable architecture: found \"%s\", expected \"%s\"."), exe_arch, arch) + "\n";
}
}
String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
@ -769,7 +794,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito
}
bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
String err = "";
String err;
bool valid = true;
List<ExportOption> options;
@ -793,6 +818,43 @@ bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<Edit
return valid;
}
String EditorExportPlatformWindows::_get_exe_arch(const String &p_path) const {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
return "invalid";
}
// Jump to the PE header and check the magic number.
{
f->seek(0x3c);
uint32_t pe_pos = f->get_32();
f->seek(pe_pos);
uint32_t magic = f->get_32();
if (magic != 0x00004550) {
return "invalid";
}
}
// Process header.
uint16_t machine = f->get_16();
f->close();
switch (machine) {
case 0x014c:
return "x86_32";
case 0x8664:
return "x86_64";
case 0x01c0:
case 0x01c4:
return "arm32";
case 0xaa64:
return "arm64";
default:
return "unknown";
}
}
Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
// Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
@ -936,7 +998,7 @@ void EditorExportPlatformWindows::cleanup() {
cleanup_commands.clear();
}
Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, BitField<EditorExportPlatform::DebugFlags> p_debug_flags) {
cleanup();
if (p_device) { // Stop command, cleanup only.
return OK;
@ -944,7 +1006,7 @@ Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset,
EditorProgress ep("run", TTR("Running..."), 5);
const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows");
const String dest = EditorPaths::get_singleton()->get_temp_dir().path_join("windows");
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (!da->dir_exists(dest)) {
Error err = da->make_dir_recursive(dest);
@ -990,8 +1052,7 @@ Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset,
String cmd_args;
{
Vector<String> cmd_args_list;
gen_debug_flags(cmd_args_list, p_debug_flags);
Vector<String> cmd_args_list = gen_export_flags(p_debug_flags);
for (int i = 0; i < cmd_args_list.size(); i++) {
if (i != 0) {
cmd_args += " ";
@ -1000,7 +1061,7 @@ Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset,
}
}
const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
const bool use_remote = p_debug_flags.has_flag(DEBUG_FLAG_REMOTE_DEBUG) || p_debug_flags.has_flag(DEBUG_FLAG_DUMB_CLIENT);
int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
print_line("Creating temporary directory...");
@ -1085,7 +1146,6 @@ Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset,
EditorExportPlatformWindows::EditorExportPlatformWindows() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
@ -1094,7 +1154,6 @@ EditorExportPlatformWindows::EditorExportPlatformWindows() {
ImageLoaderSVG::create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {

View file

@ -52,14 +52,14 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC {
String cmd_args;
bool wait = false;
SSHCleanupCommand(){};
SSHCleanupCommand() {}
SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
host = p_host;
port = p_port;
ssh_args = p_ssh_arg;
cmd_args = p_cmd_args;
wait = p_wait;
};
}
};
Ref<ImageTexture> run_icon;
@ -73,9 +73,11 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC {
Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
String _get_exe_arch(const String &p_path) const;
public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) const override;
@ -93,7 +95,7 @@ public:
virtual int get_options_count() const override;
virtual String get_option_label(int p_index) const override;
virtual String get_option_tooltip(int p_index) const override;
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, BitField<EditorExportPlatform::DebugFlags> p_debug_flags) override;
virtual void cleanup() override;
EditorExportPlatformWindows();

View file

@ -52,8 +52,8 @@ private:
public:
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
GLManagerANGLE_Windows(){};
~GLManagerANGLE_Windows(){};
GLManagerANGLE_Windows() {}
~GLManagerANGLE_Windows() {}
};
#endif // WINDOWS_ENABLED && GLES3_ENABLED

View file

@ -35,7 +35,7 @@
#include "core/config/project_settings.h"
#include "core/version.h"
#include "thirdparty/nvapi/nvapi_minimal.h"
#include "thirdparty/misc/nvapi_minimal.h"
#include <dwmapi.h>
#include <stdio.h>
@ -452,8 +452,8 @@ Error GLManagerNative_Windows::window_create(DisplayServer::WindowID p_window_id
return FAILED;
}
// WARNING: p_window_id is an eternally growing integer since popup windows keep coming and going
// and each of them has a higher id than the previous, so it must be used in a map not a vector
// WARNING: `p_window_id` is an eternally growing integer since popup windows keep coming and going
// and each of them has a higher id than the previous, so it must be used in a map not a vector.
_windows[p_window_id] = win;
// make current

View file

@ -1,5 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Ref&lt;*&gt;">
<SmartPointer Usage="Minimal">reference</SmartPointer>
<DisplayString Condition="!reference">[empty]</DisplayString>
<DisplayString Condition="!!reference">{*reference}</DisplayString>
<Expand>
<Item Condition="!!reference" Name="[ptr]">reference</Item>
<Item Condition="!!reference" Name="[refcount]">reference->refcount.count.value</Item>
</Expand>
</Type>
<Type Name="Vector&lt;*&gt;">
<Expand>
<Item Name="[size]">_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Item>
@ -20,16 +30,6 @@
</Expand>
</Type>
<Type Name="TypedArray&lt;*&gt;">
<Expand>
<Item Name="[size]"> _p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item>
<ArrayItems>
<Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size>
<ValuePointer >(Variant *) _p->array._cowdata._ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Dictionary">
<Expand>
<Item Name="[size]">_p &amp;&amp; _p->variant_map.head_element ? _p->variant_map.num_elements : 0</Item>
@ -91,6 +91,16 @@
<StringView Condition="_data &amp;&amp; !_data->cname">_data->name,s32b</StringView>
</Type>
<Type Name="HashSet&lt;*,*,*&gt;">
<Expand>
<Item Name="[size]">num_elements</Item>
<ArrayItems>
<Size>num_elements</Size>
<ValuePointer>($T1 *) keys._cowdata._ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="HashMapElement&lt;*,*&gt;">
<DisplayString>{{Key = {($T1 *) &amp;data.key} Value = {($T2 *) &amp;data.value}}}</DisplayString>
<Expand>
@ -133,7 +143,7 @@
<Type Name="HashMapElement&lt;*,*&gt;" IncludeView="MapHelper">
<DisplayString>{data.value}</DisplayString>
<Expand>
<Item Name="[key]" >($T1 *) &amp;data.key</Item>
<Item Name="[key]">($T1 *) &amp;data.key</Item>
<Item Name="[value]">($T2 *) &amp;data.value</Item>
</Expand>
</Type>
@ -265,39 +275,164 @@
</Type>
<Type Name="Vector2">
<DisplayString>{{{x},{y}}}</DisplayString>
<DisplayString>({x,g}, {y,g})</DisplayString>
<Expand>
<Item Name="x">x</Item>
<Item Name="y">y</Item>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
</Expand>
</Type>
<Type Name="Vector2i">
<DisplayString>({x}, {y})</DisplayString>
<Expand>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
</Expand>
</Type>
<Type Name="Vector3">
<DisplayString>{{{x},{y},{z}}}</DisplayString>
<DisplayString>({x,g}, {y,g}, {z,g})</DisplayString>
<Expand>
<Item Name="x">x</Item>
<Item Name="y">y</Item>
<Item Name="z">z</Item>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
<Item Name="[z]">z</Item>
</Expand>
</Type>
<Type Name="Vector3i">
<DisplayString>({x}, {y}, {z})</DisplayString>
<Expand>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
<Item Name="[z]">z</Item>
</Expand>
</Type>
<Type Name="Vector4">
<DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString>
<Expand>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
<Item Name="[z]">z</Item>
<Item Name="[w]">w</Item>
</Expand>
</Type>
<Type Name="Vector4i">
<DisplayString>({x}, {y}, {z}, {w})</DisplayString>
<Expand>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
<Item Name="[z]">z</Item>
<Item Name="[w]">w</Item>
</Expand>
</Type>
<Type Name="Quaternion">
<DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString>
<DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString>
<Expand>
<Item Name="x">x</Item>
<Item Name="y">y</Item>
<Item Name="z">z</Item>
<Item Name="w">w</Item>
<Item Name="[x]">x</Item>
<Item Name="[y]">y</Item>
<Item Name="[z]">z</Item>
<Item Name="[w]">w</Item>
</Expand>
</Type>
<Type Name="Color">
<DisplayString>Color {{{r},{g},{b},{a}}}</DisplayString>
<DisplayString>({r,g}, {g,g}, {b,g}, {a,g})</DisplayString>
<Expand>
<Item Name="red">r</Item>
<Item Name="green">g</Item>
<Item Name="blue">b</Item>
<Item Name="alpha">a</Item>
<Item Name="[red]">r</Item>
<Item Name="[green]">g</Item>
<Item Name="[blue]">b</Item>
<Item Name="[alpha]">a</Item>
</Expand>
</Type>
<Type Name="Rect2">
<DisplayString>[P: {position}, S: {size}]</DisplayString>
<Expand>
<Item Name="[position]">position,nr</Item>
<Item Name="[size]">size,nr</Item>
</Expand>
</Type>
<Type Name="Rect2i">
<DisplayString>[P: {position}, S: {size}]</DisplayString>
<Expand>
<Item Name="[position]">position,nr</Item>
<Item Name="[size]">size,nr</Item>
</Expand>
</Type>
<Type Name="AABB">
<DisplayString>[P: {position}, S: {size}]</DisplayString>
<Expand>
<Item Name="[position]">position,nr</Item>
<Item Name="[size]">size,nr</Item>
</Expand>
</Type>
<Type Name="Plane">
<DisplayString>[N: {normal}, D: {d,g}]</DisplayString>
<Expand>
<Item Name="[normal]">normal,nr</Item>
<Item Name="[d]">d</Item>
</Expand>
</Type>
<Type Name="Basis">
<DisplayString>[X: {rows[0]}, Y: {rows[1]}, Z: {rows[2]}]</DisplayString>
<Expand>
<Item Name="[x]">rows[0],nr</Item>
<Item Name="[y]">rows[1],nr</Item>
<Item Name="[z]">rows[2],nr</Item>
</Expand>
</Type>
<Type Name="Transform2D">
<DisplayString>[X: {columns[0]}, Y: {columns[1]}, O: {columns[2]}]</DisplayString>
<Expand>
<Item Name="[x]">columns[0],nr</Item>
<Item Name="[y]">columns[1],nr</Item>
<Item Name="[origin]">columns[2],nr</Item>
</Expand>
</Type>
<Type Name="Transform3D">
<!-- Can't call column functions, so just pretend we can via obscene code duplication. -->
<DisplayString>[X: ({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g}), Y: ({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g}), Z: ({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g}), O: {origin}]</DisplayString>
<Expand>
<Synthetic Name="[x]">
<DisplayString>({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g})</DisplayString>
<Expand>
<Item Name="[x]">basis.rows[0].x</Item>
<Item Name="[y]">basis.rows[1].x</Item>
<Item Name="[z]">basis.rows[2].x</Item>
</Expand>
</Synthetic>
<Synthetic Name="[y]">
<DisplayString>({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g})</DisplayString>
<Expand>
<Item Name="[x]">basis.rows[0].y</Item>
<Item Name="[y]">basis.rows[1].y</Item>
<Item Name="[z]">basis.rows[2].y</Item>
</Expand>
</Synthetic>
<Synthetic Name="[z]">
<DisplayString>({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g})</DisplayString>
<Expand>
<Item Name="[x]">basis.rows[0].z</Item>
<Item Name="[y]">basis.rows[1].z</Item>
<Item Name="[z]">basis.rows[2].z</Item>
</Expand>
</Synthetic>
<Item Name="[origin]">origin,nr</Item>
</Expand>
</Type>
<Type Name="Projection">
<DisplayString>[X: {columns[0]}, Y: {columns[1]}, Z: {columns[2]}, W: {columns[3]}]</DisplayString>
<Expand>
<Item Name="[x]">columns[0],nr</Item>
<Item Name="[y]">columns[1],nr</Item>
<Item Name="[z]">columns[2],nr</Item>
<Item Name="[w]">columns[3],nr</Item>
</Expand>
</Type>
</AutoVisualizer>

View file

@ -1,6 +1,11 @@
#include "core/version.h"
#ifndef RT_MANIFEST
#define RT_MANIFEST 24
#endif
GODOT_ICON ICON platform/windows/godot_console.ico
1 RT_MANIFEST "godot.manifest"
1 VERSIONINFO
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0

View file

@ -57,90 +57,6 @@ static const char dummy[8] __attribute__((section("pck"), used)) = { 0 };
#endif
#endif
PCHAR *
CommandLineToArgvA(
PCHAR CmdLine,
int *_argc) {
PCHAR *argv;
PCHAR _argv;
ULONG len;
ULONG argc;
CHAR a;
ULONG i, j;
BOOLEAN in_QM;
BOOLEAN in_TEXT;
BOOLEAN in_SPACE;
len = strlen(CmdLine);
i = ((len + 2) / 2) * sizeof(PVOID) + sizeof(PVOID);
argv = (PCHAR *)GlobalAlloc(GMEM_FIXED,
i + (len + 2) * sizeof(CHAR));
_argv = (PCHAR)(((PUCHAR)argv) + i);
argc = 0;
argv[argc] = _argv;
in_QM = FALSE;
in_TEXT = FALSE;
in_SPACE = TRUE;
i = 0;
j = 0;
a = CmdLine[i];
while (a) {
if (in_QM) {
if (a == '\"') {
in_QM = FALSE;
} else {
_argv[j] = a;
j++;
}
} else {
switch (a) {
case '\"':
in_QM = TRUE;
in_TEXT = TRUE;
if (in_SPACE) {
argv[argc] = _argv + j;
argc++;
}
in_SPACE = FALSE;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if (in_TEXT) {
_argv[j] = '\0';
j++;
}
in_TEXT = FALSE;
in_SPACE = TRUE;
break;
default:
in_TEXT = TRUE;
if (in_SPACE) {
argv[argc] = _argv + j;
argc++;
}
_argv[j] = a;
j++;
in_SPACE = FALSE;
break;
}
}
i++;
a = CmdLine[i];
}
_argv[j] = '\0';
argv[argc] = nullptr;
(*_argc) = argc;
return argv;
}
char *wc_to_utf8(const wchar_t *wc) {
int ulen = WideCharToMultiByte(CP_UTF8, 0, wc, -1, nullptr, 0, nullptr, nullptr);
char *ubuf = new char[ulen + 1];

View file

@ -46,17 +46,23 @@ DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
return ERROR_DEVICE_NOT_CONNECTED;
}
MMRESULT WINAPI _winmm_get_joycaps(UINT uJoyID, LPJOYCAPSW pjc, UINT cbjc) {
return MMSYSERR_NODRIVER;
}
JoypadWindows::JoypadWindows() {
}
JoypadWindows::JoypadWindows(HWND *hwnd) {
input = Input::get_singleton();
hWnd = hwnd;
joypad_count = 0;
x_joypad_probe_count = 0;
d_joypad_count = 0;
dinput = nullptr;
xinput_dll = nullptr;
xinput_get_state = nullptr;
xinput_set_state = nullptr;
winmm_get_joycaps = nullptr;
load_xinput();
@ -79,14 +85,15 @@ JoypadWindows::JoypadWindows(HWND *hwnd) {
}
JoypadWindows::~JoypadWindows() {
close_joypad();
close_d_joypad();
if (dinput) {
dinput->Release();
}
unload_winmm();
unload_xinput();
}
bool JoypadWindows::have_device(const GUID &p_guid) {
bool JoypadWindows::is_d_joypad_known(const GUID &p_guid) {
for (int i = 0; i < JOYPADS_MAX; i++) {
if (d_joypads[i].guid == p_guid) {
d_joypads[i].confirmed = true;
@ -97,7 +104,7 @@ bool JoypadWindows::have_device(const GUID &p_guid) {
}
// adapted from SDL2, works a lot better than the MSDN version
bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
bool JoypadWindows::is_xinput_joypad(const GUID *p_guid) {
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
@ -122,8 +129,9 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
memcmp(p_guid, &IID_XOneSWirelessGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_XOneSBluetoothGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0)
memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0) {
return true;
}
PRAWINPUTDEVICELIST dev_list = nullptr;
unsigned int dev_list_count = 0;
@ -158,12 +166,56 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
return false;
}
void JoypadWindows::probe_xinput_joypad(const String &name) {
if (x_joypad_probe_count >= XUSER_MAX_COUNT) {
return;
}
int i = x_joypad_probe_count;
x_joypad_probe_count++;
ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE));
DWORD dwResult = xinput_get_state(i, &x_joypads[i].state);
if (dwResult == ERROR_SUCCESS) {
int id = input->get_unused_joy_id();
if (id != -1 && !x_joypads[i].attached) {
x_joypads[i].attached = true;
x_joypads[i].id = id;
x_joypads[i].ff_timestamp = 0;
x_joypads[i].ff_end_timestamp = 0;
x_joypads[i].vibrating = false;
attached_joypads[id] = true;
Dictionary joypad_info;
String joypad_name;
joypad_info["xinput_index"] = (int)i;
JOYCAPSW jc;
memset(&jc, 0, sizeof(JOYCAPSW));
MMRESULT jcResult = winmm_get_joycaps((UINT)id, &jc, sizeof(JOYCAPSW));
if (jcResult == JOYERR_NOERROR) {
joypad_info["vendor_id"] = itos(jc.wMid);
joypad_info["product_id"] = itos(jc.wPid);
if (!name.is_empty()) {
joypad_name = name.trim_prefix("Controller (").trim_suffix(")");
}
}
input->joy_connection_changed(id, true, joypad_name, "__XINPUT_DEVICE__", joypad_info);
}
} else if (x_joypads[i].attached) {
x_joypads[i].attached = false;
attached_joypads[x_joypads[i].id] = false;
input->joy_connection_changed(x_joypads[i].id, false, "");
}
}
bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
ERR_FAIL_NULL_V_MSG(dinput, false, "DirectInput not initialized. Rebooting your PC may solve this issue.");
HRESULT hr;
int num = input->get_unused_joy_id();
if (have_device(instance->guidInstance) || num == -1) {
if (is_d_joypad_known(instance->guidInstance) || num == -1) {
return false;
}
@ -192,6 +244,10 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
WORD version = 0;
sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0);
Dictionary joypad_info;
joypad_info["vendor_id"] = itos(vendor);
joypad_info["product_id"] = itos(product);
id_to_change = num;
slider_count = 0;
@ -201,16 +257,17 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
joy->joy_axis.sort();
joy->guid = instance->guidInstance;
input->joy_connection_changed(num, true, instance->tszProductName, uid);
const String &name = String(instance->tszProductName).trim_prefix("Controller (").trim_suffix(")");
input->joy_connection_changed(num, true, name, uid, joypad_info);
joy->attached = true;
joy->id = num;
attached_joypads[num] = true;
joy->confirmed = true;
joypad_count++;
d_joypad_count++;
return true;
}
void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
void JoypadWindows::setup_d_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
if (ob->dwType & DIDFT_AXIS) {
HRESULT res;
DIPROPRANGE prop_range;
@ -269,7 +326,8 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) {
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
if (self->is_xinput_device(&p_instance->guidProduct)) {
if (self->is_xinput_joypad(&p_instance->guidProduct)) {
self->probe_xinput_joypad(p_instance->tszProductName);
return DIENUM_CONTINUE;
}
self->setup_dinput_joypad(p_instance);
@ -278,15 +336,15 @@ BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, vo
BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *p_instance, void *p_context) {
JoypadWindows *self = static_cast<JoypadWindows *>(p_context);
self->setup_joypad_object(p_instance, self->id_to_change);
self->setup_d_joypad_object(p_instance, self->id_to_change);
return DIENUM_CONTINUE;
}
void JoypadWindows::close_joypad(int id) {
void JoypadWindows::close_d_joypad(int id) {
if (id == -1) {
for (int i = 0; i < JOYPADS_MAX; i++) {
close_joypad(i);
close_d_joypad(i);
}
return;
}
@ -301,45 +359,29 @@ void JoypadWindows::close_joypad(int id) {
attached_joypads[d_joypads[id].id] = false;
d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0;
input->joy_connection_changed(d_joypads[id].id, false, "");
joypad_count--;
d_joypad_count--;
}
void JoypadWindows::probe_joypads() {
ERR_FAIL_NULL_MSG(dinput, "DirectInput not initialized. Rebooting your PC may solve this issue.");
DWORD dwResult;
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE));
dwResult = xinput_get_state(i, &x_joypads[i].state);
if (dwResult == ERROR_SUCCESS) {
int id = input->get_unused_joy_id();
if (id != -1 && !x_joypads[i].attached) {
x_joypads[i].attached = true;
x_joypads[i].id = id;
x_joypads[i].ff_timestamp = 0;
x_joypads[i].ff_end_timestamp = 0;
x_joypads[i].vibrating = false;
attached_joypads[id] = true;
Dictionary joypad_info;
joypad_info["xinput_index"] = (int)i;
input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__", joypad_info);
}
} else if (x_joypads[i].attached) {
x_joypads[i].attached = false;
attached_joypads[x_joypads[i].id] = false;
input->joy_connection_changed(x_joypads[i].id, false, "");
}
}
for (int i = 0; i < joypad_count; i++) {
d_joypads[i].confirmed = false;
for (int i = 0; i < d_joypad_count; i++) {
d_joypads[i].confirmed = false; // Flag DirectInput devices for re-checking their availability.
}
x_joypad_probe_count = 0;
// Probe _all attached_ joypad devices.
dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
for (int i = 0; i < joypad_count; i++) {
for (int i = x_joypad_probe_count; i < XUSER_MAX_COUNT; i++) {
// Handle disconnect of XInput devices.
// And act as a fallback, just in case DirectInput could not find the device.
probe_xinput_joypad();
}
for (int i = 0; i < d_joypad_count; i++) {
if (!d_joypads[i].confirmed) {
close_joypad(i);
close_d_joypad(i); // Any DirectInput device not found during probing is considered as disconnected.
}
}
}
@ -347,6 +389,7 @@ void JoypadWindows::probe_joypads() {
void JoypadWindows::process_joypads() {
HRESULT hr;
// Handle XInput joypads.
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
xinput_gamepad &joy = x_joypads[i];
if (!joy.attached) {
@ -387,6 +430,7 @@ void JoypadWindows::process_joypads() {
}
}
// Handle DirectIndput joypads.
for (int i = 0; i < JOYPADS_MAX; i++) {
dinput_gamepad *joy = &d_joypads[i];
@ -534,7 +578,9 @@ void JoypadWindows::joypad_vibration_stop_xinput(int p_device, uint64_t p_timest
void JoypadWindows::load_xinput() {
xinput_get_state = &_xinput_get_state;
xinput_set_state = &_xinput_set_state;
winmm_get_joycaps = &_winmm_get_joycaps;
bool legacy_xinput = false;
xinput_dll = LoadLibrary("XInput1_4.dll");
if (!xinput_dll) {
xinput_dll = LoadLibrary("XInput1_3.dll");
@ -559,6 +605,16 @@ void JoypadWindows::load_xinput() {
}
xinput_get_state = func;
xinput_set_state = set_func;
winmm_dll = LoadLibrary("Winmm.dll");
if (winmm_dll) {
joyGetDevCaps_t caps_func = (joyGetDevCaps_t)GetProcAddress((HMODULE)winmm_dll, "joyGetDevCapsW");
if (caps_func) {
winmm_get_joycaps = caps_func;
} else {
unload_winmm();
}
}
}
void JoypadWindows::unload_xinput() {
@ -566,3 +622,9 @@ void JoypadWindows::unload_xinput() {
FreeLibrary((HMODULE)xinput_dll);
}
}
void JoypadWindows::unload_winmm() {
if (winmm_dll) {
FreeLibrary((HMODULE)winmm_dll);
}
}

View file

@ -37,6 +37,8 @@
#include <dinput.h>
#include <xinput.h>
#include <mmsystem.h>
#ifndef SAFE_RELEASE // when Windows Media Device M? is not present
#define SAFE_RELEASE(x) \
if (x != nullptr) { \
@ -107,14 +109,18 @@ private:
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
typedef MMRESULT(WINAPI *joyGetDevCaps_t)(UINT uJoyID, LPJOYCAPSW pjc, UINT cbjc);
HWND *hWnd = nullptr;
HANDLE xinput_dll;
HANDLE winmm_dll;
LPDIRECTINPUT8 dinput;
Input *input = nullptr;
int id_to_change;
int slider_count;
int joypad_count;
int x_joypad_probe_count; // XInput equivalent to dinput_gamepad.confirmed.
int d_joypad_count;
bool attached_joypads[JOYPADS_MAX];
dinput_gamepad d_joypads[JOYPADS_MAX];
xinput_gamepad x_joypads[XUSER_MAX_COUNT];
@ -122,22 +128,25 @@ private:
static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context);
static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context);
void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
void close_joypad(int id = -1);
void setup_d_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
void close_d_joypad(int id = -1);
void load_xinput();
void unload_xinput();
void unload_winmm();
void post_hat(int p_device, DWORD p_dpad);
bool have_device(const GUID &p_guid);
bool is_xinput_device(const GUID *p_guid);
bool is_d_joypad_known(const GUID &p_guid);
bool is_xinput_joypad(const GUID *p_guid);
bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance);
void probe_xinput_joypad(const String &name = ""); // Handles connect, disconnect & re-connect for XInput joypads.
void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
float axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
XInputGetState_t xinput_get_state;
XInputSetState_t xinput_set_state;
joyGetDevCaps_t winmm_get_joycaps; // Only for reading info on XInput joypads.
};
#endif // JOYPAD_WINDOWS_H

View file

@ -158,7 +158,7 @@ Size2 NativeMenuWindows::get_size(const RID &p_rid) const {
int count = GetMenuItemCount(md->menu);
for (int i = 0; i < count; i++) {
RECT rect;
if (GetMenuItemRect(NULL, md->menu, i, &rect)) {
if (GetMenuItemRect(nullptr, md->menu, i, &rect)) {
size.x = MAX(size.x, rect.right - rect.left);
size.y += rect.bottom - rect.top;
}
@ -177,6 +177,16 @@ void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) {
}
SetForegroundWindow(hwnd);
TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr);
if (md->close_cb.is_valid()) {
Variant ret;
Callable::CallError ce;
md->close_cb.callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute popup close callback: %s.", Variant::get_callable_error_text(md->close_cb, nullptr, 0, ce)));
}
}
PostMessage(hwnd, WM_NULL, 0, 0);
}
@ -200,12 +210,17 @@ Callable NativeMenuWindows::get_popup_open_callback(const RID &p_rid) const {
}
void NativeMenuWindows::set_popup_close_callback(const RID &p_rid, const Callable &p_callback) {
// Not supported.
MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL(md);
md->close_cb = p_callback;
}
Callable NativeMenuWindows::get_popup_close_callback(const RID &p_rid) const {
// Not supported.
return Callable();
const MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL_V(md, Callable());
return md->close_cb;
}
void NativeMenuWindows::set_minimum_width(const RID &p_rid, float p_width) {
@ -992,7 +1007,7 @@ void NativeMenuWindows::set_item_submenu(const RID &p_rid, int p_idx, const RID
if (p_submenu_rid.is_valid()) {
item.hSubMenu = md_sub->menu;
} else {
item.hSubMenu = 0;
item.hSubMenu = nullptr;
}
SetMenuItemInfoW(md->menu, p_idx, true, &item);
}
@ -1095,7 +1110,7 @@ void NativeMenuWindows::set_item_icon(const RID &p_rid, int p_idx, const Ref<Tex
item_data->bmp = _make_bitmap(item_data->img);
} else {
item_data->img = Ref<Image>();
item_data->bmp = 0;
item_data->bmp = nullptr;
}
item.hbmpItem = item_data->bmp;
SetMenuItemInfoW(md->menu, p_idx, true, &item);

View file

@ -31,6 +31,7 @@
#ifndef NATIVE_MENU_WINDOWS_H
#define NATIVE_MENU_WINDOWS_H
#include "core/io/image.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display/native_menu.h"
@ -60,6 +61,8 @@ class NativeMenuWindows : public NativeMenu {
struct MenuData {
HMENU menu = 0;
Callable close_cb;
bool is_rtl = false;
};

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,6 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/os/os.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "servers/audio_server.h"
@ -95,8 +94,10 @@ public:
class JoypadWindows;
class OS_Windows : public OS {
uint64_t target_ticks = 0;
uint64_t ticks_start = 0;
uint64_t ticks_per_second = 0;
uint64_t delay_resolution = 1000;
HINSTANCE hInstance;
MainLoop *main_loop = nullptr;
@ -134,6 +135,8 @@ class OS_Windows : public OS {
DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const;
DWRITE_FONT_STRETCH _stretch_to_dw(int p_stretch) const;
bool is_using_con_wrapper() const;
// functions used by main to initialize/deinitialize the OS
protected:
virtual void initialize() override;
@ -143,12 +146,17 @@ protected:
virtual void finalize() override;
virtual void finalize_core() override;
virtual String get_stdin_string() override;
virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
virtual StdHandleType get_stdin_type() const override;
virtual StdHandleType get_stdout_type() const override;
virtual StdHandleType get_stderr_type() const override;
String _quote_command_line_argument(const String &p_text) const;
struct ProcessInfo {
STARTUPINFO si;
STARTUPINFOEX si;
PROCESS_INFORMATION pi;
mutable bool is_running = true;
mutable int exit_code = -1;
@ -170,8 +178,10 @@ public:
virtual String get_name() const override;
virtual String get_distribution_name() const override;
virtual String get_version() const override;
virtual String get_version_alias() const override;
virtual Vector<String> get_video_adapter_driver_info() const override;
virtual bool get_user_prefers_integrated_gpu() const override;
virtual void initialize_joypads() override {}
@ -181,13 +191,14 @@ public:
virtual Error set_cwd(const String &p_cwd) override;
virtual void add_frame_delay(bool p_can_draw) override;
virtual void delay_usec(uint32_t p_usec) const override;
virtual uint64_t get_ticks_usec() const override;
virtual Dictionary get_memory_info() const override;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override;
virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking = true) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
@ -209,15 +220,18 @@ public:
virtual String get_processor_name() const override;
virtual String get_model_name() const override;
virtual uint64_t get_embedded_pck_offset() const override;
virtual String get_config_path() const override;
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
virtual String get_temp_path() const override;
virtual String get_godot_dir_name() const override;
virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
virtual String get_user_data_dir() const override;
virtual String get_user_data_dir(const String &p_user_dir) const override;
virtual String get_unique_id() const override;

View file

@ -2,23 +2,11 @@
import os
from detect import get_mingw_bin_prefix, try_cmd
def make_debug_mingw(target, source, env):
dst = str(target[0])
# Force separate debug symbols if executable size is larger than 1.9 GB.
if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465:
mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
else:
os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(dst))
else:
os.system("strip --strip-debug --strip-unneeded {0}".format(dst))
if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
else:
os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(env["OBJCOPY"], dst))
os.system("{0} --strip-debug --strip-unneeded {1}".format(env["STRIP"], dst))
os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(env["OBJCOPY"], dst))

View file

@ -34,11 +34,7 @@
#include "rendering_context_driver_vulkan_windows.h"
#ifdef USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif
#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanWindows::_get_platform_surface_extension() const {
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
@ -64,7 +60,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_c
create_info.hwnd = wpd->window;
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface);
ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
Surface *surface = memnew(Surface);

View file

@ -43,7 +43,7 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
} else if (event.eEventId == SPEI_END_INPUT_STREAM) {
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[stream_num].id);
tts->ids.erase(stream_num);
tts->_update_tts();
tts->update_requested = true;
} else if (event.eEventId == SPEI_WORD_BOUNDARY) {
const Char16String &string = tts->ids[stream_num].string;
int pos = 0;
@ -60,8 +60,8 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
}
}
void TTS_Windows::_update_tts() {
if (!is_speaking() && !paused && queue.size() > 0) {
void TTS_Windows::process_events() {
if (update_requested && !paused && queue.size() > 0 && !is_speaking()) {
DisplayServer::TTSUtterance &message = queue.front()->get();
String text;
@ -110,6 +110,8 @@ void TTS_Windows::_update_tts() {
ids[(uint32_t)stream_number] = ut;
queue.pop_front();
update_requested = false;
}
}
@ -207,7 +209,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum
if (is_paused()) {
resume();
} else {
_update_tts();
update_requested = true;
}
}

View file

@ -55,9 +55,9 @@ class TTS_Windows {
int id;
};
HashMap<uint32_t, UTData> ids;
bool update_requested = false;
static void __stdcall speech_event_callback(WPARAM wParam, LPARAM lParam);
void _update_tts();
static TTS_Windows *singleton;
@ -73,6 +73,8 @@ public:
void resume();
void stop();
void process_events();
TTS_Windows();
~TTS_Windows();
};

View file

@ -30,6 +30,8 @@
#include "windows_terminal_logger.h"
#include "core/os/os.h"
#ifdef WINDOWS_ENABLED
#include <stdio.h>
@ -78,8 +80,8 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
}
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hCon || hCon == INVALID_HANDLE_VALUE) {
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
if (OS::get_singleton()->get_stdout_type() != OS::STD_HANDLE_CONSOLE || !hCon || hCon == INVALID_HANDLE_VALUE) {
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type);
} else {
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
GetConsoleScreenBufferInfo(hCon, &sbi);

View file

@ -67,11 +67,11 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) {
{
// The custom LoadLibraryExW is used instead of open_dynamic_library
// to avoid loading the original PDB into the debugger.
HMODULE library_ptr = LoadLibraryExW((LPCWSTR)(p_dll_path.utf16().get_data()), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
HMODULE library_ptr = LoadLibraryExW((LPCWSTR)(p_dll_path.utf16().get_data()), nullptr, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
ERR_FAIL_NULL_V_MSG(library_ptr, ERR_FILE_CANT_OPEN, vformat("Failed to load library '%s'.", p_dll_path));
IMAGE_DEBUG_DIRECTORY *dbg_dir = (IMAGE_DEBUG_DIRECTORY *)ImageDirectoryEntryToDataEx(library_ptr, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dbg_info_size, NULL);
IMAGE_DEBUG_DIRECTORY *dbg_dir = (IMAGE_DEBUG_DIRECTORY *)ImageDirectoryEntryToDataEx(library_ptr, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dbg_info_size, nullptr);
bool has_debug = dbg_dir && dbg_dir->Type == IMAGE_DEBUG_TYPE_CODEVIEW;
if (has_debug) {
@ -155,7 +155,11 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) {
} else if (!FileAccess::exists(copy_pdb_path)) {
copy_pdb_path = dll_base_dir.path_join(copy_pdb_path.get_file());
}
ERR_FAIL_COND_V_MSG(!FileAccess::exists(copy_pdb_path), FAILED, vformat("File '%s' does not exist.", copy_pdb_path));
if (!FileAccess::exists(copy_pdb_path)) {
// The PDB file may be distributed separately on purpose, so we don't consider this an error.
WARN_VERBOSE(vformat("PDB file '%s' for library '%s' was not found, skipping copy/rename.", copy_pdb_path, p_dll_path));
return ERR_SKIP;
}
String new_pdb_base_name = p_dll_path.get_file().get_basename() + "_";
@ -175,9 +179,7 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) {
if (new_expected_buffer_size > original_path_size) {
ERR_FAIL_COND_V_MSG(original_path_size < min_base_size + suffix_size, FAILED, vformat("The original PDB path size in bytes is too small: '%s'. Expected size: %d or more bytes, but available %d.", pdb_info.path, min_base_size + suffix_size, original_path_size));
utf8_name.resize(original_path_size - suffix_size + 1); // +1 for the \0
utf8_name[utf8_name.size() - 1] = '\0';
new_pdb_base_name.parse_utf8(utf8_name);
new_pdb_base_name.parse_utf8(utf8_name, original_path_size - suffix_size);
new_pdb_base_name[new_pdb_base_name.length() - 1] = '_'; // Restore the last '_'
WARN_PRINT(vformat("The original path size of '%s' in bytes was too small to fit the new name, so it was shortened to '%s%d.pdb'.", pdb_info.path, new_pdb_base_name, max_pdb_names - 1));
}